diff --git a/.appveyor.yml b/.appveyor.yml index eb3e089fd20b..edc5ecbae89d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,21 +1,24 @@ environment: - matrix: - - nodejs_version: "6" + nodejs_version: "10.9.0" # Same version as used in CircleCI. matrix: fast_finish: true install: - ps: Install-Product node $env:nodejs_version - - npm install -g npm@~5.3.0 - - npm install + # --network-timeout is a workaround for https://github.com/yarnpkg/yarn/issues/6221 + - yarn --frozen-lockfile --network-timeout=500000 + - yarn webdriver-update-appveyor test_script: - node --version - - npm --version - - node tests\run_e2e.js --appveyor + - yarn --version + - yarn test + - node tests\legacy-cli\run_e2e.js --appveyor "--glob=tests/{basic,commands,generate,build/styles}/**" build: off +deploy: off cache: - - node_modules -> package-lock.json + - node_modules -> yarn.lock + - "%LOCALAPPDATA%\\Yarn" diff --git a/.circleci/bazel.rc b/.circleci/bazel.rc new file mode 100644 index 000000000000..0cf9444d5d72 --- /dev/null +++ b/.circleci/bazel.rc @@ -0,0 +1,20 @@ +# These options are enabled when running on CI +# We do this by copying this file to /etc/bazel.bazelrc at the start of the build. + +# Echo all the configuration settings and their source +build --announce_rc + +# Don't be spammy in the logs +build --noshow_progress + +# Don't run manual tests +test --test_tag_filters=-manual + +# Workaround https://github.com/bazelbuild/bazel/issues/3645 +# Bazel doesn't calculate the memory ceiling correctly when running under Docker. +# Limit Bazel to consuming resources that fit in CircleCI "medium" class which is the default: +# https://circleci.com/docs/2.0/configuration-reference/#resource_class +build --local_resources=3072,2.0,1.0 + +# Retry in the event of flakes +test --flaky_test_attempts=2 diff --git a/.circleci/config.yml b/.circleci/config.yml index 85d7be1c8ca1..ae48002bb43c 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,221 +1,210 @@ -version: 2 +# Configuration file for https://circleci.com/gh/angular/angular-cli -# Settings common to each job. -anchor_1: &defaults - working_directory: ~/angular-cli - docker: - - image: angular/ngcontainer +# Note: YAML anchors allow an object to be re-used, reducing duplication. +# The ampersand declares an alias for an object, then later the `<<: *name` +# syntax dereferences it. +# See http://blog.daemonl.com/2016/02/yaml.html +# To validate changes, use an online parser, eg. +# http://yaml-online-parser.appspot.com/ -# Restore cache based on package-lock.json checksum for branch. -anchor_2: &restore_cache_defaults - key: angular-cli-{{ checksum "package-lock.json" }} +# Variables -# Attach workspace that contains: -# - dist/ : built cli -# - angular-cli-e2e-default/ : initialized e2e test project -anchor_3: &attach_workspace_defaults - at: /workspace +## IMPORTANT +# If you change the `docker_image` version, also change the `cache_key` suffix and the version of +# `com_github_bazelbuild_buildtools` in the `/WORKSPACE` file. +var_1: &docker_image angular/ngcontainer:0.5.0 +var_2: &cache_key angular_devkit-{{ checksum "yarn.lock" }}-0.5.0 +var_3: &node_8_docker_image angular/ngcontainer:0.3.3 +# Settings common to each job +anchor_1: &defaults + working_directory: ~/ng + docker: + - image: *docker_image + +# After checkout, rebase on top of master. +# Similar to travis behavior, but not quite the same. +# See https://discuss.circleci.com/t/1662 +anchor_2: &post_checkout + post: git pull --ff-only origin "refs/pull/${CI_PULL_REQUEST//*pull\//}/merge" +anchor_3: &root_package_lock_key + key: *cache_key +anchor_4: &attach_options + at: . + +# Job definitions +version: 2 jobs: - build: + install: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - run: node --version - - run: npm --version - - run: npm install --quiet - - run: npm run build + - checkout: *post_checkout + - restore_cache: *root_package_lock_key + - run: yarn install --frozen-lockfile + - persist_to_workspace: + root: . + paths: + - ./* - save_cache: - key: angular-cli-{{ checksum "package-lock.json" }} + <<: *root_package_lock_key paths: - - "node_modules" - + - ~/.cache/yarn + lint: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults + - attach_workspace: *attach_options - run: npm run lint - test: + validate: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - run: npm run test + - attach_workspace: *attach_options + - run: npm run validate -- --ci -# E2E test for current Angular. - e2e-setup: + test: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - run: mkdir /workspace - - run: mkdir /workspace/angular-cli-e2e-default - # Ignore all tests, we just want the setup step to persist it to the workspace. - - run: node tests/run_e2e.js --tmpdir=/workspace/angular-cli-e2e-default --ignore=**/* - - run: mv dist /workspace/ - - persist_to_workspace: - root: /workspace - paths: - - dist/ - - angular-cli-e2e-default/ + - attach_workspace: *attach_options + - run: npm run test -- --full - e2e-0: + test-large: <<: *defaults + resource_class: large + parallelism: 4 steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-default/test-project --nb-shards=4 --shard=0 --nosilent - - e2e-1: - <<: *defaults - steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-default/test-project --nb-shards=4 --shard=1 --nosilent - - e2e-2: + - attach_workspace: *attach_options + - run: npm run webdriver-update-circleci + - run: npm run test-large -- --full --nb-shards=${CIRCLE_NODE_TOTAL} --shard=${CIRCLE_NODE_INDEX} + + e2e-cli: <<: *defaults + environment: + BASH_ENV: ~/.profile + resource_class: xlarge + parallelism: 4 steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-default/test-project --nb-shards=4 --shard=2 --nosilent - - e2e-3: + - attach_workspace: *attach_options + - run: xvfb-run -a node ./tests/legacy-cli/run_e2e --nb-shards=${CIRCLE_NODE_TOTAL} --shard=${CIRCLE_NODE_INDEX} + - store_artifacts: + path: /tmp/dist + destination: cli/new-production + + e2e-node-8: <<: *defaults + # Overwrite docker image to node 8. + docker: + - image: *node_8_docker_image + environment: + BASH_ENV: ~/.profile + resource_class: xlarge + parallelism: 2 steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-default/test-project --nb-shards=4 --shard=3 --nosilent - -# E2E test for Angular nightly. - e2e-setup-nightly: + - attach_workspace: *attach_options + - run: npm install --global npm@6 + - run: xvfb-run -a node ./tests/legacy-cli/run_e2e --glob=tests/basic/* --nb-shards=${CIRCLE_NODE_TOTAL} --shard=${CIRCLE_NODE_INDEX} + + e2e-cli-ng-snapshots: <<: *defaults + environment: + BASH_ENV: ~/.profile + resource_class: xlarge + parallelism: 4 steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - run: mkdir /workspace - - run: mkdir /workspace/angular-cli-e2e-nightly - # Ignore all tests, we just want the setup step to persist it to the workspace. - - run: node tests/run_e2e.js --tmpdir=/workspace/angular-cli-e2e-nightly --ignore=**/* --nightly - - run: mv dist /workspace/ - - persist_to_workspace: - root: /workspace - paths: - - dist/ - - angular-cli-e2e-nightly/ + - attach_workspace: *attach_options + - run: xvfb-run -a node ./tests/legacy-cli/run_e2e --nb-shards=${CIRCLE_NODE_TOTAL} --shard=${CIRCLE_NODE_INDEX} --ng-snapshots - e2e-0-nightly: + build: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-nightly/test-project --nb-shards=4 --shard=0 --nosilent --nightly - - e2e-1-nightly: + - attach_workspace: *attach_options + - run: npm run admin -- build + + build-bazel: <<: *defaults + resource_class: xlarge steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-nightly/test-project --nb-shards=4 --shard=1 --nosilent --nightly - - e2e-2-nightly: + - attach_workspace: *attach_options + - run: sudo cp .circleci/bazel.rc /etc/bazel.bazelrc + - run: bazel test //packages/... + + snapshot_publish: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-nightly/test-project --nb-shards=4 --shard=2 --nosilent --nightly - - e2e-3-nightly: + - attach_workspace: *attach_options + - run: + name: Decrypt Credentials + command: | + openssl aes-256-cbc -d -in .circleci/github_token -k "${KEY}" -out ~/github_token + - run: + name: Deployment to Snapshot + command: | + npm run admin -- snapshots --verbose --githubTokenFile=${HOME}/github_token + + publish: <<: *defaults steps: - - checkout - - restore_cache: - <<: *restore_cache_defaults - - attach_workspace: - <<: *attach_workspace_defaults - - run: cp -r /workspace/dist/ ./ - - run: xvfb-run -a node tests/run_e2e.js --nobuild --reuse=/workspace/angular-cli-e2e-nightly/test-project --nb-shards=4 --shard=3 --nosilent --nightly + - attach_workspace: *attach_options + - run: + name: Decrypt Credentials + command: | + openssl aes-256-cbc -d -in .circleci/npm_token -k "${KEY}" -out ~/.npmrc + - run: + name: Deployment to NPM + command: | + npm run admin -- publish --verbose workflows: version: 2 - build_and_test: + default_workflow: jobs: - - build + - install - lint: + requires: + - install + - validate: + requires: + - install + - build: + requires: + - install + - build-bazel: requires: - build - test: requires: - build - # E2E test for current Angular. - - e2e-setup: + - test-large: requires: - build - - e2e-0: - requires: - - e2e-setup - - e2e-1: + - e2e-cli: requires: - - e2e-setup - - e2e-2: - requires: - - e2e-setup - - e2e-3: + - build + - e2e-node-8: requires: - - e2e-setup - # E2E test for Angular nightly. - - e2e-setup-nightly: + - build + - e2e-cli-ng-snapshots: requires: - build filters: branches: - only: - - master - - e2e-0-nightly: - requires: - - e2e-setup-nightly - - e2e-1-nightly: - requires: - - e2e-setup-nightly - - e2e-2-nightly: + only: master + - snapshot_publish: requires: - - e2e-setup-nightly - - e2e-3-nightly: + - test + - build + - e2e-cli + filters: + branches: + only: master + - publish: requires: - - e2e-setup-nightly + - test + - build + - e2e-cli + - snapshot_publish + filters: + tags: + only: /^v\d+/ + branches: + ignore: /.*/ diff --git a/.circleci/github_token b/.circleci/github_token new file mode 100644 index 000000000000..450cb2c93f8c --- /dev/null +++ b/.circleci/github_token @@ -0,0 +1 @@ +Salted__zÈùº¬ö"Bõ¾Y¾’|‚Û¢V”QÖ³UzWò±/G…îR ¡e}j‘% þÿ¦<%öáÉÿ–¼ \ No newline at end of file diff --git a/.circleci/npm_token b/.circleci/npm_token new file mode 100644 index 000000000000..5a1bb6303052 --- /dev/null +++ b/.circleci/npm_token @@ -0,0 +1 @@ +Salted__°/¥ÙL Ž¡”ö¦°Â;ª…(.|©í¡ –ÚCŒàÔ’“þÖ5`h¢8Ðài8JÁo*´?}çû£3§0f´!Ð'ÛB¸Ì œ"UÆŠ&K!¨%Áɵڤ \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index b53765a86c8d..36e19acf952e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,11 +2,12 @@ root = true -[*] +[*.ts] charset = utf-8 indent_style = space indent_size = 2 insert_final_newline = true +spaces_around_brackets = inside trim_trailing_whitespace = true [*.md] diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index bd119135a505..000000000000 --- a/.eslintignore +++ /dev/null @@ -1,10 +0,0 @@ -dist/ -.git/ -tmp/ -typings/ - -# Ignore all blueprint files. We e2e tests those later on. -packages/@angular/cli/blueprints/*/files/ - -# Ignore ember cli. -packages/@angular/cli/ember-cli/ \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 18ed2a13b1c4..000000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "ecmaFeatures": { - "modules": true, - "module": true - }, - "env": { - "mocha": true, - "node": true, - "es6": true - }, - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module" - }, - "rules": { - "no-alert": "off", - "no-array-constructor": "off", - "no-bitwise": "off", - "no-caller": "off", - "no-case-declarations": "error", - "no-catch-shadow": "off", - "no-class-assign": "error", - "no-cond-assign": "error", - "no-confusing-arrow": "off", - "no-console": "error", - "no-const-assign": "error", - "no-constant-condition": "error", - "no-continue": "off", - "no-control-regex": "error", - "no-debugger": "error", - "no-delete-var": "error", - "no-div-regex": "off", - "no-dupe-class-members": "error", - "no-dupe-keys": "error", - "no-dupe-args": "error", - "no-duplicate-case": "error", - "no-duplicate-imports": "off", - "no-else-return": "off", - "no-empty": "error", - "no-empty-character-class": "error", - "no-empty-function": "off", - "no-empty-pattern": "error", - "no-eq-null": "off", - "no-eval": "off", - "no-ex-assign": "error", - "no-extend-native": "off", - "no-extra-bind": "off", - "no-extra-boolean-cast": "error", - "no-extra-label": "off", - "no-extra-parens": "off", - "no-extra-semi": "error", - "no-fallthrough": "error", - "no-floating-decimal": "off", - "no-func-assign": "error", - "no-implicit-coercion": "off", - "no-implicit-globals": "off", - "no-implied-eval": "off", - "no-inline-comments": "off", - "no-inner-declarations": "error", - "no-invalid-regexp": "error", - "no-invalid-this": "off", - "no-irregular-whitespace": "error", - "no-iterator": "off", - "no-label-var": "off", - "no-labels": "off", - "no-lone-blocks": "off", - "no-lonely-if": "off", - "no-loop-func": "off", - "no-mixed-requires": "off", - "no-mixed-spaces-and-tabs": "error", - "linebreak-style": "off", - "no-multi-spaces": "off", - "no-multi-str": "off", - "no-multiple-empty-lines": "off", - "no-native-reassign": "off", - "no-negated-condition": "off", - "no-negated-in-lhs": "error", - "no-nested-ternary": "off", - "no-new": "off", - "no-new-func": "off", - "no-new-object": "off", - "no-new-require": "off", - "no-new-symbol": "error", - "no-new-wrappers": "off", - "no-obj-calls": "error", - "no-octal": "error", - "no-octal-escape": "off", - "no-param-reassign": "off", - "no-path-concat": "off", - "no-plusplus": "off", - "no-process-env": "off", - "no-process-exit": "off", - "no-proto": "off", - "no-redeclare": "error", - "no-regex-spaces": "error", - "no-restricted-globals": "off", - "no-restricted-imports": "off", - "no-restricted-modules": "off", - "no-restricted-syntax": "off", - "no-return-assign": "off", - "no-script-url": "off", - "no-self-assign": "error", - "no-self-compare": "off", - "no-sequences": "off", - "no-shadow": "off", - "no-shadow-restricted-names": "off", - "no-whitespace-before-property": "off", - "no-spaced-func": "off", - "no-sparse-arrays": "error", - "no-sync": "off", - "no-ternary": "off", - "no-trailing-spaces": "off", - "no-this-before-super": "error", - "no-throw-literal": "off", - "no-undef": "error", - "no-undef-init": "off", - "no-undefined": "off", - "no-unexpected-multiline": "error", - "no-underscore-dangle": "off", - "no-unmodified-loop-condition": "off", - "no-unneeded-ternary": "off", - "no-unreachable": "error", - "no-unused-expressions": "off", - "no-unused-labels": "error", - "no-unused-vars": "error", - "no-use-before-define": "off", - "no-useless-call": "off", - "no-useless-concat": "off", - "no-useless-constructor": "off", - "no-void": "off", - "no-var": "off", - "no-warning-comments": "off", - "no-with": "off", - "no-magic-numbers": "off", - "array-bracket-spacing": "off", - "array-callback-return": "off", - "arrow-body-style": "off", - "arrow-parens": "off", - "arrow-spacing": "off", - "accessor-pairs": "off", - "block-scoped-var": "off", - "block-spacing": "off", - "brace-style": [2, "1tbs", { "allowSingleLine": false }], - "callback-return": "off", - "camelcase": "off", - "comma-dangle": "off", - "comma-spacing": "off", - "comma-style": "off", - "complexity": ["off", 11], - "computed-property-spacing": "off", - "consistent-return": "off", - "consistent-this": "off", - "constructor-super": "error", - "curly": "off", - "default-case": "off", - "dot-location": "off", - "dot-notation": "off", - "eol-last": "off", - "eqeqeq": "off", - "func-names": "off", - "func-style": "off", - "generator-star-spacing": "off", - "global-require": "off", - "guard-for-in": "off", - "handle-callback-err": "off", - "id-length": "off", - "indent": [2,2, { "SwitchCase": 1 }], - "init-declarations": "off", - "jsx-quotes": "off", - "key-spacing": [2, { - "multiLine": { - "beforeColon": false, - "afterColon": true, - "mode": "minimum" - } - }], - "keyword-spacing": "off", - "lines-around-comment": "off", - "max-depth": "off", - "max-len": "off", - "max-nested-callbacks": "off", - "max-params": "off", - "max-statements": "off", - "max-statements-per-line": "off", - "new-cap": "off", - "new-parens": "off", - "newline-after-var": "off", - "newline-before-return": "off", - "newline-per-chained-call": "off", - "object-curly-spacing": [2, "always"], - "object-shorthand": "off", - "one-var": "off", - "one-var-declaration-per-line": "off", - "operator-assignment": "off", - "operator-linebreak": "off", - "padded-blocks": "off", - "prefer-arrow-callback": "off", - "prefer-const": "off", - "prefer-reflect": "off", - "prefer-rest-params": "off", - "prefer-spread": "off", - "prefer-template": "off", - "quote-props": "off", - "quotes": [2, "single"], - "radix": "off", - "id-match": "off", - "id-blacklist": "off", - "require-jsdoc": "off", - "require-yield": "off", - "semi-spacing": "off", - "sort-vars": "off", - "sort-imports": "off", - "space-before-blocks": "off", - "space-before-function-paren": "off", - "space-in-parens": "off", - "space-infix-ops": "off", - "space-unary-ops": "off", - "spaced-comment": "off", - "strict": "off", - "template-curly-spacing": "off", - "use-isnan": "error", - "valid-jsdoc": "off", - "valid-typeof": "error", - "vars-on-top": "off", - "wrap-iife": "off", - "wrap-regex": "off", - "yield-star-spacing": "off", - "yoda": "off" - } -} diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS deleted file mode 100644 index 1c37110b0f28..000000000000 --- a/.github/CODEOWNERS +++ /dev/null @@ -1,3 +0,0 @@ -packages/@ngtools/webpack/* @hansl -packages/@angular/blueprints/* @Brocco -packages/@angular/models/webpack-configs/* @filipesilva diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md index 32136f97ff09..524740f30080 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE.md @@ -1,40 +1,56 @@ +### Bug Report or Feature Request (mark with an `x`) +``` +- [ ] bug report -> please search issues before submitting +- [ ] feature request +``` -### Versions +### Command (mark with an `x`) ``` +- [ ] new +- [ ] build +- [ ] serve +- [ ] test +- [ ] e2e +- [ ] generate +- [ ] add +- [ ] update +- [ ] lint +- [ ] xi18n +- [ ] run +- [ ] config +- [ ] help +- [ ] version +- [ ] doc +``` + +### Versions -``` + ### Repro steps -* Step 1 -* Step 2 -* Step 3 -### Observed behavior -``` - -``` +### The log given by the failure + + -### Desired behavior +### Desired functionality -### Mention any other details that might be useful (optional) - +### Mention any other details that might be useful + diff --git a/.github/SAVED_REPLIES.md b/.github/SAVED_REPLIES.md index 697336412011..29e19832903c 100644 --- a/.github/SAVED_REPLIES.md +++ b/.github/SAVED_REPLIES.md @@ -34,6 +34,15 @@ Thanks for reporting this issue. However, you didn't provide sufficient informat If the problem persists, please file a new issue and ensure you provide all of the required information when filling out the issue template. ``` + +## Angular CLI: NPM install issue (v1) +``` +This seems like a problem with your node/npm and not with Angular CLI. + +Please have a look at the [fixing npm permissions page](https://docs.npmjs.com/getting-started/fixing-npm-permissions), [common errors page](https://docs.npmjs.com/troubleshooting/common-errors), [npm issue tracker](https://github.com/npm/npm/issues), or open a new issue if the problem you are experiencing isn't known. +``` + + ## Angular CLI: Issue Outside of Angular CLI (v1.1) ``` I'm sorry, but this issue is not caused by Angular CLI. Please contact the author(s) of the project or file an issue on their issue tracker. @@ -43,8 +52,12 @@ I'm sorry, but this issue is not caused by Angular CLI. Please contact the autho ## Angular CLI: Non-reproducible (v1) ``` I'm sorry, but we can't reproduce the problem following the instructions you provided. +Remember that we have a large number of issues to resolve, and have only a limited amount of time to reproduce your issue. +Short, explicit instructions make it much more likely we'll be able to reproduce the problem so we can fix it. If the problem persists, please open a new issue following [our submission guidelines](https://github.com/angular/angular-cli/blob/master/CONTRIBUTING.md#-submitting-an-issue). + +A good way to make a minimal repro is to create a new app via `ng new repro-app` and adding the minimum possible code to show the problem. Then you can push this repository to github and link it here. ``` @@ -68,7 +81,7 @@ If you are wondering why we don't resolve support issues via the issue tracker, ``` Hello, errors like `Error encountered resolving symbol values statically` mean that there has been some problem in statically analyzing your app. -Angular CLI always runs *some* statical analysis, even on JIT mode, in order to discover lazy-loaded routes. +Angular CLI always runs *some* static analysis, even in JIT mode, in order to discover lazy-loaded routes. This may cause a lot of static analysis errors to surface when importing your project into the CLI, or upgrading for older versions where we didn't run this kind of analysis. Below are good resources on how to to debug these errors: @@ -78,3 +91,10 @@ Below are good resources on how to to debug these errors: If your problem still persists, it might be a bug with the Angular Compiler itself. In that case, please open an issue in https://github.com/angular/angular. ``` + +## Angular CLI: Lockfiles (v1) +``` +I'd like to remind everyone that **you only have reproducible installs if you use a lockfile**. Both [NPM v5+](https://docs.npmjs.com/files/package-locks) and [Yarn](https://yarnpkg.com/lang/en/docs/yarn-lock/) support lockfiles. If your CI works one day but not the next and you did not change your code or `package.json`, it is likely because one of your dependencies had a bad release and you did not have a lockfile. + +**It is your responsibility as a library consumer to use lockfiles**. No one wants to do a release with bugs but it sometimes happens, and the best we can do is to fix it as fast as possible with a new release. When you have a couple of thousand total dependencies it is only a matter of time until one of them has a bad release. +``` diff --git a/.github/_CODEOWNERS.tmp b/.github/_CODEOWNERS.tmp new file mode 100644 index 000000000000..3e79d395914f --- /dev/null +++ b/.github/_CODEOWNERS.tmp @@ -0,0 +1,17 @@ +/packages/_/ @hansl @clydin +/packages/angular/pwa @hansl @Brocco +/packages/angular_devkit/architect/ @filipesilva @hansl +/packages/angular_devkit/architect_cli/ @filipesilva @hansl +/packages/angular_devkit/build_angular/ @filipesilva @clydin +/packages/angular_devkit/build_ng_packagr/ @filipesilva @clydin +/packages/angular_devkit/build_optimizer/ @filipesilva @clydin +/packages/angular_devkit/core/ @hansl @clydin +/packages/angular_devkit/schematics/ @hansl @Brocco +/packages/angular_devkit/schematics_cli/ @hansl @Brocco +/packages/ngtools/webpack/ @hansl @filipesilva @clydin +/packages/schematics/angular/ @hansl @Brocco +/packages/schematics/package_update/ @hansl @Brocco +/packages/schematics/schematics/ @hansl @Brocco +/packages/schematics/update/ @hansl @Brocco +/rules/ @hansl @clydin +/scripts/ @hansl @clydin diff --git a/.github/angular-robot.yml b/.github/angular-robot.yml new file mode 100644 index 000000000000..5e6b231c9d62 --- /dev/null +++ b/.github/angular-robot.yml @@ -0,0 +1,99 @@ +# Configuration for angular-robot + +# options for the merge plugin +merge: + # the status will be added to your pull requests + status: + # set to true to disable + disabled: false + # the name of the status + context: "ci/angular: merge status" + # text to show when all checks pass + successText: "All checks passed!" + # text to show when some checks are failing + failureText: "The following checks are failing:" + + # comment that will be added to a PR when there is a conflict, leave empty or set to false to disable + mergeConflictComment: "Hi @{{PRAuthor}}! This PR has merge conflicts due to recent upstream merges. +\nPlease help to unblock it by resolving these conflicts. Thanks!" + + # label to monitor + mergeLabel: "PR action: merge" + + # list of checks that will determine if the merge label can be added + checks: + # whether the PR shouldn't have a conflict with the base branch + noConflict: true + # whether the PR should have all reviews completed. + requireReviews: true + # list of labels that a PR needs to have, checked with a regexp (e.g. "PR target:" will work for the label "PR target: master") + requiredLabels: + - "PR target: *" + - "cla: yes" + + # list of labels that a PR shouldn't have, checked after the required labels with a regexp + forbiddenLabels: + - "PR target: TBD" + - "PR action: cleanup" + - "PR action: review" + - "PR state: blocked" + - "cla: no" + + # list of PR statuses that need to be successful + requiredStatuses: + - "continuous-integration/appveyor/pr" + - "ci/circleci: build" + - "ci/circleci: build-bazel" + - "ci/circleci: install" + - "ci/circleci: lint" + - "ci/circleci: validate" + - "ci/circleci: test" + - "ci/circleci: test-large" + + # the comment that will be added when the merge label is added despite failing checks, leave empty or set to false to disable + # {{MERGE_LABEL}} will be replaced by the value of the mergeLabel option + # {{PLACEHOLDER}} will be replaced by the list of failing checks + mergeRemovedComment: "I see that you just added the `{{MERGE_LABEL}}` label, but the following checks are still failing: +\n{{PLACEHOLDER}} +\n +\n**If you want your PR to be merged, it has to pass all the CI checks.** +\n +\nIf you can't get the PR to a green state due to flakes or broken master, please try rebasing to master and/or restarting the CI job. If that fails and you believe that the issue is not due to your change, please contact the caretaker and ask for help." + +# options for the triage plugin +triage: + # set to true to disable + disabled: false + # number of the milestone to apply when the issue has not been triaged yet + needsTriageMilestone: 11, + # number of the milestone to apply when the issue is triaged + defaultMilestone: 12, + # arrays of labels that determine if an issue has been triaged by the caretaker + l1TriageLabels: + - + - "comp: *" + # arrays of labels that determine if an issue has been fully triaged + l2TriageLabels: + - + - "type: bug/fix" + - "severity*" + - "freq*" + - "comp: *" + - + - "type: feature" + - "comp: *" + - + - "type: refactor" + - "comp: *" + - + - "type: RFC / Discussion / question" + - "comp: *" + - + - "type: docs" + - "comp: *" + +# Size checking +size: + circleCiStatusName: "ci/circleci: e2e-cli" + maxSizeIncrease: 10000 + comment: true diff --git a/.gitignore b/.gitignore index cc0280e30214..88895c7481f5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ +# Outputs +bazel-* +test-project-host-* dist/ -node_modules/ -npm-debug.log* -yarn-error.log* +dist-schema/ # IDEs .idea/ @@ -12,7 +13,12 @@ jsconfig.json typings/ # Misc +coverage/ +node_modules/ tmp/ +npm-debug.log* +yarn-error.log* +.ng_pkg_build/ # Mac OSX Finder files. **/.DS_Store diff --git a/.mailmap b/.mailmap index e93c84244f0c..bf8640d5dec9 100644 --- a/.mailmap +++ b/.mailmap @@ -12,6 +12,8 @@ Igor Minar ################################################################################ # Angular CLI Team ################################################################################ +Charles Lyding + Charles Lyding <19598772+clydin@users.noreply.github.com> Filipe Silva Mike Brocchi @@ -26,9 +28,6 @@ Carlo Dapor Cédric Exbrayat Cédric Exbrayat -Charles Lyding - Charles Lyding - Charles Lyding <19598772+clydin@users.noreply.github.com> Chris Pearce Chris Pearce Dominic Watson diff --git a/.monorepo.json b/.monorepo.json new file mode 100644 index 000000000000..aea9500b922e --- /dev/null +++ b/.monorepo.json @@ -0,0 +1,208 @@ +{ + "badges": [ + [ + { + "image": "https://img.shields.io/circleci/project/github/angular/angular-cli/master.svg?label=circleci", + "label": "CircleCI branch", + "url": "https://circleci.com/gh/angular/angular-cli" + }, + { + "title": "![Dependency Status](https://david-dm.org/angular/angular-cli.svg)", + "url": "https://david-dm.org/angular/angular-cli" + }, + { + "title": "![devDependency Status](https://david-dm.org/angular/angular-cli/dev-status.svg)", + "url": "https://david-dm.org/angular/angular-cli?type=dev" + } + ], + [ + { + "label": "License", + "image": "https://img.shields.io/npm/l/@angular/cli.svg", + "url": "https://github.com/angular/angular-cli/blob/master/LICENSE" + } + ], + [ + { + "label": "GitHub forks", + "image": "https://img.shields.io/github/forks/angular/angular-cli.svg?style=social&label=Fork", + "url": "https://github.com/angular/angular-cli/fork" + }, + { + "label": "GitHub stars", + "image": "https://img.shields.io/github/stars/angular/angular-cli.svg?style=social&label=Star", + "url": "https://github.com/angular/angular-cli" + } + ] + ], + "links": { + "Gitter": "https://gitter.im/angular/angular-cli", + "Contributing": "https://github.com/angular/angular-cli/blob/master/CONTRIBUTING.md", + "Angular CLI": "http://github.com/angular/angular-cli" + }, + "packages": { + "@_/benchmark": { + "version": "0.9.0-rc.2", + "hash": "ed6f2ae751fd3db351a20ae55349e8ad" + }, + "@_/builders": { + "version": "0.9.0-rc.2", + "hash": "569aef8bc23693c344e71b9755e62c50" + }, + "devkit": { + "version": "0.9.0-rc.2", + "hash": "9230702b29c8827fca50617e90f4db62" + }, + "@angular/cli": { + "name": "Angular CLI", + "section": "Tooling", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular/cli/README.md" + } + ], + "version": "7.0.0-rc.2", + "snapshotRepo": "angular/cli-builds", + "hash": "0f0265f67cbd611fe76f9cf2a35eac46" + }, + "@angular/pwa": { + "name": "Angular PWA Schematics", + "section": "Schematics", + "version": "0.9.0-rc.2", + "hash": "a575d61acf532ea665ac6705e91a0369", + "snapshotRepo": "angular/angular-pwa-builds" + }, + "@angular-devkit/architect": { + "name": "Architect", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/architect/README.md" + } + ], + "version": "0.9.0-rc.2", + "hash": "c644f2be33bdc5068cf74fb4f7c39e29", + "snapshotRepo": "angular/angular-devkit-architect-builds" + }, + "@angular-devkit/architect-cli": { + "name": "Architect CLI", + "version": "0.9.0-rc.2", + "hash": "f0ad25801262bdf4cd4a83f678af7dd6", + "snapshotRepo": "angular/angular-devkit-architect-cli-builds" + }, + "@angular-devkit/benchmark": { + "name": "Benchmark", + "section": "Tooling", + "version": "1.0.0-rc.2", + "hash": "4809184dd4ad5a0b8e3e28ff460a2837" + }, + "@angular-devkit/build-optimizer": { + "name": "Build Optimizer", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_optimizer/README.md" + } + ], + "version": "0.9.0-rc.2", + "hash": "ab55ec940e1f2e84073b45a16d45e3cd", + "snapshotRepo": "angular/angular-devkit-build-optimizer-builds" + }, + "@angular-devkit/build-ng-packagr": { + "name": "Build NgPackagr", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_ng_packagr/README.md" + } + ], + "version": "0.9.0-rc.2", + "hash": "a7cb02fd554c0947889e974cb9046d96", + "snapshotRepo": "angular/angular-devkit-build-ng-packagr-builds" + }, + "@angular-devkit/build-angular": { + "name": "Build Angular", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/README.md" + } + ], + "version": "0.9.0-rc.2", + "hash": "d7fd8733c5b28f1ef21528b0066f0d1a", + "snapshotRepo": "angular/angular-devkit-build-angular-builds" + }, + "@angular-devkit/build-webpack": { + "name": "Build Webpack", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_webpack/README.md" + } + ], + "version": "0.9.0-rc.2", + "snapshotRepo": "angular/angular-devkit-build-webpack-builds", + "hash": "a2574369237d6b3769f7602ff8fa4a31" + }, + "@angular-devkit/core": { + "name": "Core", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/core/README.md" + } + ], + "version": "7.0.0-rc.2", + "hash": "a5844a4ed97391807c4fd12cb2ef1cf2", + "snapshotRepo": "angular/angular-devkit-core-builds" + }, + "@angular-devkit/schematics": { + "name": "Schematics", + "links": [ + { + "label": "README", + "url": "https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/README.md" + } + ], + "version": "7.0.0-rc.2", + "hash": "c17d545d96ae49c8a80275cfc986eb4c", + "snapshotRepo": "angular/angular-devkit-schematics-builds" + }, + "@angular-devkit/schematics-cli": { + "name": "Schematics CLI", + "section": "Tooling", + "version": "0.9.0-rc.2", + "hash": "e1fdd7b7f2ea718c3a22d16915a91ff6", + "snapshotRepo": "angular/angular-devkit-schematics-cli-builds" + }, + "@ngtools/webpack": { + "name": "Webpack Angular Plugin", + "version": "7.0.0-rc.2", + "section": "Misc", + "hash": "780c036bfa14accd80cd0bd4c2c7704d", + "snapshotRepo": "angular/ngtools-webpack-builds" + }, + "@schematics/angular": { + "name": "Angular Schematics", + "section": "Schematics", + "version": "7.0.0-rc.2", + "hash": "f204ff9639c871494ac8fe050e327df0", + "snapshotRepo": "angular/schematics-angular-builds" + }, + "@schematics/schematics": { + "name": "Schematics Schematics", + "version": "0.9.0-rc.2", + "section": "Schematics", + "hash": "4a3e9d9fc64c6efddb0dfba3b745c92a", + "snapshotRepo": "angular/schematics-schematics-builds" + }, + "@schematics/update": { + "name": "Package Update Schematics", + "version": "0.9.0-rc.2", + "section": "Schematics", + "hash": "6706dfa9fbc9cdbc892fb6e9ed8026f8", + "snapshotRepo": "angular/schematics-update-builds" + } + } +} diff --git a/.nvmrc b/.nvmrc index 1e8b31496214..f599e28b8ab0 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -6 +10 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 9b50b6185d4c..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,122 +0,0 @@ -dist: trusty -sudo: false - -addons: - chrome: stable - -language: node_js - -cache: - directories: - - ./node_modules - -matrix: - fast_finish: true - allow_failures: - - env: nightly - - env: ng2 - - node_js: "7" - - node_js: "8" - include: - - stage: build - script: npm run lint - env: lint - - script: npm run build - env: build - - - stage: test - script: npm run test - env: test - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=0 --nosilent - env: e2e-0 - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=1 --nosilent - env: e2e-1 - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=2 --nosilent - env: e2e-2 - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=3 --nosilent - env: e2e-3 - - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=0 --nosilent --nightly - env: nightly-0 - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=1 --nosilent --nightly - env: nightly-1 - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=2 --nosilent --nightly - env: nightly-2 - - node_js: "6" - os: linux - script: node tests/run_e2e.js --nb-shards=4 --shard=3 --nosilent --nightly - env: nightly-3 - - - node_js: "6" - os: linux - script: node tests/run_e2e.js --eject "--glob=tests/build/**" - env: eject - - # Optional builds. - - node_js: "6" - os: linux - before_script: if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then exit 0; fi - script: node tests/run_e2e.js --ng2 "--glob=tests/{build,test,misc}/**" - env: ng2 - - node_js: "7" - os: linux - before_script: if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then exit 0; fi - script: node tests/run_e2e.js "--glob=tests/{build,test,misc}/**" - env: node7 - - node_js: "8" - os: linux - before_script: if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then exit 0; fi - script: node tests/run_e2e.js "--glob=tests/build/**" - env: node8 - - - stage: deploy - script: skip - env: builds - deploy: - - provider: script - script: node scripts/git-builds.js - skip_cleanup: true - on: - all_branches: true - - stage: deploy - script: skip - env: publish - deploy: - - provider: script - script: node scripts/publish/publish.js - skip_cleanup: true - on: - tags: true - - -before_install: - # Install npm 5. - - npm install -g npm@~5.3.0 - -install: - - npm install - -env: - global: - - DBUS_SESSION_BUS_ADDRESS=/dev/null - # GITHUB_ACCESS_TOKEN= - # This is needed to publish packages to github for continuous packages delivery. - - secure: "XUM1RCN/ZH34ju2PI9eHPRMnSlbj45XcBx/ZnZ13wfau60iJCveU7Ded8SC8uwGDp58rGGePXyJfh5l5dAnIWbSAGNKlrEgGTr41RSCbyzrV6m4lAcwNzUo/PkKum1vAApk21PqscrSSWOBAOC3nMCln25GLzgUMm6G8FBOc599NuszcoQvru+H+4JthSHn4l/nmeTZDs2oCBvwnmng/78rEW5CXvJEpAwuaaZLvzzIFdoZu+SuceYvGnL5xHo0ppPF/0NYzZlb7KBKREp44Lq1lOKlDtH5wqjEi7b2aA7/GnesOgLUBmbbSVUzmCxs6PtzGhD56aiL2Qtu8c4LZyvNfzPXSLbx8ljYmdytHkio9w3377wWFRXJDfIsgv9JKHxxyA0T34yzQkqWbgWKPMgJ3om+lb875iXAtXfNyS0trnN+rwLZZtFxygjHyx8IWY+NZD5i5fyjMdFyetNxbHe3ktI73nY+Tl6hDqJXvN8WwQlMovLNUMcY4wGUoPooLka9L+94uetbf3U4KVgshrLHI59jMZsO0qrDGsCZMubHEy80acrNkCTi/uGIbVR0KF94z81VF+S7edYv80AkQTRijpgNV34045L/IqSHgbueozRgVFj2arkAGGFjLlZJifmsRC/Eq1ZWkKsKY/1NusKssCRtycJQjeLOW0qV1T0w=" - # NPM_TOKEN used for deployment. - - secure: "QDefZm9p3/SQ6ts0WVkzwr1qv4tvxpu5hB5ptTGQwRP02oPQumebE+uazSjhrbMf9zCnlrQSaCV7VxMdqQ0GUdAQ+gZz4mr/6SyT1eThTfgqq4GFX24M5dlcWW4rB6ot5NICPnsvASBVDn4IkapTY135/s5fqp2TeDJmAH8xMxKRbsG/b4+KCvhjpO7WJMZumkrwsWFrtAh1zFjrXoHwEySYPkwZceJmSi7GPmjZLodMmSkMxi4vuOAgrx6kWPTuCszKGXm7+Y1UbjeSSoBYLt2c19oy2dJKrER9sSx8/1yeV1C2JJ/cabYBktcn1svUh0lo1j1YOWtEXaIv7SRU694EtWxiuaL8iIcABHdoaLt/BZ34MLG0RdvFu0i2Bv5HxGWQg5TB/Jy502dqkep5ILofF80Ya9NTeapIPSbI3IEWcsCCw+t0pv/91XXU7mduDwtvBtzwxC4nKS4PITjrFTSrsr0wiLagW6ZCbKMrUitEFgedvsa3Tf8wVtt1s/Z7W2iLt81TTVdCei+46PtLIG3k9R1J78WmPLsGJ3uMXo/Cgc7q5PN66Dx6V1RZMBbS9xG0OPxd8a/6Lj94u6QWS1x50osVPEqUqGmT2tWP5fabrDKLUnVLm2Y0O1eBnnu9ew+ccCKou0FCqlx5ppRekBIaMibHbmgahRLMgNbaJR0=" - - diff --git a/BUILD b/BUILD new file mode 100644 index 000000000000..10cfed3bc771 --- /dev/null +++ b/BUILD @@ -0,0 +1,80 @@ +# 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 +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) # MIT License + +exports_files([ + "LICENSE", + "tsconfig.json", # @external + "tslint.base.json", # @external +]) + +# NOTE: this will move to node_modules/BUILD in a later release +# @external_begin +NODE_MODULES_EXCLUDE = [ + # e.g. node_modules/adm-zip/test/assets/attributes_test/New folder/hidden.txt + "node_modules/**/test/**", + # e.g. node_modules/xpath/docs/function resolvers.md + "node_modules/**/docs/**", + # e.g. node_modules/puppeteer/.local-chromium/mac-536395/chrome-mac/Chromium.app/Contents/Versions/66.0.3347.0/Chromium Framework.framework/Chromium Framework + "node_modules/**/.*/**", + # Ignore paths with spaces. + "node_modules/**/* *", +] + +filegroup( + name = "node_modules", + srcs = glob( + # Only include files we might use, to reduce the file count and surface size of + # filename problems. + [ + "node_modules/**/*.js", + "node_modules/**/*.json", + "node_modules/**/*.d.ts", + ], + exclude = NODE_MODULES_EXCLUDE, + ) + glob(["node_modules/.bin/*"]), +) + +# node_modules filegroup for tools/quicktype_runner, which contains quicktype-core and tslint. +QUICKTYPE_TRANSITIVE_DEPENDENCIES = [ + "collection-utils", + "core-util-is", + "inherits", + "isarray", + "js-base64", + "pako", + "pluralize", + "process-nextick-args", + "quicktype-core", + "readable-stream", + "safe-buffer", + "stream-json", + "string-to-stream", + "tiny-inflate", + "unicode-properties", + "unicode-trie", + "urijs", + "util-deprecate", + "wordwrap", +] + +filegroup( + name = "quicktype_node_modules", + srcs = glob( + [ + "/".join([ + "node_modules", "**", pkg, "**/*.js", + ]) for pkg in QUICKTYPE_TRANSITIVE_DEPENDENCIES + ] + [ + "/".join([ + "node_modules", "**", pkg, "**/*.json", + ]) for pkg in QUICKTYPE_TRANSITIVE_DEPENDENCIES + ], + exclude = NODE_MODULES_EXCLUDE, + ) +) +# @external_end diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3968a29e332..1018473d1ac6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ -# Contributing to Angular CLI +# Contributing to Angular DevKit -We would love for you to contribute to Angular CLI and help make it even better +We would love for you to contribute to DevKit and help make it even better than it is today! As a contributor, here are the guidelines we would like you to follow: @@ -18,7 +18,10 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con ## Got a Question or Problem? -Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](https://stackoverflow.com/questions/tagged/angular-cli) where the questions should be tagged with tag `angular-cli`. +Please, do not open issues for the general support questions as we want to keep GitHub issues for +bug reports and feature requests. You've got much better chances of getting your question answered +on [StackOverflow](https://stackoverflow.com/questions/tagged/angular-devkit) where the questions +should be tagged with tag `angular-cli` or `angular-devkit`. StackOverflow is a much better place to ask questions since: @@ -26,7 +29,8 @@ StackOverflow is a much better place to ask questions since: - questions and answers stay available for public viewing so your question / answer might help someone else - StackOverflow's voting system assures that the best answers are prominently visible. -To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow. +To save your and our time we will be systematically closing all the issues that are requests for +general support and redirecting people to StackOverflow. If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter]. @@ -38,23 +42,13 @@ If you find a bug in the source code or a mistake in the documentation, you can ## Want a Feature? You can *request* a new feature by [submitting an issue](#submit-issue) to our [GitHub Repository][github]. If you would like to *implement* a new feature, please submit an issue with -a proposal for your work first, to be sure that we can use it. Angular CLI is in developer preview -and we are not ready to accept major contributions ahead of the full release. +a proposal for your work first, to be sure that we can use it. +Please consider what kind of change it is: -First open an issue and outline your proposal so that it can be +* For a **Major Feature**, first open an issue and outline your proposal so that it can be discussed. This will also allow us to better coordinate our efforts, prevent duplication of work, and help you to craft the change so that it is successfully accepted into the project. - -**All features require a proper design and review by team members.** Before starting work, you might want to -discuss with us to figure out: - -* Is this something we want? Sometimes people make feature requests that make sense for them, but aren't valuable - to the rest of the CLI users, or impede on other people's workflow. We try to always put the greater community - first. -* Is the API valid? Does it change currently existing flags, or add new ones? -* What's the impact on the rest of the CLI? Does it affect other commands/flags? - -Answering those questions first in the request might help us make a decision. +* **Small Features** can be crafted and directly [submitted as a Pull Request](#submit-pr). ## Submission Guidelines @@ -62,10 +56,11 @@ Answering those questions first in the request might help us make a decision. Before you submit an issue, please search the issue tracker, maybe an issue for your problem already exists and the discussion might inform you of workarounds readily available. -We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. In order to reproduce bugs we will systematically ask you to provide a minimal reproduction scenario using `ng new repro-app`. Having a reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like: +We want to fix all the issues as soon as possible, but before fixing a bug we need to reproduce and confirm it. Having a reproducible scenario gives us wealth of important information without going back & forth to you with additional questions like: - version of Angular CLI used -- `.angular-cli.json` configuration +- `.angular-cli.json` or `angular.json` configuration +- version of Angular DevKit used - 3rd-party libraries and their versions - and most importantly - a use-case that fails @@ -93,7 +88,7 @@ Before you submit your Pull Request (PR) consider the following guidelines: * Create your patch, **including appropriate test cases**. * Follow our [Coding Rules](#rules). -* Run the full Angular CLI test suite, as described in the [developer documentation][dev-doc], +* Run the full Angular CLI and DevKit test suite, as described in the [developer documentation][dev-doc], and ensure that all tests pass (coming soon). * Commit your changes using a descriptive commit message that follows our [commit message conventions](#commit). Adherence to these conventions @@ -110,10 +105,10 @@ Before you submit your Pull Request (PR) consider the following guidelines: git push origin my-fix-branch ``` -* In GitHub, send a pull request to `angular-cli:master`. +* In GitHub, send a pull request to `devkit:master`. * If we suggest changes then: * Make the required updates. - * Re-run the Angular CLI test suites to ensure tests are still passing. + * Re-run the Angular DevKit test suites to ensure tests are still passing. * Rebase your branch and force push to your GitHub repository (this will update your Pull Request): ```shell @@ -164,7 +159,7 @@ To ensure consistency throughout the source code, keep these rules in mind as yo We have very precise rules over how our git commit messages can be formatted. This leads to **more readable messages** that are easy to follow when looking through the **project history**. But also, -we use the git commit messages to **generate the Angular CLI change log**. +we use the git commit messages to **generate the Angular DevKit change log**. ### Commit Message Format Each commit message consists of a **header**, a **body** and a **footer**. The header has a special @@ -189,16 +184,20 @@ If the commit reverts a previous commit, it should begin with `revert: `, follow ### Type Must be one of the following: -* **build**: Changes that affect the build system or external dependencies -* **ci**: Changes to our CI configuration files and scripts -* **docs**: Documentation only changes -* **feat**: A new feature -* **fix**: A bug fix -* **perf**: A code change that improves performance -* **refactor**: A code change that neither fixes a bug nor adds a feature -* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing - semi-colons, etc) -* **test**: Adding missing tests or correcting existing tests +* **build**: Changes that affect the build system or external dependencies. [2] +* **ci**: Changes to our CI configuration files and scripts. [2] +* **docs**: Documentation only changes. +* **feat**: A new feature. [1] +* **fix**: A bug fix. [1] +* **refactor**: A code change that neither fixes a bug nor adds a feature +* **release**: A release commit. Must only include version changes. [2] +* **revert**: A git commit revert. The description must include the original commit message. [2] +* **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc). +* **test**: Adding missing tests or correcting existing tests. + + +[1] This type MUST have a scope. See the next section for more information.
+[2] This type MUST NOT have a scope. It only applies to general scripts and tooling. ### Scope The scope should be the name of the npm package affected as perceived by the person reading changelog generated from the commit messages. @@ -206,23 +205,44 @@ The scope should be the name of the npm package affected as perceived by the per The following is the list of supported scopes: * **@angular/cli** -* **@ngtools/json-schema** -* **@ngtools/logger** +* **@angular/pwa** +* **@angular-devkit/architect** +* **@angular-devkit/architect-cli** +* **@angular-devkit/build-angular** +* **@angular-devkit/build-ng-packagr** +* **@angular-devkit/build-optimizer** +* **@angular-devkit/build-webpack** +* **@angular-devkit/core** +* **@angular-devkit/schematics** +* **@angular-devkit/schematics-cli** * **@ngtools/webpack** +* **@schematics/angular** +* **@schematics/schematics** +* **@schematics/update** -There are currently a few exceptions to the "use package name" rule: - -* **packaging**: used for changes that change the npm package layout in all of our packages, e.g. public path changes, package.json changes done to all packages, d.ts file/format changes, changes to bundles, etc. -* **changelog**: used for updating the release notes in CHANGELOG.md -* none/empty string: useful for `style`, `test` and `refactor` changes that are done across all packages (e.g. `style: add missing semicolons`) ### Subject The subject contains succinct description of the change: * use the imperative, present tense: "change" not "changed" nor "changes" * don't capitalize first letter +* be concise and direct * no dot (.) at the end +### Examples +Examples of valid commit messages: + +* `fix(@angular/cli): prevent the flubber from grassing` +* `refactor(@schematics/angular): move all JSON classes together` + +Examples of invalid commit messages: +* `fix(@angular/cli): add a new XYZ command` + + This is a feature, not a fix. +* `ci(@angular/cli): fix publishing workflow` + + The `ci` type cannot have a scope. + ### Body Just as in the **subject**, use the imperative, present tense: "change" not "changed" nor "changes". The body should include the motivation for the change and contrast this with previous behavior. @@ -248,9 +268,9 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise [coc]: https://github.com/angular/code-of-conduct/blob/master/CODE_OF_CONDUCT.md [commit-message-format]: https://docs.google.com/document/d/1QrDFcIiPjSLDn3EL15IJygNPiHORgU1_OOAqWjiDU5Y/edit# [corporate-cla]: http://code.google.com/legal/corporate-cla-v1.0.html -[dev-doc]: https://github.com/angular/angular-cli#development-hints-for-working-on-angular-cli +[dev-doc]: https://github.com/angular/angular-cli/blob/master/packages/angular/cli/README.md#development-hints-for-working-on-angular-cli [GitHub]: https://github.com/angular/angular-cli [gitter]: https://gitter.im/angular/angular-cli [individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html [js-style-guide]: https://google.github.io/styleguide/jsguide.html -[stackoverflow]: http://stackoverflow.com/questions/tagged/angular-cli +[stackoverflow]: http://stackoverflow.com/questions/tagged/angular-devkit diff --git a/LICENSE b/LICENSE index 47bfda24adf2..8876c32c1969 100644 --- a/LICENSE +++ b/LICENSE @@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index bee1c9f8e33f..f3606ec894ef 100644 --- a/README.md +++ b/README.md @@ -1,208 +1,110 @@ -## Angular CLI -### CLI for Angular applications based on the [ember-cli](http://www.ember-cli.com/) project. + -[![Build Status](https://img.shields.io/travis/angular/angular-cli/master.svg?label=travis)][travis-badge-url] -[![CircleCI branch](https://img.shields.io/circleci/project/github/RedSparr0w/node-csgo-parser/master.svg?label=circleci)](https://circleci.com/gh/angular/angular-cli) -[![Dependency Status][david-badge]][david-badge-url] -[![devDependency Status][david-dev-badge]][david-dev-badge-url] + This file is automatically generated during release. It is important for you to not update + README directly. -[![npm](https://img.shields.io/npm/v/%40angular/cli.svg)][npm-badge-url] -[![npm](https://img.shields.io/npm/v/%40angular/cli/next.svg)][npm-badge-url] -[![npm](https://img.shields.io/npm/l/@angular/cli.svg)][npm-badge-url] -[![npm](https://img.shields.io/npm/dm/@angular/cli.svg)][npm-badge-url] + - If you need to change the content, update `scripts/templates/readme.ejs` + - If you need to add/remove a package or a link, update the .monorepo.json file instead. -[![Join the chat at https://gitter.im/angular/angular-cli](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/angular/angular-cli?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[![Caretaker](https://img.shields.io/badge/caretaker-filipesilva-blue.svg)](https://github.com/filipesilva) + Any changes to README.md directly will result in a failure on CI. +--> -[![GitHub forks](https://img.shields.io/github/forks/angular/angular-cli.svg?style=social&label=Fork)](https://github.com/angular/angular-cli/fork) -[![GitHub stars](https://img.shields.io/github/stars/angular/angular-cli.svg?style=social&label=Star)](https://github.com/angular/angular-cli) +# Angular CLI +### Development tools and libraries specialized for Angular +This is the home of the DevKit and the Angular CLI code. You can find the Angular CLI specific README +[here](https://github.com/angular/angular-cli/blob/master/packages/angular/cli/README.md). -## Note -If you are updating from a beta or RC version, check out our [1.0 Update Guide](https://github.com/angular/angular-cli/wiki/stories-1.0-update). +[![CircleCI branch](https://img.shields.io/circleci/project/github/angular/angular-cli/master.svg?label=circleci)](https://circleci.com/gh/angular/angular-cli) [![Dependency Status](https://david-dm.org/angular/angular-cli.svg)](https://david-dm.org/angular/angular-cli) [![devDependency Status](https://david-dm.org/angular/angular-cli/dev-status.svg)](https://david-dm.org/angular/angular-cli?type=dev) -If you wish to collaborate, check out [our issue list](https://github.com/angular/angular-cli/issues). +[![License](https://img.shields.io/npm/l/@angular/cli.svg)](https://github.com/angular/angular-cli/blob/master/LICENSE) -Before submitting new issues, have a look at [issues marked with the `type: faq` label](https://github.com/angular/angular-cli/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22type%3A%20faq%22%20). +[![GitHub forks](https://img.shields.io/github/forks/angular/angular-cli.svg?style=social&label=Fork)](https://github.com/angular/angular-cli/fork) [![GitHub stars](https://img.shields.io/github/stars/angular/angular-cli.svg?style=social&label=Star)](https://github.com/angular/angular-cli) -## Prerequisites -Both the CLI and generated project have dependencies that require Node 6.9.0 or higher, together -with NPM 3 or higher. -## Table of Contents +### Quick Links +[Gitter](https://gitter.im/angular/angular-cli) | [Contributing](https://github.com/angular/angular-cli/blob/master/CONTRIBUTING.md) | [Angular CLI](http://github.com/angular/angular-cli) | +|---|---|---| -* [Installation](#installation) -* [Usage](#usage) -* [Generating a New Project](#generating-and-serving-an-angular-project-via-a-development-server) -* [Generating Components, Directives, Pipes and Services](#generating-components-directives-pipes-and-services) -* [Updating Angular CLI](#updating-angular-cli) -* [Development Hints for working on Angular CLI](#development-hints-for-working-on-angular-cli) -* [Documentation](#documentation) -* [License](#license) +---- -## Installation - -**BEFORE YOU INSTALL:** please read the [prerequisites](#prerequisites) -```bash -npm install -g @angular/cli -``` - -## Usage - -```bash -ng help -``` - -### Generating and serving an Angular project via a development server - -```bash -ng new PROJECT-NAME -cd PROJECT-NAME -ng serve -``` -Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. - -You can configure the default HTTP host and port used by the development server with two command-line options : - -```bash -ng serve --host 0.0.0.0 --port 4201 -``` - -### Generating Components, Directives, Pipes and Services - -You can use the `ng generate` (or just `ng g`) command to generate Angular components: - -```bash -ng generate component my-new-component -ng g component my-new-component # using the alias - -# components support relative path generation -# if in the directory src/app/feature/ and you run -ng g component new-cmp -# your component will be generated in src/app/feature/new-cmp -# but if you were to run -ng g component ../newer-cmp -# your component will be generated in src/app/newer-cmp -# if in the directory src/app you can also run -ng g component feature/new-cmp -# and your component will be generated in src/app/feature/new-cmp -``` -You can find all possible blueprints in the table below: +## The Goal of Angular CLI -Scaffold | Usage ---- | --- -[Component](https://github.com/angular/angular-cli/wiki/generate-component) | `ng g component my-new-component` -[Directive](https://github.com/angular/angular-cli/wiki/generate-directive) | `ng g directive my-new-directive` -[Pipe](https://github.com/angular/angular-cli/wiki/generate-pipe) | `ng g pipe my-new-pipe` -[Service](https://github.com/angular/angular-cli/wiki/generate-service) | `ng g service my-new-service` -[Class](https://github.com/angular/angular-cli/wiki/generate-class) | `ng g class my-new-class` -[Guard](https://github.com/angular/angular-cli/wiki/generate-guard) | `ng g guard my-new-guard` -[Interface](https://github.com/angular/angular-cli/wiki/generate-interface) | `ng g interface my-new-interface` -[Enum](https://github.com/angular/angular-cli/wiki/generate-enum) | `ng g enum my-new-enum` -[Module](https://github.com/angular/angular-cli/wiki/generate-module) | `ng g module my-module` +The Angular CLI creates, manages, builds and test your Angular projects. It's built on top of the +Angular DevKit. +## The Goal of DevKit +DevKit's goal is to provide a large set of libraries that can be used to manage, develop, deploy and +analyze your code. +# Getting Started - Local Development -angular-cli will add reference to `components`, `directives` and `pipes` automatically in the `app.module.ts`. If you need to add this references to another custom module, follow this steps: - - 1. `ng g module new-module` to create a new module - 2. call `ng g component new-module/new-component` - -This should add the new `component`, `directive` or `pipe` reference to the `new-module` you've created. - -### Updating Angular CLI - -If you're using Angular CLI `1.0.0-beta.28` or less, you need to uninstall `angular-cli` package. It should be done due to changing of package's name and scope from `angular-cli` to `@angular/cli`: -```bash -npm uninstall -g angular-cli -npm uninstall --save-dev angular-cli -``` - -To update Angular CLI to a new version, you must update both the global package and your project's local package. - -Global package: -```bash -npm uninstall -g @angular/cli -npm cache clean -# if npm version is > 5 then use `npm cache verify` to avoid errors (or to avoid using --force) -npm install -g @angular/cli@latest -``` - -Local project package: -```bash -rm -rf node_modules dist # use rmdir /S/Q node_modules dist in Windows Command Prompt; use rm -r -fo node_modules,dist in Windows PowerShell -npm install --save-dev @angular/cli@latest -npm install -``` - -If you are updating to 1.0 from a beta or RC version, check out our [1.0 Update Guide](https://github.com/angular/angular-cli/wiki/stories-1.0-update). - -You can find more details about changes between versions in [the Releases tab on GitHub](https://github.com/angular/angular-cli/releases). +## Installation +To get started locally, follow these instructions: +1. If you haven't done it already, [make a fork of this repo](https://github.com/angular/angular-cli/fork). +1. Clone to your local computer using `git`. +1. Make sure that you have Node 10.9 or later installed. See instructions [here](https://nodejs.org/en/download/). The Angular CLI requires Node 8, but development requires Node 10. +1. Make sure that you have `yarn` installed; see instructions [here](https://yarnpkg.com/lang/en/docs/install/). +1. Run `yarn` (no arguments) from the root of your clone of this project. +1. Run `yarn link` to add all custom scripts we use to your global install. -## Development Hints for working on Angular CLI +## Creating New Packages +Adding a package to this repository means running two separate commands: -### Working with master +1. `schematics devkit:package PACKAGE_NAME`. This will update the `.monorepo` file, and create the + base files for the new package (package.json, src/index, etc). +1. `devkit-admin templates`. This will update the README and all other template files that might + have changed when adding a new package. -```bash -git clone https://github.com/angular/angular-cli.git -cd angular-cli -npm link -``` +For private packages, you will need to add a `"private": true` key to your package.json manually. +This will require re-running the template admin script. -`npm link` is very similar to `npm install -g` except that instead of downloading the package -from the repo, the just cloned `angular-cli/` folder becomes the global package. -Additionally, this repository publishes several packages and we use special logic to load all of them -on development setups. +# Packages -Any changes to the files in the `angular-cli/` folder will immediately affect the global `@angular/cli` package, -allowing you to quickly test any changes you make to the cli project. +This is a monorepo which contains many tools and packages: -Now you can use `@angular/cli` via the command line: -```bash -ng new foo -cd foo -npm link @angular/cli -ng serve -``` -`npm link @angular/cli` is needed because by default the globally installed `@angular/cli` just loads -the local `@angular/cli` from the project which was fetched remotely from npm. -`npm link @angular/cli` symlinks the global `@angular/cli` package to the local `@angular/cli` package. -Now the `angular-cli` you cloned before is in three places: -The folder you cloned it into, npm's folder where it stores global packages and the Angular CLI project you just created. +## Tools -You can also use `ng new foo --link-cli` to automatically link the `@angular/cli` package. +| Project | Package | Version | Links | +|---|---|---|---| +**Angular CLI** | [`@angular/cli`](https://npmjs.com/package/@angular/cli) | [![latest](https://img.shields.io/npm/v/%40angular%2Fcli/latest.svg)](https://npmjs.com/package/@angular/cli) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular/cli/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/cli-builds) +**Schematics CLI** | [`@angular-devkit/schematics-cli`](https://npmjs.com/package/@angular-devkit/schematics-cli) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fschematics-cli/latest.svg)](https://npmjs.com/package/@angular-devkit/schematics-cli) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-schematics-cli-builds) -Please read the official [npm-link documentation](https://docs.npmjs.com/cli/link) -and the [npm-link cheatsheet](http://browsenpm.org/help#linkinganynpmpackagelocally) for more information. -To run the Angular CLI test suite use the `node tests/run_e2e.js` command. -It can also receive a filename to only run that test (e.g. `node tests/run_e2e.js tests/e2e/tests/build/dev-build.ts`). +## Packages -As part of the test procedure, all packages will be built and linked. -You will need to re-run `npm link` to re-link the development Angular CLI environment after tests finish. +| Project | Package | Version | Links | +|---|---|---|---| +**Architect** | [`@angular-devkit/architect`](https://npmjs.com/package/@angular-devkit/architect) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Farchitect/latest.svg)](https://npmjs.com/package/@angular-devkit/architect) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/architect/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-architect-builds) +**Architect CLI** | [`@angular-devkit/architect-cli`](https://npmjs.com/package/@angular-devkit/architect-cli) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Farchitect-cli/latest.svg)](https://npmjs.com/package/@angular-devkit/architect-cli) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-architect-cli-builds) +**Build Angular** | [`@angular-devkit/build-angular`](https://npmjs.com/package/@angular-devkit/build-angular) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-angular/latest.svg)](https://npmjs.com/package/@angular-devkit/build-angular) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_angular/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-angular-builds) +**Build NgPackagr** | [`@angular-devkit/build-ng-packagr`](https://npmjs.com/package/@angular-devkit/build-ng-packagr) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-ng-packagr/latest.svg)](https://npmjs.com/package/@angular-devkit/build-ng-packagr) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_ng_packagr/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-ng-packagr-builds) +**Build Optimizer** | [`@angular-devkit/build-optimizer`](https://npmjs.com/package/@angular-devkit/build-optimizer) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-optimizer/latest.svg)](https://npmjs.com/package/@angular-devkit/build-optimizer) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_optimizer/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-optimizer-builds) +**Build Webpack** | [`@angular-devkit/build-webpack`](https://npmjs.com/package/@angular-devkit/build-webpack) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fbuild-webpack/latest.svg)](https://npmjs.com/package/@angular-devkit/build-webpack) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/build_webpack/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-build-webpack-builds) +**Core** | [`@angular-devkit/core`](https://npmjs.com/package/@angular-devkit/core) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fcore/latest.svg)](https://npmjs.com/package/@angular-devkit/core) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/core/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-core-builds) +**Schematics** | [`@angular-devkit/schematics`](https://npmjs.com/package/@angular-devkit/schematics) | [![latest](https://img.shields.io/npm/v/%40angular-devkit%2Fschematics/latest.svg)](https://npmjs.com/package/@angular-devkit/schematics) | [![README](https://img.shields.io/badge/README--green.svg)](https://github.com/angular/angular-cli/blob/master/packages/angular_devkit/schematics/README.md) [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-devkit-schematics-builds) -## Documentation +#### Schematics -The documentation for the Angular CLI is located in this repo's [wiki](https://github.com/angular/angular-cli/wiki). +| Project | Package | Version | Links | +|---|---|---|---| +**Angular PWA Schematics** | [`@angular/pwa`](https://npmjs.com/package/@angular/pwa) | [![latest](https://img.shields.io/npm/v/%40angular%2Fpwa/latest.svg)](https://npmjs.com/package/@angular/pwa) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/angular-pwa-builds) +**Angular Schematics** | [`@schematics/angular`](https://npmjs.com/package/@schematics/angular) | [![latest](https://img.shields.io/npm/v/%40schematics%2Fangular/latest.svg)](https://npmjs.com/package/@schematics/angular) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/schematics-angular-builds) +**Schematics Schematics** | [`@schematics/schematics`](https://npmjs.com/package/@schematics/schematics) | [![latest](https://img.shields.io/npm/v/%40schematics%2Fschematics/latest.svg)](https://npmjs.com/package/@schematics/schematics) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/schematics-schematics-builds) +**Package Update Schematics** | [`@schematics/update`](https://npmjs.com/package/@schematics/update) | [![latest](https://img.shields.io/npm/v/%40schematics%2Fupdate/latest.svg)](https://npmjs.com/package/@schematics/update) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/schematics-update-builds) -## License +#### Misc -MIT +| Project | Package | Version | Links | +|---|---|---|---| +**Webpack Angular Plugin** | [`@ngtools/webpack`](https://npmjs.com/package/@ngtools/webpack) | [![latest](https://img.shields.io/npm/v/%40ngtools%2Fwebpack/latest.svg)](https://npmjs.com/package/@ngtools/webpack) | [![snapshot](https://img.shields.io/badge/snapshot--blue.svg)](https://github.com/angular/ngtools-webpack-builds) -[travis-badge]: https://travis-ci.org/angular/angular-cli.svg?branch=master -[travis-badge-url]: https://travis-ci.org/angular/angular-cli -[david-badge]: https://david-dm.org/angular/angular-cli.svg -[david-badge-url]: https://david-dm.org/angular/angular-cli -[david-dev-badge]: https://david-dm.org/angular/angular-cli/dev-status.svg -[david-dev-badge-url]: https://david-dm.org/angular/angular-cli?type=dev -[npm-badge]: https://img.shields.io/npm/v/@angular/cli.svg -[npm-badge-url]: https://www.npmjs.com/package/@angular/cli diff --git a/SUPPORT.md b/SUPPORT.md deleted file mode 100644 index 70b95eb65532..000000000000 --- a/SUPPORT.md +++ /dev/null @@ -1,16 +0,0 @@ -# Got a Question or Problem? - -Please, do not open issues for the general support questions as we want to keep GitHub issues for bug reports and feature requests. You've got much better chances of getting your question answered on [StackOverflow](https://stackoverflow.com/questions/tagged/angular-cli) where the questions should be tagged with tag `angular-cli`. - -StackOverflow is a much better place to ask questions since: - -- there are thousands of people willing to help on StackOverflow -- questions and answers stay available for public viewing so your question / answer might help someone else -- StackOverflow's voting system assures that the best answers are prominently visible. - -To save your and our time we will be systematically closing all the issues that are requests for general support and redirecting people to StackOverflow. - -If you would like to chat about the question in real-time, you can reach out via [our gitter channel][gitter]. - - -[gitter]: https://gitter.im/angular/angular-cli \ No newline at end of file diff --git a/WORKSPACE b/WORKSPACE new file mode 100644 index 000000000000..14eab931653d --- /dev/null +++ b/WORKSPACE @@ -0,0 +1,92 @@ +workspace(name = "angular_devkit") + +# We get Buildifier from here. +http_archive( + name = "com_github_bazelbuild_buildtools", + url = "https://github.com/bazelbuild/buildtools/archive/0.15.0.zip", + strip_prefix = "buildtools-0.15.0", + sha256 = "76d1837a86fa6ef5b4a07438f8489f00bfa1b841e5643b618e01232ba884b1fe", +) + +load("@com_github_bazelbuild_buildtools//buildifier:deps.bzl", "buildifier_dependencies") +buildifier_dependencies() + +# The Go toolchain is used for Buildifier. +# rules_typescript_dependencies() also tries to load it but we add it explicitely so we +# don't have hidden dependencies. +# This also means we need to load it before rules_typescript_dependencies(). +http_archive( + name = "io_bazel_rules_go", + url = "https://github.com/bazelbuild/rules_go/archive/0.14.0.zip", + strip_prefix = "rules_go-0.14.0", + sha256 = "9bd7c2743f014e4e112b671098ba1da6aec036fe07093b10ca39a9f81ec5cc33", +) + +load("@io_bazel_rules_go//go:def.bzl", "go_register_toolchains", "go_rules_dependencies") +go_rules_dependencies() +go_register_toolchains() + +# We need a minimum of this version to include https://github.com/bazelbuild/rules_nodejs/pull/281. +http_archive( + name = "build_bazel_rules_nodejs", + url = "https://github.com/bazelbuild/rules_nodejs/archive/0.12.4.zip", + strip_prefix = "rules_nodejs-0.12.4", + sha256 = "c482700e032b4df60425cb9a6f8f28152fb1c4c947a9d61e6132fc59ce332b16", +) + +# Load the TypeScript rules, its dependencies, and setup the workspace. +http_archive( + name = "build_bazel_rules_typescript", + url = "https://github.com/bazelbuild/rules_typescript/archive/0.16.1.zip", + strip_prefix = "rules_typescript-0.16.1", + sha256 = "5b2b0bc63cfcffe7bf97cad2dad3b26a73362f806de66207051f66c87956a995", +) + +load("@build_bazel_rules_typescript//:package.bzl", "rules_typescript_dependencies") +# build_bazel_rules_nodejs is loaded transitively through rules_typescript_dependencies. +rules_typescript_dependencies() + +load("@build_bazel_rules_typescript//:defs.bzl", "ts_setup_workspace") +ts_setup_workspace() + +# Load the nodejs dependencies, check minimum Bazel version, and define the local node_modules. +load("@build_bazel_rules_nodejs//:package.bzl", "rules_nodejs_dependencies") +rules_nodejs_dependencies() + +load("@build_bazel_rules_nodejs//:defs.bzl", "check_bazel_version", "node_repositories") +check_bazel_version("0.15.0") +node_repositories( + package_json = ["//:package.json"], + preserve_symlinks = True, + node_version = "10.9.0", + yarn_version = "1.9.2", + node_repositories = { + "10.9.0-darwin_amd64": ( + "node-v10.9.0-darwin-x64.tar.gz", + "node-v10.9.0-darwin-x64", + "3c4fe75dacfcc495a432a7ba2dec9045cff359af2a5d7d0429c84a424ef686fc" + ), + "10.9.0-linux_amd64": ( + "node-v10.9.0-linux-x64.tar.xz", + "node-v10.9.0-linux-x64", + "c5acb8b7055ee0b6ac653dc4e458c5db45348cecc564b388f4ed1def84a329ff" + ), + "10.9.0-windows_amd64": ( + "node-v10.9.0-win-x64.zip", + "node-v10.9.0-win-x64", + "6a75cdbb69d62ed242d6cbf0238a470bcbf628567ee339d4d098a5efcda2401e" + ), + }, + yarn_repositories = { + "1.9.2": ( + "yarn-v1.9.2.tar.gz", + "yarn-v1.9.2", + "3ad69cc7f68159a562c676e21998eb21b44138cae7e8fe0749a7d620cf940204" + ), + }, +) + +local_repository( + name = "rxjs", + path = "node_modules/rxjs/src", +) diff --git a/benchmark/aio/.gitignore b/benchmark/aio/.gitignore new file mode 100644 index 000000000000..3c85010e11ea --- /dev/null +++ b/benchmark/aio/.gitignore @@ -0,0 +1 @@ +angular/ \ No newline at end of file diff --git a/benchmark/aio/package.json b/benchmark/aio/package.json new file mode 100644 index 000000000000..fce9b14e36f7 --- /dev/null +++ b/benchmark/aio/package.json @@ -0,0 +1,18 @@ +{ + "name": "aio-benchmark", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "initialize": "yarn clone && yarn setup && yarn update", + "clone": "(git clone https://github.com/angular/angular --depth 1 || true) && cd angular && git fetch origin dd2a650c3455f3bc0a88f8181758a84aacb25fea && git checkout -f FETCH_HEAD", + "setup": "cd angular && yarn && cd aio && yarn && yarn setup", + "update": "cd angular/aio && yarn add ../../../../dist/_angular-devkit_build-angular.tgz --dev", + "//": "Shouldn't need to install the package twice, but the first install seems to leave two @ngtools/webpack installs around.", + "postupdate": "cd angular/aio && yarn add ../../../../dist/_angular-devkit_build-angular.tgz --dev", + "benchmark": "cd angular/aio && benchmark --verbose -- yarn ~~build --configuration=stable" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/bin/architect b/bin/architect new file mode 100755 index 000000000000..7885feefe26a --- /dev/null +++ b/bin/architect @@ -0,0 +1,14 @@ +#!/usr/bin/env node +/** + * @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 + */ +'use strict'; + + +require('../lib/bootstrap-local'); +const packages = require('../lib/packages').packages; +require(packages['@angular-devkit/architect-cli'].bin['architect']); diff --git a/bin/benchmark b/bin/benchmark new file mode 100755 index 000000000000..4ada663d8bfc --- /dev/null +++ b/bin/benchmark @@ -0,0 +1,19 @@ +#!/usr/bin/env node +/** + * @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 + */ +'use strict'; + + +require('../lib/bootstrap-local'); +const packages = require('../lib/packages').packages; +const main = require(packages['@angular-devkit/benchmark'].bin['benchmark']).main; + +const args = process.argv.slice(2); +main({ args }) + .then(exitCode => process.exitCode = exitCode) + .catch(e => { throw (e); }); diff --git a/bin/build-optimizer b/bin/build-optimizer new file mode 100755 index 000000000000..6f540387043c --- /dev/null +++ b/bin/build-optimizer @@ -0,0 +1,14 @@ +#!/usr/bin/env node +/** + * @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 + */ +'use strict'; + + +require('../lib/bootstrap-local'); +const packages = require('../lib/packages').packages; +require(packages['@angular-devkit/build-optimizer'].bin['build-optimizer']); diff --git a/bin/devkit-admin b/bin/devkit-admin new file mode 100755 index 000000000000..45abb60cc659 --- /dev/null +++ b/bin/devkit-admin @@ -0,0 +1,77 @@ +#!/usr/bin/env node +/** + * @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 + */ +'use strict'; + +/** + * This file is useful for not having to load bootstrap-local in various javascript. + * Simply use package.json to have npm scripts that use this script as well, or use + * this script directly. + */ +require('../lib/bootstrap-local'); + + +const minimist = require('minimist'); +const path = require('path'); + +const args = minimist(process.argv.slice(2), { + boolean: ['verbose'] +}); +const scriptName = args._.shift(); +const scriptPath = path.join('../scripts', scriptName); + +const cwd = process.cwd(); +process.chdir(path.join(__dirname, '..')); + + +// This might get awkward, so we fallback to console if there was an error. +let logger = null; +try { + logger = new (require('@angular-devkit/core').logging.IndentLogger)('root'); + const { bold, gray, red, yellow, white } = require('@angular-devkit/core').terminal; + const filter = require('rxjs/operators').filter; + + logger + .pipe(filter(entry => (entry.level !== 'debug' || args.verbose))) + .subscribe(entry => { + let color = gray; + let output = process.stdout; + switch (entry.level) { + case 'info': color = white; break; + case 'warn': color = yellow; break; + case 'error': color = red; output = process.stderr; break; + case 'fatal': color = x => bold(red(x)); output = process.stderr; break; + } + + output.write(color(entry.message) + '\n'); + }); +} catch (e) { + console.error(`Reverting to manual console logging.\nReason: ${e.message}.`); + logger = { + debug: console.log.bind(console), + info: console.log.bind(console), + warn: console.warn.bind(console), + error: console.error.bind(console), + fatal: x => { console.error(x); process.exit(100); }, + createChild: () => logger, + }; +} + + +try { + Promise.resolve() + .then(() => require(scriptPath).default(args, logger, cwd)) + .then(exitCode => process.exit(exitCode || 0)) + .catch(err => { + logger.fatal(err.stack); + process.exit(99); + }); +} catch (err) { + logger.fatal(err.stack); + process.exit(99); +} diff --git a/bin/ng b/bin/ng index 64e49f258ceb..d43c5512e47b 100755 --- a/bin/ng +++ b/bin/ng @@ -1,9 +1,14 @@ #!/usr/bin/env node +/** + * @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 + */ 'use strict'; -// Provide a title to the process in `ps`. -// Due to an obscure Mac bug, do not start this title with any symbol. -process.title = 'ng'; require('../lib/bootstrap-local'); -require('../packages/@angular/cli/bin/ng'); +const packages = require('../lib/packages').packages; +require(packages['@angular/cli'].bin['ng']); diff --git a/bin/schematics b/bin/schematics new file mode 100755 index 000000000000..ea3f5176befa --- /dev/null +++ b/bin/schematics @@ -0,0 +1,14 @@ +#!/usr/bin/env node +/** + * @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 + */ +'use strict'; + + +require('../lib/bootstrap-local'); +const packages = require('../lib/packages').packages; +require(packages['@angular-devkit/schematics-cli'].bin['schematics']).main({ args: process.argv.slice(2) }); diff --git a/docs/design/deployurl-basehref.md b/docs/design/deployurl-basehref.md new file mode 100644 index 000000000000..160975423aeb --- /dev/null +++ b/docs/design/deployurl-basehref.md @@ -0,0 +1,18 @@ +| | Deploy URL | Base HREF | +|--|:--:|:--:| +| Initial scripts (index.html) | ✅ 👠| ✅ 👠| +| Initial stylesheets (index.html) | ✅ 👠| ✅ 👠| +| Lazy scripts (routes/import()/etc.) | ✅ 👠| ✅ 👠| +| Processed CSS resources (images/fonts/etc.) | ✅ 👠| ✅ 👠| +| Relative template (HTML) assets | ⌠👎 | ✅ 👠| +| Angular Router Default Base (APP_BASE_HREF) | ⌠| ✅ *1 | +| Single reference in deployed Application | ⌠👎 | ✅ 👠| +| Special resource logic within CLI | ✅ 👎 | ⌠👠| +| Relative fetch/XMLHttpRequest | ⌠| ✅ | + +✅ - has/affects the item/trait +⌠- does not have/affect the item/trait +👠- favorable behavior +👎 - unfavorable behavior + +*1 -- Users with more complicated setups may need to manually configure the `APP_BASE_HREF` token within the application. (e.g., application routing base is `/` but assets/scripts/etc. are at `/assets/`) \ No newline at end of file diff --git a/docs/design/docker-deploy.md b/docs/design/docker-deploy.md index 634fdc8b3e21..d37455e68713 100644 --- a/docs/design/docker-deploy.md +++ b/docs/design/docker-deploy.md @@ -436,19 +436,19 @@ The "2. Docker CLI tools via `child_process.exec`" method is recommended based o * [Docker Run](https://docs.docker.com/engine/reference/run/) * [Docker-Compose File](https://docs.docker.com/compose/compose-file/) -* [Kubernetes Pod](http://kubernetes.io/docs/api-reference/v1/definitions/#_v1_pod) +* [Kubernetes Pod](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.10/) * [Marathon App](https://mesosphere.github.io/marathon/docs/rest-api.html#post-v2-apps) * [Tutum Container](https://docs.tutum.co/v2/api/#container) -* [AWS Elastic Beanstalk/ECS Task Definition](http://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_defintions.html) -* [Azure Service Fabric App](https://azure.microsoft.com/en-us/documentation/articles/service-fabric-deploy-remove-applications/) -* [Heroku Docker CLI](https://github.com/heroku/heroku-docker) +* [AWS Elastic Beanstalk/ECS Task Definition](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/task_definitions.html) +* [Azure Service Fabric App](https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-deploy-remove-applications) +* [Heroku Docker CLI](https://github.com/heroku/heroku-container-tools) * [Redspread](https://github.com/redspread/spread) * [Docker Universal Control Plane](https://www.docker.com/products/docker-universal-control-plane) * [Puppet Docker Module](https://github.com/garethr/garethr-docker) * [Chef Docker Cookbook](https://supermarket.chef.io/cookbooks/docker) -* [Ansible Docker Module](http://docs.ansible.com/ansible/docker_module.html) +* [Ansible Docker Module](https://docs.ansible.com/ansible/latest/modules/docker_module.html) * [Bamboo Docker Tasks](https://confluence.atlassian.com/bamboo/configuring-the-docker-task-in-bamboo-720411254.html) -* [Freight Forwarder Manifest](http://freight-forwarder.readthedocs.org/en/latest/config/overview.html) +* [Freight Forwarder Manifest](http://freight-forwarder.readthedocs.io/en/latest/config/overview.html) * [Gulp Docker Tasks](https://www.npmjs.com/package/gulp-docker) * [Grunt Dock Tasks](https://www.npmjs.com/package/grunt-dock) -* [Robo Docker Tasks](http://robo.li/tasks/Docker/) +* [Robo Docker Tasks](https://robo.li/tasks/Docker/) diff --git a/docs/documentation/angular-cli.md b/docs/documentation/1-x/angular-cli.md similarity index 100% rename from docs/documentation/angular-cli.md rename to docs/documentation/1-x/angular-cli.md diff --git a/docs/documentation/1-x/build.md b/docs/documentation/1-x/build.md new file mode 100644 index 000000000000..211aa1dc7a5b --- /dev/null +++ b/docs/documentation/1-x/build.md @@ -0,0 +1,407 @@ + + +# ng build + +## Overview +`ng build` compiles the application into an output directory + +### Creating a build + +```bash +ng build +``` + +The build artifacts will be stored in the `dist/` directory. + +All commands that build or serve your project, `ng build/serve/e2e`, will delete the output +directory (`dist/` by default). +This can be disabled via the `--no-delete-output-path` (or `--delete-output-path=false`) flag. + +### Build Targets and Environment Files + +`ng build` can specify both a build target (`--target=production` or `--target=development`) and an +environment file to be used with that build (`--environment=dev` or `--environment=prod`). +By default, the development build target and environment are used. + +The mapping used to determine which environment file is used can be found in `.angular-cli.json`: + +```json +"environmentSource": "environments/environment.ts", +"environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" +} +``` + +These options also apply to the serve command. If you do not pass a value for `environment`, +it will default to `dev` for `development` and `prod` for `production`. + +```bash +# these are equivalent +ng build --target=production --environment=prod +ng build --prod --env=prod +ng build --prod +# and so are these +ng build --target=development --environment=dev +ng build --dev --e=dev +ng build --dev +ng build +``` + +You can also add your own env files other than `dev` and `prod` by doing the following: +- create a `src/environments/environment.NAME.ts` +- add `{ "NAME": 'src/environments/environment.NAME.ts' }` to the `apps[0].environments` object in `.angular-cli.json` +- use them via the `--env=NAME` flag on the build/serve commands. + +### Base tag handling in index.html + +When building you can modify base tag (``) in your index.html with `--base-href your-url` option. + +```bash +# Sets base tag href to /myUrl/ in your index.html +ng build --base-href /myUrl/ +ng build --bh /myUrl/ +``` + +### Bundling & Tree-Shaking + +All builds make use of bundling and limited tree-shaking, while `--prod` builds also run limited +dead code elimination via UglifyJS. + +### `--dev` vs `--prod` builds + +Both `--dev`/`--target=development` and `--prod`/`--target=production` are 'meta' flags, that set other flags. +If you do not specify either you will get the `--dev` defaults. + +Flag | `--dev` | `--prod` +--- | --- | --- +`--aot` | `false` | `true` +`--environment` | `dev` | `prod` +`--output-hashing` | `media` | `all` +`--sourcemaps` | `true` | `false` +`--extract-css` | `false` | `true` +`--named-chunks`   | `true` | `false` +`--build-optimizer` | `false` | `true` with AOT and Angular 5 + +`--prod` also sets the following non-flaggable settings: +- Adds service worker if configured in `.angular-cli.json`. +- Replaces `process.env.NODE_ENV` in modules with the `production` value (this is needed for some libraries, like react). +- Runs UglifyJS on the code. + +### `--build-optimizer` and `--vendor-chunk` + +When using Build Optimizer the vendor chunk will be disabled by default. +You can override this with `--vendor-chunk=true`. + +Total bundle sizes with Build Optimizer are smaller if there is no separate vendor chunk because +having vendor code in the same chunk as app code makes it possible for Uglify to remove more unused +code. + +### CSS resources + +Resources in CSS, such as images and fonts, will be copied over automatically as part of a build. +If a resource is less than 10kb it will also be inlined. + +You'll see these resources be outputted and fingerprinted at the root of `dist/`. + +### Service Worker + +There is experimental service worker support for production builds available in the CLI. +To enable it, run the following commands: +``` +npm install @angular/service-worker --save +ng set apps.0.serviceWorker=true +``` + +On `--prod` builds a service worker manifest will be created and loaded automatically. +Remember to disable the service worker while developing to avoid stale code. + +Note: service worker support is experimental and subject to change. + +### ES2015 support + +To build in ES2015 mode, edit `./tsconfig.json` to use `"target": "es2015"` (instead of `es5`). + +This will cause application TypeScript and Uglify be output as ES2015, and third party libraries +to be loaded through the `es2015` entry in `package.json` if available. + +Be aware that JIT does not support ES2015 and so you should build/serve your app with `--aot`. +See https://github.com/angular/angular-cli/issues/7797 for details. + +## Options +
+ aot +

+ --aot default value: false +

+

+ Build using Ahead of Time compilation. +

+
+ +
+ app +

+ --app (aliases: -a) +

+

+ Specifies app name or index to use. +

+
+ +
+ base-href +

+ --base-href (aliases: -bh) +

+

+ Base url for the application being built. +

+
+ +
+ deploy-url +

+ --deploy-url (aliases: -d) +

+

+ URL where files will be deployed. +

+
+ +
+ environment +

+ --environment (aliases: -e) +

+

+ Defines the build environment. +

+
+ +
+ extract-css +

+ --extract-css (aliases: -ec) +

+

+ Extract css from global styles onto css files instead of js ones. +

+
+ +
+ i18n-file +

+ --i18n-file +

+

+ Localization file to use for i18n. +

+
+ +
+ i18n-format +

+ --i18n-format +

+

+ Format of the localization file specified with --i18n-file. +

+
+ +
+ locale +

+ --locale +

+

+ Locale to use for i18n. +

+
+ +
+ missing-translation +

+ --missing-translation +

+

+ How to handle missing translations for i18n. +

+

+ Values: error, warning, ignore +

+
+ +
+ output-hashing +

+ --output-hashing (aliases: -oh) +

+

+ Define the output filename cache-busting hashing mode. +

+

+ Values: none, all, media, bundles +

+
+ +
+ output-path +

+ --output-path (aliases: -op) +

+

+ Path where output will be placed. +

+
+ +
+ delete-output-path +

+ --delete-output-path (aliases: -dop) default value: true +

+

+ Delete the output-path directory. +

+
+ +
+ poll +

+ --poll +

+

+ Enable and define the file watching poll time period (milliseconds). +

+
+ +
+ progress +

+ --progress (aliases: -pr) default value: true inside TTY, false otherwise +

+

+ Log progress to the console while building. +

+
+ +
+ sourcemap +

+ --sourcemap (aliases: -sm, sourcemaps) +

+

+ Output sourcemaps. +

+
+ +
+ stats-json +

+ --stats-json +

+

+ Generates a stats.json file which can be analyzed using tools such as: webpack-bundle-analyzer or https://webpack.github.io/analyse/. +

+
+ +
+ target +

+ --target (aliases: -t, -dev, -prod) default value: development +

+

+ Defines the build target. +

+
+ +
+ vendor-chunk +

+ --vendor-chunk (aliases: -vc) default value: true +

+

+ Use a separate bundle containing only vendor libraries. +

+
+ +
+ common-chunk +

+ --common-chunk (aliases: -cc) default value: true +

+

+ Use a separate bundle containing code used across multiple bundles. +

+
+ +
+ verbose +

+ --verbose (aliases: -v) default value: false +

+

+ Adds more details to output logging. +

+
+ +
+ watch +

+ --watch (aliases: -w) +

+

+ Run build when files change. +

+
+ +
+ show-circular-dependencies +

+ --show-circular-dependencies (aliases: -scd) +

+

+ Show circular dependency warnings on builds. +

+
+ +
+ build-optimizer +

+ --build-optimizer +

+

+ Enables @angular-devkit/build-optimizer optimizations when using `--aot`. +

+
+ +
+ named-chunks +

+ --named-chunks (aliases: -nc) +

+

+ Use file name for lazy loaded chunks. +

+
+ +
+ bundle-dependencies +

+ --bundle-dependencies +

+

+ In a server build, state whether `all` or `none` dependencies should be bundles in the output. +

+
+ + +
+ extract-licenses +

+ --extract-licenses default value: true +

+

+ Extract all licenses in a separate file, in the case of production builds only. +

+
diff --git a/docs/documentation/1-x/config.md b/docs/documentation/1-x/config.md new file mode 100644 index 000000000000..b114b60c0d7d --- /dev/null +++ b/docs/documentation/1-x/config.md @@ -0,0 +1,20 @@ + + +# ng config + +## Overview +`ng config [key] [value]` Get/set configuration values. +`[key]` should be in JSON path format. Example: `a[3].foo.bar[2]`. +If only the `[key]` is provided it will get the value. +If both the `[key]` and `[value]` are provided it will set the value. + +## Options +
+ global +

+ --global default value: false +

+

+ Get/set the value in the global configuration (in your home directory). +

+
diff --git a/docs/documentation/1-x/doc.md b/docs/documentation/1-x/doc.md new file mode 100644 index 000000000000..f6ea8b2d8d33 --- /dev/null +++ b/docs/documentation/1-x/doc.md @@ -0,0 +1,18 @@ + + +# ng doc + +## Overview +`ng doc [search term]` Opens the official Angular API documentation for a given keyword on [angular.io](https://angular.io). + +## Options + +
+ search +

+ --search (alias: -s) default value: false +

+

+ Search for the keyword in the whole [angular.io](https://angular.io) documentation instead of just the API. +

+
diff --git a/docs/documentation/1-x/e2e.md b/docs/documentation/1-x/e2e.md new file mode 100644 index 000000000000..6e638298b67d --- /dev/null +++ b/docs/documentation/1-x/e2e.md @@ -0,0 +1,81 @@ + + +# ng e2e + +## Overview +`ng e2e` serves the application and runs end-to-end tests + +### Running end-to-end tests + +```bash +ng e2e +``` + +End-to-end tests are run via [Protractor](http://www.protractortest.org/). + +## Options + +Please note that options that are supported by `ng serve` are also supported by `ng e2e` + +
+ config +

+ --config (aliases: -c) +

+

+ Use a specific config file. Defaults to the protractor config file in .angular-cli.json. +

+
+ +
+ element-explorer +

+ --element-explorer (aliases: -ee) default value: false +

+

+ Start Protractor's Element Explorer for debugging. +

+
+ +
+ serve +

+ --serve (aliases: -s) default value: true +

+

+ Compile and Serve the app. All serve options are also available. The live-reload option defaults to false, and the default port will be random. +

+

+ NOTE: Build failure will not launch the e2e task. You must first fix error(s) and run e2e again. +

+
+ +
+ specs +

+ --specs (aliases: -sp) default value: [] +

+

+ Override specs in the protractor config. Can send in multiple specs by repeating flag (ng e2e --specs=spec1.ts --specs=spec2.ts). +

+
+ +
+ suite +

+ --suite (aliases: -su) +

+

+ Override suite in the protractor config. Can send in multiple suite by comma separated values (ng e2e --suite=suiteA,suiteB). +

+
+ +
+ webdriver-update +

+ --webdriver-update (aliases: -wu) default value: true +

+

+ Try to update webdriver. +

+
diff --git a/docs/documentation/1-x/eject.md b/docs/documentation/1-x/eject.md new file mode 100644 index 000000000000..d1c55e34a6a0 --- /dev/null +++ b/docs/documentation/1-x/eject.md @@ -0,0 +1,233 @@ + + +# ng eject + +## Overview +`ng eject` ejects your app and output the proper webpack configuration and scripts. + +This command uses the same flags as `ng build`, generating webpack configuration to match those +flags. + +You can use `--force` to overwrite existing configurations. +You can eject multiple times, to have a dev and prod config for instance, by renaming the ejected +configuration and using the `--force` flag. + +### Ejecting the CLI + +```bash +ng eject +``` + +## Options +
+ aot +

+ --aot +

+

+ Build using Ahead of Time compilation. +

+
+ +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ base-href +

+ --base-href (aliases: -bh) +

+

+ Base url for the application being built. +

+
+ +
+ deploy-url +

+ --deploy-url (aliases: -d) +

+

+ URL where files will be deployed. +

+
+ +
+ environment +

+ --environment (aliases: -e) +

+

+ Defines the build environment. +

+
+ +
+ extract-css +

+ --extract-css (aliases: -ec) +

+

+ Extract css from global styles onto css files instead of js ones. +

+
+ +
+ force +

+ --force default value: false +

+

+ Overwrite any webpack.config.js and npm scripts already existing. +

+
+ +
+ i18n-file +

+ --i18n-file +

+

+ Localization file to use for i18n. +

+
+ +
+ i18n-format +

+ --i18n-format +

+

+ Format of the localization file specified with --i18n-file. +

+
+ +
+ locale +

+ --locale +

+

+ Locale to use for i18n. +

+
+ +
+ missing-translation +

+ --missing-translation +

+

+ How to handle missing translations for i18n. +

+

+ Values: error, warning, ignore +

+
+ +
+ output-hashing +

+ --output-hashing (aliases: -oh) default value: +

+

+ Define the output filename cache-busting hashing mode. Possible values: none, all, media, bundles +

+
+ +
+ output-path +

+ --output-path (aliases: -op) default value: +

+

+ Path where output will be placed. +

+
+ +
+ poll +

+ --poll +

+

+ Enable and define the file watching poll time period (milliseconds) . +

+
+ +
+ progress +

+ --progress (aliases: -pr) default value: true inside TTY, false otherwise +

+

+ Log progress to the console while building. +

+
+ +
+ sourcemap +

+ --sourcemap (aliases: -sm, sourcemaps) +

+

+ Output sourcemaps. +

+
+ +
+ target +

+ --target (aliases: -t, -dev, -prod) default value: development +

+

+ Defines the build target. +

+
+ +
+ vendor-chunk +

+ --vendor-chunk (aliases: -vc) default value: true +

+

+ Use a separate bundle containing only vendor libraries. +

+
+ +
+ common-chunk +

+ --common-chunk (aliases: -cc) default value: true +

+

+ Use a separate bundle containing code used across multiple bundles. +

+
+ +
+ verbose +

+ --verbose (aliases: -v) default value: false +

+

+ Adds more details to output logging. +

+
+ +
+ watch +

+ --watch (aliases: -w) +

+

+ Run build when files change. +

+
diff --git a/docs/documentation/1-x/generate.md b/docs/documentation/1-x/generate.md new file mode 100644 index 000000000000..74bae41b3a65 --- /dev/null +++ b/docs/documentation/1-x/generate.md @@ -0,0 +1,48 @@ + + +# ng generate + +## Overview +`ng generate [name]` generates the specified blueprint + +## Available blueprints: + - [class](1-x/generate/class) + - [component](1-x/generate/component) + - [directive](1-x/generate/directive) + - [enum](1-x/generate/enum) + - [guard](1-x/generate/guard) + - [interface](1-x/generate/interface) + - [module](1-x/generate/module) + - [pipe](1-x/generate/pipe) + - [service](1-x/generate/service) + +## Options +
+ dry-run +

+ --dry-run (aliases: -d) default value: false +

+

+ Run through without making any changes. +

+
+ +
+ force +

+ --force (aliases: -f) default value: false +

+

+ Forces overwriting of files. +

+
+ +
+ app +

+ --app +

+

+ Specifies app name to use. +

+
diff --git a/docs/documentation/1-x/generate/class.md b/docs/documentation/1-x/generate/class.md new file mode 100644 index 000000000000..e1ccd6f5c1b0 --- /dev/null +++ b/docs/documentation/1-x/generate/class.md @@ -0,0 +1,27 @@ + + +# ng generate class + +## Overview +`ng generate class [name]` generates a class + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
diff --git a/docs/documentation/1-x/generate/component.md b/docs/documentation/1-x/generate/component.md new file mode 100644 index 000000000000..37b31a077b67 --- /dev/null +++ b/docs/documentation/1-x/generate/component.md @@ -0,0 +1,117 @@ + + +# ng generate component + +## Overview +`ng generate component [name]` generates a component + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ change-detection +

+ --change-detection (aliases: -c) +

+

+ Specifies the change detection strategy. +

+
+ +
+ flat +

+ --flat default value: false +

+

+ Flag to indicate if a dir is created. +

+
+ +
+ export +

+ --export default value: false +

+

+ Specifies if declaring module exports the component. +

+
+ +
+ inline-style +

+ --inline-style (aliases: -s) default value: false +

+

+ Specifies if the style will be in the ts file. +

+
+ +
+ inline-template +

+ --inline-template (aliases: -t) default value: false +

+

+ Specifies if the template will be in the ts file. +

+
+ +
+ module +

+ --module (aliases: -m) +

+

+ Allows specification of the declaring module's file name (e.g `app.module.ts`). +

+
+ +
+ prefix +

+ --prefix +

+

+ Specifies whether to use the prefix. +

+
+ +
+ skip-import +

+ --skip-import default value: false +

+

+ Allows for skipping the module import. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
+ +
+ view-encapsulation +

+ --view-encapsulation (aliases: -v) +

+

+ Specifies the view encapsulation strategy. +

+
diff --git a/docs/documentation/1-x/generate/directive.md b/docs/documentation/1-x/generate/directive.md new file mode 100644 index 000000000000..9ed8f37046c7 --- /dev/null +++ b/docs/documentation/1-x/generate/directive.md @@ -0,0 +1,77 @@ + + +# ng generate directive + +## Overview +`ng generate directive [name]` generates a directive + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ export +

+ --export default value: false +

+

+ Specifies if declaring module exports the component. +

+
+ +
+ flat +

+ --flat +

+

+ Flag to indicate if a dir is created. +

+
+ +
+ module +

+ --module (aliases: -m) +

+

+ Allows specification of the declaring module. +

+
+ +
+ prefix +

+ --prefix +

+

+ Specifies whether to use the prefix. +

+
+ +
+ skip-import +

+ --skip-import +

+

+ Allows for skipping the module import. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
diff --git a/docs/documentation/1-x/generate/enum.md b/docs/documentation/1-x/generate/enum.md new file mode 100644 index 000000000000..c7b4b66ff19f --- /dev/null +++ b/docs/documentation/1-x/generate/enum.md @@ -0,0 +1,17 @@ + + +# ng generate enum + +## Overview +`ng generate enum [name]` generates an enumeration + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
diff --git a/docs/documentation/1-x/generate/guard.md b/docs/documentation/1-x/generate/guard.md new file mode 100644 index 000000000000..3435dd172f66 --- /dev/null +++ b/docs/documentation/1-x/generate/guard.md @@ -0,0 +1,45 @@ +# ng generate guard + +## Overview +`ng generate guard [name]` generates a guard + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ flat +

+ --flat +

+

+ Indicate if a dir is created. +

+
+ +
+ module +

+ --module (aliases: -m) +

+

+ Specifies where the guard should be provided. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
diff --git a/docs/documentation/1-x/generate/interface.md b/docs/documentation/1-x/generate/interface.md new file mode 100644 index 000000000000..8aa09de4ca76 --- /dev/null +++ b/docs/documentation/1-x/generate/interface.md @@ -0,0 +1,24 @@ + + +# ng generate interface + +## Overview +`ng generate interface [name] ` generates an interface + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ type +

+ Optional String to specify the type of interface. +

+
diff --git a/docs/documentation/1-x/generate/module.md b/docs/documentation/1-x/generate/module.md new file mode 100644 index 000000000000..55559f122406 --- /dev/null +++ b/docs/documentation/1-x/generate/module.md @@ -0,0 +1,59 @@ + + +# ng generate module + +## Overview +`ng generate module [name]` generates an NgModule + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ flat +

+ --flat +

+

+ Flag to indicate if a dir is created. +

+
+ +
+ module +

+ --module (aliases: -m) +

+

+ Specifies where the module should be imported. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
+ +
+ routing +

+ --routing +

+

+ Specifies if a routing module file should be generated. +

+
+ + diff --git a/docs/documentation/1-x/generate/pipe.md b/docs/documentation/1-x/generate/pipe.md new file mode 100644 index 000000000000..b8ee09497f3a --- /dev/null +++ b/docs/documentation/1-x/generate/pipe.md @@ -0,0 +1,67 @@ + + +# ng generate pipe + +## Overview +`ng generate pipe [name]` generates a pipe + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ export +

+ --export +

+

+ Specifies if declaring module exports the pipe. +

+
+ +
+ flat +

+ --flat +

+

+ Flag to indicate if a dir is created. +

+
+ +
+ module +

+ --module (aliases: -m) +

+

+ Allows specification of the declaring module. +

+
+ +
+ skip-import +

+ --skip-import +

+

+ Allows for skipping the module import. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
diff --git a/docs/documentation/1-x/generate/service.md b/docs/documentation/1-x/generate/service.md new file mode 100644 index 000000000000..eb94f5c5b9bc --- /dev/null +++ b/docs/documentation/1-x/generate/service.md @@ -0,0 +1,47 @@ + + +# ng generate service + +## Overview +`ng generate service [name]` generates a service + +## Options +
+ app +

+ --app (aliases: -a) default value: 1st app +

+

+ Specifies app name to use. +

+
+ +
+ flat +

+ --flat +

+

+ Flag to indicate if a dir is created. +

+
+ +
+ module +

+ --module (aliases: -m) +

+

+ Specifies where the service should be provided. +

+
+ +
+ spec +

+ --spec +

+

+ Specifies if a spec file is generated. +

+
diff --git a/docs/documentation/1-x/home.md b/docs/documentation/1-x/home.md new file mode 100644 index 000000000000..a03e9c185ecb --- /dev/null +++ b/docs/documentation/1-x/home.md @@ -0,0 +1,66 @@ + + +# Angular CLI + +NOTE: this documentation is for Angular CLI 1.x. For Angular CLI 6 go [here](home) instead. + +### Overview +The Angular CLI is a tool to initialize, develop, scaffold and maintain [Angular](https://angular.io) applications + +### Getting Started +To install the Angular CLI: +``` +npm install -g @angular/cli +``` + +Generating and serving an Angular project via a development server +[Create](1-x/new) and [run](1-x/serve) a new project: +``` +ng new my-project +cd my-project +ng serve +``` +Navigate to http://localhost:4200/. The app will automatically reload if you change any of the source files. + +### Bundling + +All builds make use of bundling, and using the `--prod` flag in `ng build --prod` +or `ng serve --prod` will also make use of uglifying and tree-shaking functionality. + +### Running unit tests + +```bash +ng test +``` + +Tests will execute after a build is executed via [Karma](http://karma-runner.github.io/0.13/index.html), and it will automatically watch your files for changes. You can run tests a single time via `--watch=false` or `--single-run`. + +### Running end-to-end tests + +```bash +ng e2e +``` + +Before running the tests make sure you are serving the app via `ng serve`. +End-to-end tests are run via [Protractor](http://www.protractortest.org/). + +### Additional Commands +* [ng new](1-x/new) +* [ng serve](1-x/serve) +* [ng generate](1-x/generate) +* [ng lint](1-x/lint) +* [ng test](1-x/test) +* [ng e2e](1-x/e2e) +* [ng build](1-x/build) +* [ng get/ng set](1-x/config) +* [ng doc](1-x/doc) +* [ng eject](1-x/eject) +* [ng xi18n](1-x/xi18n) +* [ng update](1-x/update) + +## Angular CLI Config Schema +* [Config Schema](1-x/angular-cli) + +### Additional Information +There are several [stories](1-x/stories) which will walk you through setting up +additional aspects of Angular applications. diff --git a/docs/documentation/1-x/lint.md b/docs/documentation/1-x/lint.md new file mode 100644 index 000000000000..46a005c8741e --- /dev/null +++ b/docs/documentation/1-x/lint.md @@ -0,0 +1,47 @@ + + +# ng lint + +## Overview +`ng lint` will lint you app code using tslint. + +## Options +
+ fix +

+ --fix default value: false +

+

+ Fixes linting errors (may overwrite linted files). +

+
+ +
+ force +

+ --force default value: false +

+

+ Succeeds even if there was linting errors. +

+
+ +
+ type-check +

+ --type-check default value: false +

+

+ Controls the type check for linting. +

+
+ +
+ format +

+ --format (aliases: -t) default value: prose +

+

+ Output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame). +

+
diff --git a/docs/documentation/1-x/new.md b/docs/documentation/1-x/new.md new file mode 100644 index 000000000000..2dedb230af07 --- /dev/null +++ b/docs/documentation/1-x/new.md @@ -0,0 +1,168 @@ + + +# ng new + +## Overview +`ng new [name]` creates a new angular application. + +Default applications are created in a directory of the same name, with an initialized Angular application. + +## Options +
+ directory +

+ --directory (alias: -d) default value: dir +

+

+ The directory name to create the app in. +

+
+ +
+ dry-run +

+ --dry-run (alias: -d) default value: false +

+

+ Run through without making any changes. Will list all files that would have been created when running ng new. +

+
+ +
+ inline-style +

+ --inline-style (alias: -s) default value: false +

+

+ Should have an inline style. +

+
+ +
+ inline-template +

+ --inline-template (alias: -t) default value: false +

+

+ Should have an inline template. +

+
+ +
+ minimal +

+ --minimal default value: false +

+

+ Should create a minimal app. +

+
+ +
+ prefix +

+ --prefix (alias: -p) default value: app +

+

+ The prefix to use for all component selectors. +

+

+ You can later change the value in .angular-cli.json (apps[0].prefix). +

+
+ +
+ routing +

+ --routing default value: false +

+

+ Generate a routing module. +

+
+ +
+ skip-commit +

+ --skip-commit (alias: -sc) default value: false +

+

+ Skip committing the first commit to git. +

+
+ +
+ skip-git +

+ --skip-git (alias: -g) default value: false +

+

+ Skip initializing a git repository. +

+
+ +
+ skip-install +

+ --skip-install (alias: -si) default value: false +

+

+ Skip installing packages. +

+
+ +
+ skip-tests +

+ --skip-tests (aliases: -S) default value: false +

+

+ Skip creating spec files. +

+

+ Skip including e2e functionality. +

+
+ +
+ source-dir +

+ --source-dir (alias: -D) default value: src +

+

+ The name of the source directory. +

+

+ You can later change the value in .angular-cli.json (apps[0].root). +

+
+ +
+ style +

+ --style default value: css +

+
+ The style file default extension. Possible values: +
    +
  • css
  • +
  • scss
  • +
  • less
  • +
  • sass
  • +
  • styl (stylus)
  • +
+
+

+ You can later change the value in .angular-cli.json (defaults.styleExt). +

+
+ +
+ verbose +

+ --verbose (alias: -v) default value: false +

+

+ Adds more details to output logging. +

+
diff --git a/docs/documentation/1-x/serve.md b/docs/documentation/1-x/serve.md new file mode 100644 index 000000000000..2a441a2dc59c --- /dev/null +++ b/docs/documentation/1-x/serve.md @@ -0,0 +1,316 @@ + + +# ng serve + +## Overview +`ng serve` builds the application and starts a web server. + +All the build Options are available in serve, below are the additional options. + +## Options +
+ host +

+ --host (aliases: -H) default value: localhost +

+

+ Listens only on localhost by default. +

+
+ +
+ hmr +

+ --hmr default value: false +

+

+ Enable hot module replacement. +

+
+ +
+ live-reload +

+ --live-reload (aliases: -lr) default value: true +

+

+ Whether to reload the page on change, using live-reload. +

+
+ +
+ public-host +

+ --public-host (aliases: --live-reload-client) +

+

+ Specify the URL that the browser client will use. +

+
+ +
+ disable-host-check +

+ --disable-host-check default value: false +

+

+ Don't verify connected clients are part of allowed hosts. +

+
+ +
+ open +

+ --open (aliases: -o) default value: false +

+

+ Opens the url in default browser. +

+
+ +
+ port +

+ --port (aliases: -p) default value: 4200 +

+

+ Port to listen to for serving. --port 0 will get a free port +

+
+ +
+ ssl +

+ --ssl +

+

+ Serve using HTTPS. +

+
+ +
+ ssl-cert +

+ --ssl-cert (aliases: -) default value: +

+

+ SSL certificate to use for serving HTTPS. +

+
+ +
+ ssl-key +

+ --ssl-key +

+

+ SSL key to use for serving HTTPS. +

+
+ +
+ aot +

+ --aot +

+

+ Build using Ahead of Time compilation. +

+
+ +
+ base-href +

+ --base-href (aliases: -bh) +

+

+ Base url for the application being built. +

+
+ +
+ deploy-url +

+ --deploy-url (aliases: -d) +

+

+ URL where files will be deployed. +

+
+ +
+ environment +

+ --environment (aliases: -e) +

+

+ Defines the build environment. +

+
+ +
+ extract-css +

+ --extract-css (aliases: -ec) +

+

+ Extract css from global styles onto css files instead of js ones. +

+
+ +
+ i18n-file +

+ --i18n-file +

+

+ Localization file to use for i18n. +

+
+ +
+ i18n-format +

+ --i18n-format +

+

+ Format of the localization file specified with --i18n-file. +

+
+ +
+ locale +

+ --locale +

+

+ Locale to use for i18n. +

+
+ +
+ missing-translation +

+ --missing-translation +

+

+ How to handle missing translations for i18n. +

+

+ Values: error, warning, ignore +

+
+ +
+ output-hashing +

+ --output-hashing (aliases: -oh) default value: +

+

+ Define the output filename cache-busting hashing mode. Possible values: none, all, media, bundles +

+
+ +
+ output-path +

+ --output-path (aliases: -op) default value: +

+

+ Path where output will be placed. +

+
+ +
+ poll +

+ --poll +

+

+ Enable and define the file watching poll time period (milliseconds) . +

+
+ +
+ progress +

+ --progress (aliases: -pr) default value: true inside TTY, false otherwise +

+

+ Log progress to the console while building. +

+
+ +
+ proxy-config +

+ --proxy-config (aliases: -pc) +

+

+ Use a proxy configuration file to send some requests to a backend server rather than the webpack dev server. +

+
+ +
+ sourcemap +

+ --sourcemap (aliases: -sm, sourcemaps) +

+

+ Output sourcemaps. +

+
+ +
+ target +

+ --target (aliases: -t, -dev, -prod) default value: development +

+

+ Defines the build target. +

+
+ +
+ vendor-chunk +

+ --vendor-chunk (aliases: -vc) default value: true +

+

+ Use a separate bundle containing only vendor libraries. +

+
+ +
+ common-chunk +

+ --common-chunk (aliases: -cc) default value: true +

+

+ Use a separate bundle containing code used across multiple bundles. +

+
+ +
+ verbose +

+ --verbose (aliases: -v) default value: false +

+

+ Adds more details to output logging. +

+
+ +
+ watch +

+ --watch (aliases: -w) +

+

+ Run build when files change. +

+
+ + +## Note +When running `ng serve`, the compiled output is served from memory, not from disk. This means that the application being served is not located on disk in the `dist` folder. diff --git a/docs/documentation/1-x/stories.md b/docs/documentation/1-x/stories.md new file mode 100644 index 000000000000..d602d59e328c --- /dev/null +++ b/docs/documentation/1-x/stories.md @@ -0,0 +1,34 @@ + + +# Stories describing how to do more with the CLI + + - [1.0 Update](1-x/stories/1.0-update) + - [Asset Configuration](1-x/stories/asset-configuration) + - [Autocompletion](1-x/stories/autocompletion) + - [Configure Hot Module Replacement](1-x/stories/configure-hmr) + - [CSS Preprocessors](1-x/stories/css-preprocessors) + - [Global Lib](1-x/stories/global-lib) + - [Global Scripts](1-x/stories/global-scripts) + - [Global Styles](1-x/stories/global-styles) + - [Angular Flex Layout](1-x/stories/include-angular-flex) + - [Angular Material](1-x/stories/include-angular-material) + - [AngularFire](1-x/stories/include-angularfire) + - [Bootstrap](1-x/stories/include-bootstrap) + - [Budgets](1-x/stories/budgets) + - [Font Awesome](1-x/stories/include-font-awesome) + - [Moving Into the CLI](1-x/stories/moving-into-the-cli) + - [Moving Out of the CLI](1-x/stories/moving-out-of-the-cli) + - [Proxy](1-x/stories/proxy) + - [Routing](1-x/stories/routing) + - [3rd Party Lib](1-x/stories/third-party-lib) + - [Corporate Proxy](1-x/stories/using-corporate-proxy) + - [Internationalization (i18n)](1-x/stories/internationalization) + - [Serve from Disk](1-x/stories/disk-serve) + - [Code Coverage](1-x/stories/code-coverage) + - [Application Environments](1-x/stories/application-environments) + - [Autoprefixer Configuration](1-x/stories/autoprefixer) + - [Deploy to GitHub Pages](1-x/stories/github-pages) + - [Linked Library](1-x/stories/linked-library) + - [Multiple apps](1-x/stories/multiple-apps) + - [Continuous Integration](1-x/stories/continuous-integration) + - [Universal Rendering](1-x/stories/universal-rendering) diff --git a/docs/documentation/stories/1.0-update.md b/docs/documentation/1-x/stories/1.0-update.md similarity index 97% rename from docs/documentation/stories/1.0-update.md rename to docs/documentation/1-x/stories/1.0-update.md index a9fc9d8d3f25..9a32e4555ab9 100644 --- a/docs/documentation/stories/1.0-update.md +++ b/docs/documentation/1-x/stories/1.0-update.md @@ -382,10 +382,10 @@ Packages in `devDependencies`: - `tslint` was updated to `~4.5.0` - `typescript` was updated to `~2.1.0` -See the [karma](#karma.conf.js) and [protractor](#protractor.conf.js) sections below for more +See the [karma](1-x/#karma.conf.js) and [protractor](1-x/#protractor.conf.js) sections below for more information on changed packages. -The [Linting rules](#Linting rules) section contains a list of rules that changed due to updates. +The [Linting rules](1-x/#Linting rules) section contains a list of rules that changed due to updates. We also updated the scripts section to make it more simple: @@ -466,7 +466,7 @@ const { SpecReporter } = require('jasmine-spec-reporter'); Remove `useAllAngular2AppRoots: true`. -Update `beforeLaunch` as described in [One tsconfig per app](#one-tsconfig-per-app): +Update `beforeLaunch` as described in [One tsconfig per app](1-x/#one-tsconfig-per-app): ``` beforeLaunch: function() { require('ts-node').register({ diff --git a/docs/documentation/1-x/stories/application-environments.md b/docs/documentation/1-x/stories/application-environments.md new file mode 100644 index 000000000000..d3c4b18d054c --- /dev/null +++ b/docs/documentation/1-x/stories/application-environments.md @@ -0,0 +1,122 @@ +# Application Environments + +## Configuring available environments + +`.angular-cli.json` contains an **environments** section. By default, this looks like: + +``` json +"environments": { + "dev": "environments/environment.ts", + "prod": "environments/environment.prod.ts" +} +``` + +You can add additional environments as required. To add a **staging** environment, your configuration would look like: + +``` json +"environments": { + "dev": "environments/environment.ts", + "staging": "environments/environment.staging.ts", + "prod": "environments/environment.prod.ts" +} +``` + +## Adding environment-specific files + +The environment-specific files are set out as shown below: + +``` +└── src + └── environments + ├── environment.prod.ts + └── environment.ts +``` + +If you wanted to add another environment for **staging**, your file structure would become: + +``` +└── src + └── environments + ├── environment.prod.ts + ├── environment.staging.ts + └── environment.ts +``` + +## Amending environment-specific files + +`environment.ts` contains the default settings. If you take a look at this file, it should look like: + +``` TypeScript +export const environment = { + production: false +}; +``` + +If you compare this to `environment.prod.ts`, which looks like: + +``` TypeScript +export const environment = { + production: true +}; +``` + +You can add further variables, either as additional properties on the `environment` object, or as separate objects, for example: + +``` TypeScript +export const environment = { + production: false, + apiUrl: 'http://my-api-url' +}; +``` + +## Using environment-specific variables in your application + +Given the following application structure: + +``` +└── src + └── app + ├── app.component.html + └── app.component.ts + └── environments + ├── environment.prod.ts + ├── environment.staging.ts + └── environment.ts +``` + +Using environment variables inside of `app.component.ts` might look something like this: + +``` TypeScript +import { Component } from '@angular/core'; +import { environment } from './../environments/environment'; + +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.css'] +}) +export class AppComponent { + constructor() { + console.log(environment.production); // Logs false for default environment + } + title = 'app works!'; +} +``` + +## Environment-specific builds + +Running: + +``` +ng build +``` + +Will use the defaults found in `environment.ts` + +Running: + +``` +ng build --env=staging +``` + +Will use the values from `environment.staging.ts` diff --git a/docs/documentation/1-x/stories/asset-configuration.md b/docs/documentation/1-x/stories/asset-configuration.md new file mode 100644 index 000000000000..ef910b1d8561 --- /dev/null +++ b/docs/documentation/1-x/stories/asset-configuration.md @@ -0,0 +1,62 @@ +# Project assets + +You use the `assets` array in `.angular-cli.json` to list files or folders you want to copy as-is +when building your project. + +By default, the `src/assets/` folder and `src/favicon.ico` are copied over. + +```json +"assets": [ + "assets", + "favicon.ico" +] +``` + +You can also further configure assets to be copied by using objects as configuration. + +The array below does the same as the default one: + +```json +"assets": [ + { "glob": "**/*", "input": "./assets/", "output": "./assets/" }, + { "glob": "favicon.ico", "input": "./", "output": "./" }, +] +``` + +`glob` is the a [node-glob](https://github.com/isaacs/node-glob) using `input` as base directory. +`input` is relative to the project root (`src/` default), while `output` is + relative to `outDir` (`dist` default). + + You can use this extended configuration to copy assets from outside your project. + For instance, you can copy assets from a node package: + + ```json +"assets": [ + { "glob": "**/*", "input": "../node_modules/some-package/images", "output": "./some-package/" }, +] +``` + +The contents of `node_modules/some-package/images/` will be available in `dist/some-package/`. + +## Writing assets outside of `dist/` + +Because of the security implications, the CLI will always refuse to read or write files outside of +the project itself (scoped by `.angular-cli.json`). It is however possible to write assets outside +the `dist/` build output folder during build. + +Because writing files in your project isn't an expected effect of `ng build`, it is disabled by +default on every assets. In order to allow this behaviour, you need to set `allowOutsideOutDir` +to `true` on your asset definition, like so: + +```json +"assets": [ + { + "glob": "**/*", + "input": "./assets/", + "output": "../not-dist/some/folder/", + "allowOutsideOutDir": true + }, +] +``` + +This needs to be set for every assets you want to write outside of your build output directory. diff --git a/docs/documentation/stories/autocompletion.md b/docs/documentation/1-x/stories/autocompletion.md similarity index 100% rename from docs/documentation/stories/autocompletion.md rename to docs/documentation/1-x/stories/autocompletion.md diff --git a/docs/documentation/1-x/stories/autoprefixer.md b/docs/documentation/1-x/stories/autoprefixer.md new file mode 100644 index 000000000000..c6902fccaf3b --- /dev/null +++ b/docs/documentation/1-x/stories/autoprefixer.md @@ -0,0 +1,43 @@ +# Change target browsers for Autoprefixer + +Currently, the CLI uses [Autoprefixer](https://github.com/postcss/autoprefixer) to ensure compatibility +with different browser and browser versions. You may find it necessary to target specific browsers +or exclude certain browser versions from your build. + +Internally, Autoprefixer relies on a library called [Browserslist](https://github.com/browserslist/browserslist) +to figure out which browsers to support with prefixing. + +There are a few ways to tell Autoprefixer what browsers to target: + +### Add a browserslist property to the `package.json` file +``` +"browserslist": [ + "> 1%", + "last 2 versions" +] +``` + +### Add a new file to the project directory called `.browserslistrc` +``` +### Supported Browsers + +> 1% +last 2 versions +``` + +Autoprefixer will look for the configuration file/property to use when it prefixes your css. +Check out the [browserslist repo](https://github.com/browserslist/browserslist) for more examples of how to target +specific browsers and versions. + +_Side note:_ +Those who are seeking to produce a [progressive web app](https://developers.google.com/web/progressive-web-apps/) and are using [Lighthouse](https://developers.google.com/web/tools/lighthouse/) to grade the project will +need to add the following browserslist config to their package.json file to eliminate the [old flexbox](https://developers.google.com/web/tools/lighthouse/audits/old-flexbox) prefixes: + +`package.json` config: +``` +"browserslist": [ + "last 2 versions", + "not ie <= 10", + "not ie_mob <= 10" +] +``` diff --git a/docs/documentation/1-x/stories/budgets.md b/docs/documentation/1-x/stories/budgets.md new file mode 100644 index 000000000000..e01364f9ce09 --- /dev/null +++ b/docs/documentation/1-x/stories/budgets.md @@ -0,0 +1,62 @@ +# Budgets + +As applications grow in functionality, they also grow in size. Budgets is a feature in the +Angular CLI which allows you to set budget thresholds in your configuration to ensure parts +of your application stay within boundries which you set. + +**.angular-cli.json** +``` +{ + ... + apps: [ + { + ... + budgets: [] + } + ] +} +``` + +## Budget Definition + +- type + - The type of budget. + - Possible values: + - bundle - The size of a specific bundle. + - initial - The initial size of the app. + - allScript - The size of all scripts. + - all - The size of the entire app. + - anyScript - The size of any one script. + - any - The size of any file. +- name + - The name of the bundle. + - Required only for type of "bundle" +- baseline + - The baseline size for comparison. +- maximumWarning + - The maximum threshold for warning relative to the baseline. +- maximumError + - The maximum threshold for error relative to the baseline. +- minimumWarning + - The minimum threshold for warning relative to the baseline. +- minimumError + - The minimum threshold for error relative to the baseline. +- warning + - The threshold for warning relative to the baseline (min & max). +- error + - The threshold for error relative to the baseline (min & max). + +## Specifying sizes + +Available formats: + +- `123` - size in bytes +- `123b` - size in bytes +- `123kb` - size in kilobytes +- `123mb` - size in megabytes +- `12%` - percentage + +## NOTES + +All sizes are relative to baseline. +Percentages are not valid for baseline values. diff --git a/docs/documentation/1-x/stories/code-coverage.md b/docs/documentation/1-x/stories/code-coverage.md new file mode 100644 index 000000000000..354063cc1242 --- /dev/null +++ b/docs/documentation/1-x/stories/code-coverage.md @@ -0,0 +1,32 @@ +# Code Coverage + +With the Angular CLI we can run unit tests as well as create code coverage reports. Code coverage reports allow us to see any parts of our code base that may not be properly tested by our unit tests. + +To generate a coverage report run the following command in the root of your project + +```bash +ng test --watch=false --code-coverage +``` + +Once the tests complete a new `/coverage` folder will appear in the project. In your Finder or Windows Explorer open the `index.html` file. You should see a report with your source code and code coverage values. + +Using the code coverage percentages we can estimate how much of our code is tested. It is up to your team to determine how much code should be unit tested. + +## Code Coverage Enforcement + +If your team decides on a set minimum amount to be unit tested you can enforce this minimum with the Angular CLI. For example our team would like the code base to have a minimum of 80% code coverage. To enable this open the `karma.conf.js` and add the following in the `coverageIstanbulReporter:` key + +```javascript +coverageIstanbulReporter: { + reports: [ 'html', 'lcovonly' ], + fixWebpackSourcePaths: true, + thresholds: { + statements: 80, + lines: 80, + branches: 80, + functions: 80 + } +} +``` + +The `thresholds` property will enforce a minimum of 80% code coverage when the unit tests are run in the project. \ No newline at end of file diff --git a/docs/documentation/1-x/stories/configure-hmr.md b/docs/documentation/1-x/stories/configure-hmr.md new file mode 100644 index 000000000000..1823e8f1ba79 --- /dev/null +++ b/docs/documentation/1-x/stories/configure-hmr.md @@ -0,0 +1,150 @@ +# Configure Hot Module Replacement + +Hot Module Replacement (HMR) is a WebPack feature to update code in a running app without rebuilding it. +This results in faster updates and less full page-reloads. + +You can read more about HMR by visiting [this page](https://webpack.js.org/guides/hot-module-replacement/). + +In order to get HMR working with Angular CLI we first need to add a new environment and enable it. + +Next we need to update the bootstrap process of our app to enable the +[@angularclass/hmr](https://github.com/gdi2290/angular-hmr) module. + +### Add environment for HMR + +Create a file called `src/environments/environment.hmr.ts` with the following contents: + +```typescript + +export const environment = { + production: false, + hmr: true +}; +``` + +Update `src/environments/environment.prod.ts` and add the `hmr: false` flag to the environment: + +```typescript +export const environment = { + production: true, + hmr: false +}; +``` + +Update `src/environments/environment.ts` and add the `hmr: false` flag to the environment: + +```typescript +export const environment = { + production: false, + hmr: false +}; +``` + + +Update `.angular-cli.json` by adding the new environment the existing environments object: + +```json +"environmentSource": "environments/environment.ts", +"environments": { + "dev": "environments/environment.ts", + "hmr": "environments/environment.hmr.ts", + "prod": "environments/environment.prod.ts" +}, +``` + +Run `ng serve` with the flag `--hmr -e=hmr` to enable hmr and select the new environment: + +```bash +ng serve --hmr -e=hmr +``` + +Create a shortcut for this by updating `package.json` and adding an entry to the script object: + +```json +"scripts": { + ... + "hmr": "ng serve --hmr -e=hmr" +} +``` + + +### Add dependency for @angularclass/hmr and configure app + +In order to get HMR working we need to install the dependency and configure our app to use it. + + +Install the `@angularclass/hmr` module as a dev-dependency + +```bash +$ npm install --save-dev @angularclass/hmr +``` + + +Create a file called `src/hmr.ts` with the following content: + +```typescript +import { NgModuleRef, ApplicationRef } from '@angular/core'; +import { createNewHosts } from '@angularclass/hmr'; + +export const hmrBootstrap = (module: any, bootstrap: () => Promise>) => { + let ngModule: NgModuleRef; + module.hot.accept(); + bootstrap().then(mod => ngModule = mod); + module.hot.dispose(() => { + const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); + const elements = appRef.components.map(c => c.location.nativeElement); + const makeVisible = createNewHosts(elements); + ngModule.destroy(); + makeVisible(); + }); +}; +``` + + +Update `src/main.ts` to use the file we just created: + +```typescript +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/app.module'; +import { environment } from './environments/environment'; + +import { hmrBootstrap } from './hmr'; + +if (environment.production) { + enableProdMode(); +} + +const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule); + +if (environment.hmr) { + if (module[ 'hot' ]) { + hmrBootstrap(module, bootstrap); + } else { + console.error('HMR is not enabled for webpack-dev-server!'); + console.log('Are you using the --hmr flag for ng serve?'); + } +} else { + bootstrap(); +} +``` + + +### Starting the development environment with HMR enabled + +Now that everything is set up we can run the new configuration: + +```bash +$ npm run hmr +``` + +When starting the server Webpack will tell you that it’s enabled: + + + NOTICE Hot Module Replacement (HMR) is enabled for the dev server. + + +Now if you make changes to one of your components they changes should be visible automatically without a complete browser refresh. + + diff --git a/docs/documentation/1-x/stories/continuous-integration.md b/docs/documentation/1-x/stories/continuous-integration.md new file mode 100644 index 000000000000..7c079084114b --- /dev/null +++ b/docs/documentation/1-x/stories/continuous-integration.md @@ -0,0 +1,155 @@ +# Continuous Integration + +One of the best ways to keep your project bug free is through a test suite, but it's easy to forget +to run tests all the time. + +That's where Continuous Integration (CI) servers come in. +You can set up your project repository so that your tests run on every commit and pull request. + +There are paid CI services like [Circle CI](https://circleci.com/) and +[Travis CI](https://travis-ci.com/), and you can also host your own for free using +[Jenkins](https://jenkins.io/) and others. + +Even though Circle CI and Travis CI are paid services, they are provided free for open source +projects. +You can create a public project on GitHub and add these services without paying. + +We're going to see how to update your test configuration to run in CI environments, and how to +set up Circle CI and Travis CI. + + +## Update test configuration + +Even though `ng test` and `ng e2e` already run on your environment, they need to be adjusted to +run in CI environments. + +When using Chrome in CI environments it has to be started without sandboxing. +We can achieve that by editing our test configs. + +In `karma.conf.js`, add a custom launcher called `ChromeNoSandbox` below `browsers`: + +``` +browsers: ['Chrome'], +customLaunchers: { + ChromeNoSandbox: { + base: 'Chrome', + flags: ['--no-sandbox'] + } +}, +``` + +Create a new file in the root of your project called `protractor-ci.conf.js`, that extends +the original `protractor.conf.js`: + +``` +const config = require('./protractor.conf').config; + +config.capabilities = { + browserName: 'chrome', + chromeOptions: { + args: ['--no-sandbox'] + } +}; + +exports.config = config; +``` + +Now you can run the following commands to use the `--no-sandbox` flag: + +``` +ng test --single-run --no-progress --browser=ChromeNoSandbox +ng e2e --no-progress --config=protractor-ci.conf.js +``` + +For CI environments it's also a good idea to disable progress reporting (via `--no-progress`) +to avoid spamming the server log with progress messages. + + +## Using Circle CI + +Create a folder called `.circleci` at the project root, and inside of it create a file called +`config.yml`: + +```yaml +version: 2 +jobs: + build: + working_directory: ~/my-project + docker: + - image: circleci/node:8-browsers + steps: + - checkout + - restore_cache: + key: my-project-{{ .Branch }}-{{ checksum "package.json" }} + - run: npm install + - save_cache: + key: my-project-{{ .Branch }}-{{ checksum "package.json" }} + paths: + - "node_modules" + - run: xvfb-run -a npm run test -- --single-run --no-progress --browser=ChromeNoSandbox + - run: xvfb-run -a npm run e2e -- --no-progress --config=protractor-ci.conf.js + +``` + +We're doing a few things here: + - + - `node_modules` is cached. + - [npm run](https://docs.npmjs.com/cli/run-script) is used to run `ng` because `@angular/cli` is + not installed globally. The double dash (`--`) is needed to pass arguments into the npm script. + - `xvfb-run` is used to run `npm run` to run a command using a virtual screen, which is needed by + Chrome. + +Commit your changes and push them to your repository. + +Next you'll need to [sign up for Circle CI](https://circleci.com/docs/2.0/first-steps/) and +[add your project](https://circleci.com/add-projects). +Your project should start building. + +Be sure to check out the [Circle CI docs](https://circleci.com/docs/2.0/) if you want to know more. + + +## Using Travis CI + +Create a file called `.travis.yml` at the project root: + +```yaml +dist: trusty +sudo: false + +language: node_js +node_js: + - "8" + +addons: + apt: + sources: + - google-chrome + packages: + - google-chrome-stable + +cache: + directories: + - ./node_modules + +install: + - npm install + +script: + # Use Chromium instead of Chrome. + - export CHROME_BIN=chromium-browser + - xvfb-run -a npm run test -- --single-run --no-progress --browser=ChromeNoSandbox + - xvfb-run -a npm run e2e -- --no-progress --config=protractor-ci.conf.js + +``` + +Although the syntax is different, we're mostly doing the same steps as were done in the +Circle CI config. +The only difference is that Travis doesn't come with Chrome, so we use Chromium instead. + +Commit your changes and push them to your repository. + +Next you'll need to [sign up for Travis CI](https://travis-ci.org/auth) and +[add your project](https://travis-ci.org/profile). +You'll need to push a new commit to trigger a build. + +Be sure to check out the [Travis CI docs](https://docs.travis-ci.com/) if you want to know more. diff --git a/docs/documentation/1-x/stories/css-preprocessors.md b/docs/documentation/1-x/stories/css-preprocessors.md new file mode 100644 index 000000000000..58bd0071deab --- /dev/null +++ b/docs/documentation/1-x/stories/css-preprocessors.md @@ -0,0 +1,34 @@ +# CSS Preprocessor integration + +Angular CLI supports all major CSS preprocessors: +- sass/scss ([http://sass-lang.com/](http://sass-lang.com/)) +- less ([http://lesscss.org/](http://lesscss.org/)) +- stylus ([http://stylus-lang.com/](http://stylus-lang.com/)) + +To use these preprocessors simply add the file to your component's `styleUrls`: + +```javascript +@Component({ + selector: 'app-root', + templateUrl: './app.component.html', + styleUrls: ['./app.component.scss'] +}) +export class AppComponent { + title = 'app works!'; +} +``` + +When generating a new project you can also define which extension you want for +style files: + +```bash +ng new sassy-project --style=sass +``` + +Or set the default style on an existing project: + +```bash +ng set defaults.styleExt scss +``` + +Style strings added to the `@Component.styles` array _must be written in CSS_ because the CLI cannot apply a pre-processor to inline styles. \ No newline at end of file diff --git a/docs/documentation/1-x/stories/disk-serve.md b/docs/documentation/1-x/stories/disk-serve.md new file mode 100644 index 000000000000..b3f4663b630b --- /dev/null +++ b/docs/documentation/1-x/stories/disk-serve.md @@ -0,0 +1,23 @@ +# Serve from Disk + +The CLI supports running a live browser reload experience to users by running `ng serve`. This will compile the application upon file saves and reload the browser with the newly compiled application. This is done by hosting the application in memory and serving it via [webpack-dev-server](https://webpack.js.org/guides/development/#webpack-dev-server). + +If you wish to get a similar experience with the application output to disk please use the steps below. This practice will allow you to ensure that serving the contents of your `dist` dir will be closer to how your application will behave when it is deployed. + +## Environment Setup +### Install a web server +You will not be using webpack-dev-server, so you will need to install a web server for the browser to request the application. There are many to choose from but a good one to try is [lite-server](https://github.com/johnpapa/lite-server) as it will auto-reload your browser when new files are output. + +## Usage +You will need two terminals to get the live-reload experience. The first will run the build in a watch mode to compile the application to the `dist` folder. The second will run the web server against the `dist` folder. The combination of these two processes will mimic the same behavior of ng serve. + +### 1st terminal - Start the build +```bash +ng build --watch +``` + +### 2nd terminal - Start the web server +```bash +lite-server --baseDir="dist" +``` +When using `lite-server` the default browser will open to the appropriate URL. diff --git a/docs/documentation/1-x/stories/github-pages.md b/docs/documentation/1-x/stories/github-pages.md new file mode 100644 index 000000000000..2bb0d0f28f7f --- /dev/null +++ b/docs/documentation/1-x/stories/github-pages.md @@ -0,0 +1,21 @@ +# Deploy to GitHub Pages + +A simple way to deploy your Angular app is to use +[GitHub Pages](https://help.github.com/articles/what-is-github-pages/). + +The first step is to [create a GitHub account](https://github.com/join), and then +[create a repository](https://help.github.com/articles/create-a-repo/) for your project. +Make a note of the user name and project name in GitHub. + +Then all you need to do is run `ng build --prod --output-path docs --base-href PROJECT_NAME`, where +`PROJECT_NAME` is the name of your project in GitHub. +Make a copy of `docs/index.html` and name it `docs/404.html`. + +Commit your changes and push. On the GitHub project page, configure it to +[publish from the docs folder](https://help.github.com/articles/configuring-a-publishing-source-for-github-pages/#publishing-your-github-pages-site-from-a-docs-folder-on-your-master-branch). + +And that's all you need to do! Now you can see your page at +`https://USER_NAME.github.io/PROJECT_NAME/`. + +You can also use [angular-cli-ghpages](https://github.com/angular-schule/angular-cli-ghpages), a full +featured package that does this all this for you and has extra functionality. diff --git a/docs/documentation/1-x/stories/global-lib.md b/docs/documentation/1-x/stories/global-lib.md new file mode 100644 index 000000000000..91c621acfd5c --- /dev/null +++ b/docs/documentation/1-x/stories/global-lib.md @@ -0,0 +1,37 @@ +# Global Library Installation + +Some javascript libraries need to be added to the global scope, and loaded as if +they were in a script tag. We can do this using the `apps[0].scripts` and +`apps[0].styles` properties of `.angular-cli.json`. + +As an example, to use [Bootstrap 4](https://getbootstrap.com/docs/4.0/getting-started/introduction/) this is +what you need to do: + +First install Bootstrap from `npm`: + +```bash +npm install jquery --save +npm install popper.js --save +npm install bootstrap@next --save +``` + +Then add the needed script files to `apps[0].scripts`: + +```json +"scripts": [ + "../node_modules/jquery/dist/jquery.slim.js", + "../node_modules/popper.js/dist/umd/popper.js", + "../node_modules/bootstrap/dist/js/bootstrap.js" +], +``` + +Finally add the Bootstrap CSS to the `apps[0].styles` array: +```json +"styles": [ + "../node_modules/bootstrap/dist/css/bootstrap.css", + "styles.css" +], +``` + +Restart `ng serve` if you're running it, and Bootstrap 4 should be working on +your app. diff --git a/docs/documentation/1-x/stories/global-scripts.md b/docs/documentation/1-x/stories/global-scripts.md new file mode 100644 index 000000000000..fe12d7473e03 --- /dev/null +++ b/docs/documentation/1-x/stories/global-scripts.md @@ -0,0 +1,56 @@ +# Global scripts + +You can add Javascript files to the global scope via the `apps[0].scripts` +property in `.angular-cli.json`. +These will be loaded exactly as if you had added them in a ` + + diff --git a/etc/cli.angular.io/license.html b/etc/cli.angular.io/license.html new file mode 100644 index 000000000000..0131cc303c40 --- /dev/null +++ b/etc/cli.angular.io/license.html @@ -0,0 +1,23 @@ +
The MIT License
+
+Copyright (c) Google, Inc. All Rights Reserved.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+ diff --git a/etc/cli.angular.io/main.css b/etc/cli.angular.io/main.css new file mode 100644 index 000000000000..61b0cb066543 --- /dev/null +++ b/etc/cli.angular.io/main.css @@ -0,0 +1 @@ +body{font-family:"Roboto",Helvetica,sans-serif}h4,h5{font-size:30px;font-weight:400;line-height:40px;margin-bottom:15px;margin-top:15px}h5{font-size:16px;font-weight:300;line-height:28px;margin-bottom:25px;max-width:300px}.mdl-demo section.section--center{max-width:920px}.mdl-grid--no-spacing>.mdl-cell{width:100%}.mdl-layout--fixed-drawer>.mdl-layout__content{margin-left:0}.mdl-layout__header{background-color:#f44336;box-shadow:0 2px 5px 0 rgba(0,0,0,.26)}.mdl-layout__header a{color:#fff;text-decoration:none}.mdl-layout--fixed-drawer.is-upgraded:not(.is-small-screen)>.mdl-layout__header{margin-left:0;width:100%}.mdl-layout--fixed-drawer>.mdl-layout__header .mdl-layout__header-row{padding-left:25px;padding-right:0}.mdl-layout__drawer-button,.top-nav-wrapper label{display:none}@media (max-width:1024px){.mdl-layout__drawer-button{display:inline-block}}.mdl-layout__drawer{margin-top:65px;height:calc(100% - 65px)}@media (max-width:1024px){.mdl-layout__drawer{margin-top:0;height:100%}}.mdl-layout-title,.mdl-layout__title{font-size:16px;line-height:28px;letter-spacing:.02em}.microsite-name{display:inline-block;font-size:20px;margin-left:8px;margin-right:30px;text-transform:uppercase;-webkit-transform:translateY(3px);transform:translateY(3px)}.mdl-navigation__link{font-size:16px;text-transform:uppercase;text-decoration:none}.mdl-navigation__link:hover,.top-nav-wrapper label:hover{background-color:#d32f2f}.top-nav-wrapper{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}@media (max-width:800px){.top-nav-wrapper{display:block;position:absolute;right:0;top:0;width:100%}.top-nav-wrapper label{cursor:pointer;display:block;float:right;line-height:56px;padding:0 16px}.top-nav-wrapper nav{background:#d32f2f;clear:both;display:none;height:auto!important}.top-nav-wrapper nav a{display:block}.top-nav-wrapper .mdl-layout-spacer{display:none}input:checked+.top-nav-wrapper label{background:#d32f2f}input:checked+.top-nav-wrapper nav{display:block}}.hero-background{background:-webkit-linear-gradient(#d32f2f ,#f44336);background:linear-gradient(#d32f2f ,#f44336);color:#fff;margin-bottom:60px}.mdl-grid,.mdl-mega-footer--bottom-section .mdl-cell--9-col{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.hero-container{padding:56px 0!important}@media (max-width:830px){.hero-container{text-align:center}}.logo-container{overflow:hidden;text-align:center}@media (max-width:840px){.tagline{max-width:100%}}.mdl-button{height:45px;line-height:45px;min-width:140px;padding:0 30px}.mdl-button--primary.mdl-button--primary.mdl-button--fab,.mdl-button--primary.mdl-button--primary.mdl-button--raised{background-color:#fff;color:#b71c1c}.features-list{width:920px;margin:0 0 23px;padding:15px 200px 15px 15px}@media (max-width:840px){.features-list{padding-right:15px}}.features-list h4{color:#37474f;font-size:28px;font-weight:500;line-height:32px;margin:0 0 16px;opacity:.87}.features-list p,footer ul a{font-size:16px;line-height:30px;opacity:.87}.button-container{margin-bottom:24px!important;text-align:center}.mdl-button--accent.mdl-button--accent.mdl-button--fab,.mdl-button--accent.mdl-button--accent.mdl-button--raised{background-color:#f44336;color:#fff}.mdl-mega-footer--bottom-section .mdl-cell--9-col{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end;display:-webkit-box;display:-ms-flexbox;display:flex}.mdl-mega-footer--bottom-section,.mdl-mega-footer__bottom-section{background-color:#263238;bottom:0;color:#fff;padding-top:0;right:0}footer ul{font-size:14px;font-weight:400;letter-spacing:0;line-height:24px;list-style:none;padding:0}footer ul a{color:#fff;line-height:28px;padding:0;text-decoration:none}footer ul a:hover{text-decoration:underline}@media (max-width:830px){footer ul{background-color:rgba(0,0,0,.12);padding:8px;text-align:center}}.mdl-mega-footer--bottom-section{margin-bottom:0}.mdl-mega-footer--bottom-section p{font-size:12px;margin:0;opacity:.54}.mdl-mega-footer--bottom-section a{color:#fff;font-weight:400;padding:0;text-decoration:none}.power-text{text-align:right}@media (max-width:830px){.power-text{text-align:center;width:calc(100% - 16px)}}.mdl-base{height:100vh} diff --git a/etc/cli.angular.io/material.min.css b/etc/cli.angular.io/material.min.css new file mode 100644 index 000000000000..e750f8137205 --- /dev/null +++ b/etc/cli.angular.io/material.min.css @@ -0,0 +1,9 @@ +/** + * material-design-lite - Material Design Components in CSS, JS and HTML + * @version v1.1.3 + * @license Apache-2.0 + * @copyright 2015 Google, Inc. + * @link https://github.com/google/material-design-lite + */ +@charset "UTF-8";html{color:rgba(0,0,0,.87)}::-moz-selection{background:#b3d4fc;text-shadow:none}::selection{background:#b3d4fc;text-shadow:none}hr{display:block;height:1px;border:0;border-top:1px solid #ccc;margin:1em 0;padding:0}audio,canvas,iframe,img,svg,video{vertical-align:middle}fieldset{border:0;margin:0;padding:0}textarea{resize:vertical}.browserupgrade{margin:.2em 0;background:#ccc;color:#000;padding:.2em 0}.hidden{display:none!important}.visuallyhidden{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.visuallyhidden.focusable:active,.visuallyhidden.focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}.invisible{visibility:hidden}.clearfix:before,.clearfix:after{content:" ";display:table}.clearfix:after{clear:both}@media print{*,*:before,*:after,*:first-letter{background:transparent!important;color:#000!important;box-shadow:none!important}a,a:visited{text-decoration:underline}a[href]:after{content:" (" attr(href)")"}abbr[title]:after{content:" (" attr(title)")"}a[href^="#"]:after,a[href^="javascript:"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100%!important}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}a,.mdl-accordion,.mdl-button,.mdl-card,.mdl-checkbox,.mdl-dropdown-menu,.mdl-icon-toggle,.mdl-item,.mdl-radio,.mdl-slider,.mdl-switch,.mdl-tabs__tab{-webkit-tap-highlight-color:transparent;-webkit-tap-highlight-color:rgba(255,255,255,0)}html{width:100%;height:100%;-ms-touch-action:manipulation;touch-action:manipulation}body{width:100%;min-height:100%;margin:0}main{display:block}*[hidden]{display:none!important}html,body{font-family:"Helvetica","Arial",sans-serif;font-size:14px;font-weight:400;line-height:20px}h1,h2,h3,h4,h5,h6,p{padding:0}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-family:"Roboto","Helvetica","Arial",sans-serif;font-weight:400;line-height:1.35;letter-spacing:-.02em;opacity:.54;font-size:.6em}h1{font-size:56px;line-height:1.35;letter-spacing:-.02em;margin:24px 0}h1,h2{font-family:"Roboto","Helvetica","Arial",sans-serif;font-weight:400}h2{font-size:45px;line-height:48px}h2,h3{margin:24px 0}h3{font-size:34px;line-height:40px}h3,h4{font-family:"Roboto","Helvetica","Arial",sans-serif;font-weight:400}h4{font-size:24px;line-height:32px;-moz-osx-font-smoothing:grayscale;margin:24px 0 16px}h5{font-size:20px;font-weight:500;line-height:1;letter-spacing:.02em}h5,h6{font-family:"Roboto","Helvetica","Arial",sans-serif;margin:24px 0 16px}h6{font-size:16px;letter-spacing:.04em}h6,p{font-weight:400;line-height:24px}p{font-size:14px;letter-spacing:0;margin:0 0 16px}a{color:#ff4081;font-weight:500}blockquote{font-family:"Roboto","Helvetica","Arial",sans-serif;position:relative;font-size:24px;font-weight:300;font-style:italic;line-height:1.35;letter-spacing:.08em}blockquote:before{position:absolute;left:-.5em;content:'“'}blockquote:after{content:'â€';margin-left:-.05em}mark{background-color:#f4ff81}dt{font-weight:700}address{font-size:12px;line-height:1;font-style:normal}address,ul,ol{font-weight:400;letter-spacing:0}ul,ol{font-size:14px;line-height:24px}.mdl-typography--display-4,.mdl-typography--display-4-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:112px;font-weight:300;line-height:1;letter-spacing:-.04em}.mdl-typography--display-4-color-contrast{opacity:.54}.mdl-typography--display-3,.mdl-typography--display-3-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:56px;font-weight:400;line-height:1.35;letter-spacing:-.02em}.mdl-typography--display-3-color-contrast{opacity:.54}.mdl-typography--display-2,.mdl-typography--display-2-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:45px;font-weight:400;line-height:48px}.mdl-typography--display-2-color-contrast{opacity:.54}.mdl-typography--display-1,.mdl-typography--display-1-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:34px;font-weight:400;line-height:40px}.mdl-typography--display-1-color-contrast{opacity:.54}.mdl-typography--headline,.mdl-typography--headline-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:24px;font-weight:400;line-height:32px;-moz-osx-font-smoothing:grayscale}.mdl-typography--headline-color-contrast{opacity:.87}.mdl-typography--title,.mdl-typography--title-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:20px;font-weight:500;line-height:1;letter-spacing:.02em}.mdl-typography--title-color-contrast{opacity:.87}.mdl-typography--subhead,.mdl-typography--subhead-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:16px;font-weight:400;line-height:24px;letter-spacing:.04em}.mdl-typography--subhead-color-contrast{opacity:.87}.mdl-typography--body-2,.mdl-typography--body-2-color-contrast{font-size:14px;font-weight:700;line-height:24px;letter-spacing:0}.mdl-typography--body-2-color-contrast{opacity:.87}.mdl-typography--body-1,.mdl-typography--body-1-color-contrast{font-size:14px;font-weight:400;line-height:24px;letter-spacing:0}.mdl-typography--body-1-color-contrast{opacity:.87}.mdl-typography--body-2-force-preferred-font,.mdl-typography--body-2-force-preferred-font-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:14px;font-weight:500;line-height:24px;letter-spacing:0}.mdl-typography--body-2-force-preferred-font-color-contrast{opacity:.87}.mdl-typography--body-1-force-preferred-font,.mdl-typography--body-1-force-preferred-font-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:14px;font-weight:400;line-height:24px;letter-spacing:0}.mdl-typography--body-1-force-preferred-font-color-contrast{opacity:.87}.mdl-typography--caption,.mdl-typography--caption-force-preferred-font{font-size:12px;font-weight:400;line-height:1;letter-spacing:0}.mdl-typography--caption-force-preferred-font{font-family:"Roboto","Helvetica","Arial",sans-serif}.mdl-typography--caption-color-contrast,.mdl-typography--caption-force-preferred-font-color-contrast{font-size:12px;font-weight:400;line-height:1;letter-spacing:0;opacity:.54}.mdl-typography--caption-force-preferred-font-color-contrast,.mdl-typography--menu{font-family:"Roboto","Helvetica","Arial",sans-serif}.mdl-typography--menu{font-size:14px;font-weight:500;line-height:1;letter-spacing:0}.mdl-typography--menu-color-contrast{opacity:.87}.mdl-typography--menu-color-contrast,.mdl-typography--button,.mdl-typography--button-color-contrast{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:14px;font-weight:500;line-height:1;letter-spacing:0}.mdl-typography--button,.mdl-typography--button-color-contrast{text-transform:uppercase}.mdl-typography--button-color-contrast{opacity:.87}.mdl-typography--text-left{text-align:left}.mdl-typography--text-right{text-align:right}.mdl-typography--text-center{text-align:center}.mdl-typography--text-justify{text-align:justify}.mdl-typography--text-nowrap{white-space:nowrap}.mdl-typography--text-lowercase{text-transform:lowercase}.mdl-typography--text-uppercase{text-transform:uppercase}.mdl-typography--text-capitalize{text-transform:capitalize}.mdl-typography--font-thin{font-weight:200!important}.mdl-typography--font-light{font-weight:300!important}.mdl-typography--font-regular{font-weight:400!important}.mdl-typography--font-medium{font-weight:500!important}.mdl-typography--font-bold{font-weight:700!important}.mdl-typography--font-black{font-weight:900!important}.material-icons{font-family:'Material Icons';font-weight:400;font-style:normal;font-size:24px;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;word-wrap:normal;-moz-font-feature-settings:'liga';font-feature-settings:'liga';-webkit-font-feature-settings:'liga';-webkit-font-smoothing:antialiased}.mdl-color-text--red{color:#f44336 !important}.mdl-color--red{background-color:#f44336 !important}.mdl-color-text--red-50{color:#ffebee !important}.mdl-color--red-50{background-color:#ffebee !important}.mdl-color-text--red-100{color:#ffcdd2 !important}.mdl-color--red-100{background-color:#ffcdd2 !important}.mdl-color-text--red-200{color:#ef9a9a !important}.mdl-color--red-200{background-color:#ef9a9a !important}.mdl-color-text--red-300{color:#e57373 !important}.mdl-color--red-300{background-color:#e57373 !important}.mdl-color-text--red-400{color:#ef5350 !important}.mdl-color--red-400{background-color:#ef5350 !important}.mdl-color-text--red-500{color:#f44336 !important}.mdl-color--red-500{background-color:#f44336 !important}.mdl-color-text--red-600{color:#e53935 !important}.mdl-color--red-600{background-color:#e53935 !important}.mdl-color-text--red-700{color:#d32f2f !important}.mdl-color--red-700{background-color:#d32f2f !important}.mdl-color-text--red-800{color:#c62828 !important}.mdl-color--red-800{background-color:#c62828 !important}.mdl-color-text--red-900{color:#b71c1c !important}.mdl-color--red-900{background-color:#b71c1c !important}.mdl-color-text--red-A100{color:#ff8a80 !important}.mdl-color--red-A100{background-color:#ff8a80 !important}.mdl-color-text--red-A200{color:#ff5252 !important}.mdl-color--red-A200{background-color:#ff5252 !important}.mdl-color-text--red-A400{color:#ff1744 !important}.mdl-color--red-A400{background-color:#ff1744 !important}.mdl-color-text--red-A700{color:#d50000 !important}.mdl-color--red-A700{background-color:#d50000 !important}.mdl-color-text--pink{color:#e91e63 !important}.mdl-color--pink{background-color:#e91e63 !important}.mdl-color-text--pink-50{color:#fce4ec !important}.mdl-color--pink-50{background-color:#fce4ec !important}.mdl-color-text--pink-100{color:#f8bbd0 !important}.mdl-color--pink-100{background-color:#f8bbd0 !important}.mdl-color-text--pink-200{color:#f48fb1 !important}.mdl-color--pink-200{background-color:#f48fb1 !important}.mdl-color-text--pink-300{color:#f06292 !important}.mdl-color--pink-300{background-color:#f06292 !important}.mdl-color-text--pink-400{color:#ec407a !important}.mdl-color--pink-400{background-color:#ec407a !important}.mdl-color-text--pink-500{color:#e91e63 !important}.mdl-color--pink-500{background-color:#e91e63 !important}.mdl-color-text--pink-600{color:#d81b60 !important}.mdl-color--pink-600{background-color:#d81b60 !important}.mdl-color-text--pink-700{color:#c2185b !important}.mdl-color--pink-700{background-color:#c2185b !important}.mdl-color-text--pink-800{color:#ad1457 !important}.mdl-color--pink-800{background-color:#ad1457 !important}.mdl-color-text--pink-900{color:#880e4f !important}.mdl-color--pink-900{background-color:#880e4f !important}.mdl-color-text--pink-A100{color:#ff80ab !important}.mdl-color--pink-A100{background-color:#ff80ab !important}.mdl-color-text--pink-A200{color:#ff4081 !important}.mdl-color--pink-A200{background-color:#ff4081 !important}.mdl-color-text--pink-A400{color:#f50057 !important}.mdl-color--pink-A400{background-color:#f50057 !important}.mdl-color-text--pink-A700{color:#c51162 !important}.mdl-color--pink-A700{background-color:#c51162 !important}.mdl-color-text--purple{color:#9c27b0 !important}.mdl-color--purple{background-color:#9c27b0 !important}.mdl-color-text--purple-50{color:#f3e5f5 !important}.mdl-color--purple-50{background-color:#f3e5f5 !important}.mdl-color-text--purple-100{color:#e1bee7 !important}.mdl-color--purple-100{background-color:#e1bee7 !important}.mdl-color-text--purple-200{color:#ce93d8 !important}.mdl-color--purple-200{background-color:#ce93d8 !important}.mdl-color-text--purple-300{color:#ba68c8 !important}.mdl-color--purple-300{background-color:#ba68c8 !important}.mdl-color-text--purple-400{color:#ab47bc !important}.mdl-color--purple-400{background-color:#ab47bc !important}.mdl-color-text--purple-500{color:#9c27b0 !important}.mdl-color--purple-500{background-color:#9c27b0 !important}.mdl-color-text--purple-600{color:#8e24aa !important}.mdl-color--purple-600{background-color:#8e24aa !important}.mdl-color-text--purple-700{color:#7b1fa2 !important}.mdl-color--purple-700{background-color:#7b1fa2 !important}.mdl-color-text--purple-800{color:#6a1b9a !important}.mdl-color--purple-800{background-color:#6a1b9a !important}.mdl-color-text--purple-900{color:#4a148c !important}.mdl-color--purple-900{background-color:#4a148c !important}.mdl-color-text--purple-A100{color:#ea80fc !important}.mdl-color--purple-A100{background-color:#ea80fc !important}.mdl-color-text--purple-A200{color:#e040fb !important}.mdl-color--purple-A200{background-color:#e040fb !important}.mdl-color-text--purple-A400{color:#d500f9 !important}.mdl-color--purple-A400{background-color:#d500f9 !important}.mdl-color-text--purple-A700{color:#a0f !important}.mdl-color--purple-A700{background-color:#a0f !important}.mdl-color-text--deep-purple{color:#673ab7 !important}.mdl-color--deep-purple{background-color:#673ab7 !important}.mdl-color-text--deep-purple-50{color:#ede7f6 !important}.mdl-color--deep-purple-50{background-color:#ede7f6 !important}.mdl-color-text--deep-purple-100{color:#d1c4e9 !important}.mdl-color--deep-purple-100{background-color:#d1c4e9 !important}.mdl-color-text--deep-purple-200{color:#b39ddb !important}.mdl-color--deep-purple-200{background-color:#b39ddb !important}.mdl-color-text--deep-purple-300{color:#9575cd !important}.mdl-color--deep-purple-300{background-color:#9575cd !important}.mdl-color-text--deep-purple-400{color:#7e57c2 !important}.mdl-color--deep-purple-400{background-color:#7e57c2 !important}.mdl-color-text--deep-purple-500{color:#673ab7 !important}.mdl-color--deep-purple-500{background-color:#673ab7 !important}.mdl-color-text--deep-purple-600{color:#5e35b1 !important}.mdl-color--deep-purple-600{background-color:#5e35b1 !important}.mdl-color-text--deep-purple-700{color:#512da8 !important}.mdl-color--deep-purple-700{background-color:#512da8 !important}.mdl-color-text--deep-purple-800{color:#4527a0 !important}.mdl-color--deep-purple-800{background-color:#4527a0 !important}.mdl-color-text--deep-purple-900{color:#311b92 !important}.mdl-color--deep-purple-900{background-color:#311b92 !important}.mdl-color-text--deep-purple-A100{color:#b388ff !important}.mdl-color--deep-purple-A100{background-color:#b388ff !important}.mdl-color-text--deep-purple-A200{color:#7c4dff !important}.mdl-color--deep-purple-A200{background-color:#7c4dff !important}.mdl-color-text--deep-purple-A400{color:#651fff !important}.mdl-color--deep-purple-A400{background-color:#651fff !important}.mdl-color-text--deep-purple-A700{color:#6200ea !important}.mdl-color--deep-purple-A700{background-color:#6200ea !important}.mdl-color-text--indigo{color:#3f51b5 !important}.mdl-color--indigo{background-color:#3f51b5 !important}.mdl-color-text--indigo-50{color:#e8eaf6 !important}.mdl-color--indigo-50{background-color:#e8eaf6 !important}.mdl-color-text--indigo-100{color:#c5cae9 !important}.mdl-color--indigo-100{background-color:#c5cae9 !important}.mdl-color-text--indigo-200{color:#9fa8da !important}.mdl-color--indigo-200{background-color:#9fa8da !important}.mdl-color-text--indigo-300{color:#7986cb !important}.mdl-color--indigo-300{background-color:#7986cb !important}.mdl-color-text--indigo-400{color:#5c6bc0 !important}.mdl-color--indigo-400{background-color:#5c6bc0 !important}.mdl-color-text--indigo-500{color:#3f51b5 !important}.mdl-color--indigo-500{background-color:#3f51b5 !important}.mdl-color-text--indigo-600{color:#3949ab !important}.mdl-color--indigo-600{background-color:#3949ab !important}.mdl-color-text--indigo-700{color:#303f9f !important}.mdl-color--indigo-700{background-color:#303f9f !important}.mdl-color-text--indigo-800{color:#283593 !important}.mdl-color--indigo-800{background-color:#283593 !important}.mdl-color-text--indigo-900{color:#1a237e !important}.mdl-color--indigo-900{background-color:#1a237e !important}.mdl-color-text--indigo-A100{color:#8c9eff !important}.mdl-color--indigo-A100{background-color:#8c9eff !important}.mdl-color-text--indigo-A200{color:#536dfe !important}.mdl-color--indigo-A200{background-color:#536dfe !important}.mdl-color-text--indigo-A400{color:#3d5afe !important}.mdl-color--indigo-A400{background-color:#3d5afe !important}.mdl-color-text--indigo-A700{color:#304ffe !important}.mdl-color--indigo-A700{background-color:#304ffe !important}.mdl-color-text--blue{color:#2196f3 !important}.mdl-color--blue{background-color:#2196f3 !important}.mdl-color-text--blue-50{color:#e3f2fd !important}.mdl-color--blue-50{background-color:#e3f2fd !important}.mdl-color-text--blue-100{color:#bbdefb !important}.mdl-color--blue-100{background-color:#bbdefb !important}.mdl-color-text--blue-200{color:#90caf9 !important}.mdl-color--blue-200{background-color:#90caf9 !important}.mdl-color-text--blue-300{color:#64b5f6 !important}.mdl-color--blue-300{background-color:#64b5f6 !important}.mdl-color-text--blue-400{color:#42a5f5 !important}.mdl-color--blue-400{background-color:#42a5f5 !important}.mdl-color-text--blue-500{color:#2196f3 !important}.mdl-color--blue-500{background-color:#2196f3 !important}.mdl-color-text--blue-600{color:#1e88e5 !important}.mdl-color--blue-600{background-color:#1e88e5 !important}.mdl-color-text--blue-700{color:#1976d2 !important}.mdl-color--blue-700{background-color:#1976d2 !important}.mdl-color-text--blue-800{color:#1565c0 !important}.mdl-color--blue-800{background-color:#1565c0 !important}.mdl-color-text--blue-900{color:#0d47a1 !important}.mdl-color--blue-900{background-color:#0d47a1 !important}.mdl-color-text--blue-A100{color:#82b1ff !important}.mdl-color--blue-A100{background-color:#82b1ff !important}.mdl-color-text--blue-A200{color:#448aff !important}.mdl-color--blue-A200{background-color:#448aff !important}.mdl-color-text--blue-A400{color:#2979ff !important}.mdl-color--blue-A400{background-color:#2979ff !important}.mdl-color-text--blue-A700{color:#2962ff !important}.mdl-color--blue-A700{background-color:#2962ff !important}.mdl-color-text--light-blue{color:#03a9f4 !important}.mdl-color--light-blue{background-color:#03a9f4 !important}.mdl-color-text--light-blue-50{color:#e1f5fe !important}.mdl-color--light-blue-50{background-color:#e1f5fe !important}.mdl-color-text--light-blue-100{color:#b3e5fc !important}.mdl-color--light-blue-100{background-color:#b3e5fc !important}.mdl-color-text--light-blue-200{color:#81d4fa !important}.mdl-color--light-blue-200{background-color:#81d4fa !important}.mdl-color-text--light-blue-300{color:#4fc3f7 !important}.mdl-color--light-blue-300{background-color:#4fc3f7 !important}.mdl-color-text--light-blue-400{color:#29b6f6 !important}.mdl-color--light-blue-400{background-color:#29b6f6 !important}.mdl-color-text--light-blue-500{color:#03a9f4 !important}.mdl-color--light-blue-500{background-color:#03a9f4 !important}.mdl-color-text--light-blue-600{color:#039be5 !important}.mdl-color--light-blue-600{background-color:#039be5 !important}.mdl-color-text--light-blue-700{color:#0288d1 !important}.mdl-color--light-blue-700{background-color:#0288d1 !important}.mdl-color-text--light-blue-800{color:#0277bd !important}.mdl-color--light-blue-800{background-color:#0277bd !important}.mdl-color-text--light-blue-900{color:#01579b !important}.mdl-color--light-blue-900{background-color:#01579b !important}.mdl-color-text--light-blue-A100{color:#80d8ff !important}.mdl-color--light-blue-A100{background-color:#80d8ff !important}.mdl-color-text--light-blue-A200{color:#40c4ff !important}.mdl-color--light-blue-A200{background-color:#40c4ff !important}.mdl-color-text--light-blue-A400{color:#00b0ff !important}.mdl-color--light-blue-A400{background-color:#00b0ff !important}.mdl-color-text--light-blue-A700{color:#0091ea !important}.mdl-color--light-blue-A700{background-color:#0091ea !important}.mdl-color-text--cyan{color:#00bcd4 !important}.mdl-color--cyan{background-color:#00bcd4 !important}.mdl-color-text--cyan-50{color:#e0f7fa !important}.mdl-color--cyan-50{background-color:#e0f7fa !important}.mdl-color-text--cyan-100{color:#b2ebf2 !important}.mdl-color--cyan-100{background-color:#b2ebf2 !important}.mdl-color-text--cyan-200{color:#80deea !important}.mdl-color--cyan-200{background-color:#80deea !important}.mdl-color-text--cyan-300{color:#4dd0e1 !important}.mdl-color--cyan-300{background-color:#4dd0e1 !important}.mdl-color-text--cyan-400{color:#26c6da !important}.mdl-color--cyan-400{background-color:#26c6da !important}.mdl-color-text--cyan-500{color:#00bcd4 !important}.mdl-color--cyan-500{background-color:#00bcd4 !important}.mdl-color-text--cyan-600{color:#00acc1 !important}.mdl-color--cyan-600{background-color:#00acc1 !important}.mdl-color-text--cyan-700{color:#0097a7 !important}.mdl-color--cyan-700{background-color:#0097a7 !important}.mdl-color-text--cyan-800{color:#00838f !important}.mdl-color--cyan-800{background-color:#00838f !important}.mdl-color-text--cyan-900{color:#006064 !important}.mdl-color--cyan-900{background-color:#006064 !important}.mdl-color-text--cyan-A100{color:#84ffff !important}.mdl-color--cyan-A100{background-color:#84ffff !important}.mdl-color-text--cyan-A200{color:#18ffff !important}.mdl-color--cyan-A200{background-color:#18ffff !important}.mdl-color-text--cyan-A400{color:#00e5ff !important}.mdl-color--cyan-A400{background-color:#00e5ff !important}.mdl-color-text--cyan-A700{color:#00b8d4 !important}.mdl-color--cyan-A700{background-color:#00b8d4 !important}.mdl-color-text--teal{color:#009688 !important}.mdl-color--teal{background-color:#009688 !important}.mdl-color-text--teal-50{color:#e0f2f1 !important}.mdl-color--teal-50{background-color:#e0f2f1 !important}.mdl-color-text--teal-100{color:#b2dfdb !important}.mdl-color--teal-100{background-color:#b2dfdb !important}.mdl-color-text--teal-200{color:#80cbc4 !important}.mdl-color--teal-200{background-color:#80cbc4 !important}.mdl-color-text--teal-300{color:#4db6ac !important}.mdl-color--teal-300{background-color:#4db6ac !important}.mdl-color-text--teal-400{color:#26a69a !important}.mdl-color--teal-400{background-color:#26a69a !important}.mdl-color-text--teal-500{color:#009688 !important}.mdl-color--teal-500{background-color:#009688 !important}.mdl-color-text--teal-600{color:#00897b !important}.mdl-color--teal-600{background-color:#00897b !important}.mdl-color-text--teal-700{color:#00796b !important}.mdl-color--teal-700{background-color:#00796b !important}.mdl-color-text--teal-800{color:#00695c !important}.mdl-color--teal-800{background-color:#00695c !important}.mdl-color-text--teal-900{color:#004d40 !important}.mdl-color--teal-900{background-color:#004d40 !important}.mdl-color-text--teal-A100{color:#a7ffeb !important}.mdl-color--teal-A100{background-color:#a7ffeb !important}.mdl-color-text--teal-A200{color:#64ffda !important}.mdl-color--teal-A200{background-color:#64ffda !important}.mdl-color-text--teal-A400{color:#1de9b6 !important}.mdl-color--teal-A400{background-color:#1de9b6 !important}.mdl-color-text--teal-A700{color:#00bfa5 !important}.mdl-color--teal-A700{background-color:#00bfa5 !important}.mdl-color-text--green{color:#4caf50 !important}.mdl-color--green{background-color:#4caf50 !important}.mdl-color-text--green-50{color:#e8f5e9 !important}.mdl-color--green-50{background-color:#e8f5e9 !important}.mdl-color-text--green-100{color:#c8e6c9 !important}.mdl-color--green-100{background-color:#c8e6c9 !important}.mdl-color-text--green-200{color:#a5d6a7 !important}.mdl-color--green-200{background-color:#a5d6a7 !important}.mdl-color-text--green-300{color:#81c784 !important}.mdl-color--green-300{background-color:#81c784 !important}.mdl-color-text--green-400{color:#66bb6a !important}.mdl-color--green-400{background-color:#66bb6a !important}.mdl-color-text--green-500{color:#4caf50 !important}.mdl-color--green-500{background-color:#4caf50 !important}.mdl-color-text--green-600{color:#43a047 !important}.mdl-color--green-600{background-color:#43a047 !important}.mdl-color-text--green-700{color:#388e3c !important}.mdl-color--green-700{background-color:#388e3c !important}.mdl-color-text--green-800{color:#2e7d32 !important}.mdl-color--green-800{background-color:#2e7d32 !important}.mdl-color-text--green-900{color:#1b5e20 !important}.mdl-color--green-900{background-color:#1b5e20 !important}.mdl-color-text--green-A100{color:#b9f6ca !important}.mdl-color--green-A100{background-color:#b9f6ca !important}.mdl-color-text--green-A200{color:#69f0ae !important}.mdl-color--green-A200{background-color:#69f0ae !important}.mdl-color-text--green-A400{color:#00e676 !important}.mdl-color--green-A400{background-color:#00e676 !important}.mdl-color-text--green-A700{color:#00c853 !important}.mdl-color--green-A700{background-color:#00c853 !important}.mdl-color-text--light-green{color:#8bc34a !important}.mdl-color--light-green{background-color:#8bc34a !important}.mdl-color-text--light-green-50{color:#f1f8e9 !important}.mdl-color--light-green-50{background-color:#f1f8e9 !important}.mdl-color-text--light-green-100{color:#dcedc8 !important}.mdl-color--light-green-100{background-color:#dcedc8 !important}.mdl-color-text--light-green-200{color:#c5e1a5 !important}.mdl-color--light-green-200{background-color:#c5e1a5 !important}.mdl-color-text--light-green-300{color:#aed581 !important}.mdl-color--light-green-300{background-color:#aed581 !important}.mdl-color-text--light-green-400{color:#9ccc65 !important}.mdl-color--light-green-400{background-color:#9ccc65 !important}.mdl-color-text--light-green-500{color:#8bc34a !important}.mdl-color--light-green-500{background-color:#8bc34a !important}.mdl-color-text--light-green-600{color:#7cb342 !important}.mdl-color--light-green-600{background-color:#7cb342 !important}.mdl-color-text--light-green-700{color:#689f38 !important}.mdl-color--light-green-700{background-color:#689f38 !important}.mdl-color-text--light-green-800{color:#558b2f !important}.mdl-color--light-green-800{background-color:#558b2f !important}.mdl-color-text--light-green-900{color:#33691e !important}.mdl-color--light-green-900{background-color:#33691e !important}.mdl-color-text--light-green-A100{color:#ccff90 !important}.mdl-color--light-green-A100{background-color:#ccff90 !important}.mdl-color-text--light-green-A200{color:#b2ff59 !important}.mdl-color--light-green-A200{background-color:#b2ff59 !important}.mdl-color-text--light-green-A400{color:#76ff03 !important}.mdl-color--light-green-A400{background-color:#76ff03 !important}.mdl-color-text--light-green-A700{color:#64dd17 !important}.mdl-color--light-green-A700{background-color:#64dd17 !important}.mdl-color-text--lime{color:#cddc39 !important}.mdl-color--lime{background-color:#cddc39 !important}.mdl-color-text--lime-50{color:#f9fbe7 !important}.mdl-color--lime-50{background-color:#f9fbe7 !important}.mdl-color-text--lime-100{color:#f0f4c3 !important}.mdl-color--lime-100{background-color:#f0f4c3 !important}.mdl-color-text--lime-200{color:#e6ee9c !important}.mdl-color--lime-200{background-color:#e6ee9c !important}.mdl-color-text--lime-300{color:#dce775 !important}.mdl-color--lime-300{background-color:#dce775 !important}.mdl-color-text--lime-400{color:#d4e157 !important}.mdl-color--lime-400{background-color:#d4e157 !important}.mdl-color-text--lime-500{color:#cddc39 !important}.mdl-color--lime-500{background-color:#cddc39 !important}.mdl-color-text--lime-600{color:#c0ca33 !important}.mdl-color--lime-600{background-color:#c0ca33 !important}.mdl-color-text--lime-700{color:#afb42b !important}.mdl-color--lime-700{background-color:#afb42b !important}.mdl-color-text--lime-800{color:#9e9d24 !important}.mdl-color--lime-800{background-color:#9e9d24 !important}.mdl-color-text--lime-900{color:#827717 !important}.mdl-color--lime-900{background-color:#827717 !important}.mdl-color-text--lime-A100{color:#f4ff81 !important}.mdl-color--lime-A100{background-color:#f4ff81 !important}.mdl-color-text--lime-A200{color:#eeff41 !important}.mdl-color--lime-A200{background-color:#eeff41 !important}.mdl-color-text--lime-A400{color:#c6ff00 !important}.mdl-color--lime-A400{background-color:#c6ff00 !important}.mdl-color-text--lime-A700{color:#aeea00 !important}.mdl-color--lime-A700{background-color:#aeea00 !important}.mdl-color-text--yellow{color:#ffeb3b !important}.mdl-color--yellow{background-color:#ffeb3b !important}.mdl-color-text--yellow-50{color:#fffde7 !important}.mdl-color--yellow-50{background-color:#fffde7 !important}.mdl-color-text--yellow-100{color:#fff9c4 !important}.mdl-color--yellow-100{background-color:#fff9c4 !important}.mdl-color-text--yellow-200{color:#fff59d !important}.mdl-color--yellow-200{background-color:#fff59d !important}.mdl-color-text--yellow-300{color:#fff176 !important}.mdl-color--yellow-300{background-color:#fff176 !important}.mdl-color-text--yellow-400{color:#ffee58 !important}.mdl-color--yellow-400{background-color:#ffee58 !important}.mdl-color-text--yellow-500{color:#ffeb3b !important}.mdl-color--yellow-500{background-color:#ffeb3b !important}.mdl-color-text--yellow-600{color:#fdd835 !important}.mdl-color--yellow-600{background-color:#fdd835 !important}.mdl-color-text--yellow-700{color:#fbc02d !important}.mdl-color--yellow-700{background-color:#fbc02d !important}.mdl-color-text--yellow-800{color:#f9a825 !important}.mdl-color--yellow-800{background-color:#f9a825 !important}.mdl-color-text--yellow-900{color:#f57f17 !important}.mdl-color--yellow-900{background-color:#f57f17 !important}.mdl-color-text--yellow-A100{color:#ffff8d !important}.mdl-color--yellow-A100{background-color:#ffff8d !important}.mdl-color-text--yellow-A200{color:#ff0 !important}.mdl-color--yellow-A200{background-color:#ff0 !important}.mdl-color-text--yellow-A400{color:#ffea00 !important}.mdl-color--yellow-A400{background-color:#ffea00 !important}.mdl-color-text--yellow-A700{color:#ffd600 !important}.mdl-color--yellow-A700{background-color:#ffd600 !important}.mdl-color-text--amber{color:#ffc107 !important}.mdl-color--amber{background-color:#ffc107 !important}.mdl-color-text--amber-50{color:#fff8e1 !important}.mdl-color--amber-50{background-color:#fff8e1 !important}.mdl-color-text--amber-100{color:#ffecb3 !important}.mdl-color--amber-100{background-color:#ffecb3 !important}.mdl-color-text--amber-200{color:#ffe082 !important}.mdl-color--amber-200{background-color:#ffe082 !important}.mdl-color-text--amber-300{color:#ffd54f !important}.mdl-color--amber-300{background-color:#ffd54f !important}.mdl-color-text--amber-400{color:#ffca28 !important}.mdl-color--amber-400{background-color:#ffca28 !important}.mdl-color-text--amber-500{color:#ffc107 !important}.mdl-color--amber-500{background-color:#ffc107 !important}.mdl-color-text--amber-600{color:#ffb300 !important}.mdl-color--amber-600{background-color:#ffb300 !important}.mdl-color-text--amber-700{color:#ffa000 !important}.mdl-color--amber-700{background-color:#ffa000 !important}.mdl-color-text--amber-800{color:#ff8f00 !important}.mdl-color--amber-800{background-color:#ff8f00 !important}.mdl-color-text--amber-900{color:#ff6f00 !important}.mdl-color--amber-900{background-color:#ff6f00 !important}.mdl-color-text--amber-A100{color:#ffe57f !important}.mdl-color--amber-A100{background-color:#ffe57f !important}.mdl-color-text--amber-A200{color:#ffd740 !important}.mdl-color--amber-A200{background-color:#ffd740 !important}.mdl-color-text--amber-A400{color:#ffc400 !important}.mdl-color--amber-A400{background-color:#ffc400 !important}.mdl-color-text--amber-A700{color:#ffab00 !important}.mdl-color--amber-A700{background-color:#ffab00 !important}.mdl-color-text--orange{color:#ff9800 !important}.mdl-color--orange{background-color:#ff9800 !important}.mdl-color-text--orange-50{color:#fff3e0 !important}.mdl-color--orange-50{background-color:#fff3e0 !important}.mdl-color-text--orange-100{color:#ffe0b2 !important}.mdl-color--orange-100{background-color:#ffe0b2 !important}.mdl-color-text--orange-200{color:#ffcc80 !important}.mdl-color--orange-200{background-color:#ffcc80 !important}.mdl-color-text--orange-300{color:#ffb74d !important}.mdl-color--orange-300{background-color:#ffb74d !important}.mdl-color-text--orange-400{color:#ffa726 !important}.mdl-color--orange-400{background-color:#ffa726 !important}.mdl-color-text--orange-500{color:#ff9800 !important}.mdl-color--orange-500{background-color:#ff9800 !important}.mdl-color-text--orange-600{color:#fb8c00 !important}.mdl-color--orange-600{background-color:#fb8c00 !important}.mdl-color-text--orange-700{color:#f57c00 !important}.mdl-color--orange-700{background-color:#f57c00 !important}.mdl-color-text--orange-800{color:#ef6c00 !important}.mdl-color--orange-800{background-color:#ef6c00 !important}.mdl-color-text--orange-900{color:#e65100 !important}.mdl-color--orange-900{background-color:#e65100 !important}.mdl-color-text--orange-A100{color:#ffd180 !important}.mdl-color--orange-A100{background-color:#ffd180 !important}.mdl-color-text--orange-A200{color:#ffab40 !important}.mdl-color--orange-A200{background-color:#ffab40 !important}.mdl-color-text--orange-A400{color:#ff9100 !important}.mdl-color--orange-A400{background-color:#ff9100 !important}.mdl-color-text--orange-A700{color:#ff6d00 !important}.mdl-color--orange-A700{background-color:#ff6d00 !important}.mdl-color-text--deep-orange{color:#ff5722 !important}.mdl-color--deep-orange{background-color:#ff5722 !important}.mdl-color-text--deep-orange-50{color:#fbe9e7 !important}.mdl-color--deep-orange-50{background-color:#fbe9e7 !important}.mdl-color-text--deep-orange-100{color:#ffccbc !important}.mdl-color--deep-orange-100{background-color:#ffccbc !important}.mdl-color-text--deep-orange-200{color:#ffab91 !important}.mdl-color--deep-orange-200{background-color:#ffab91 !important}.mdl-color-text--deep-orange-300{color:#ff8a65 !important}.mdl-color--deep-orange-300{background-color:#ff8a65 !important}.mdl-color-text--deep-orange-400{color:#ff7043 !important}.mdl-color--deep-orange-400{background-color:#ff7043 !important}.mdl-color-text--deep-orange-500{color:#ff5722 !important}.mdl-color--deep-orange-500{background-color:#ff5722 !important}.mdl-color-text--deep-orange-600{color:#f4511e !important}.mdl-color--deep-orange-600{background-color:#f4511e !important}.mdl-color-text--deep-orange-700{color:#e64a19 !important}.mdl-color--deep-orange-700{background-color:#e64a19 !important}.mdl-color-text--deep-orange-800{color:#d84315 !important}.mdl-color--deep-orange-800{background-color:#d84315 !important}.mdl-color-text--deep-orange-900{color:#bf360c !important}.mdl-color--deep-orange-900{background-color:#bf360c !important}.mdl-color-text--deep-orange-A100{color:#ff9e80 !important}.mdl-color--deep-orange-A100{background-color:#ff9e80 !important}.mdl-color-text--deep-orange-A200{color:#ff6e40 !important}.mdl-color--deep-orange-A200{background-color:#ff6e40 !important}.mdl-color-text--deep-orange-A400{color:#ff3d00 !important}.mdl-color--deep-orange-A400{background-color:#ff3d00 !important}.mdl-color-text--deep-orange-A700{color:#dd2c00 !important}.mdl-color--deep-orange-A700{background-color:#dd2c00 !important}.mdl-color-text--brown{color:#795548 !important}.mdl-color--brown{background-color:#795548 !important}.mdl-color-text--brown-50{color:#efebe9 !important}.mdl-color--brown-50{background-color:#efebe9 !important}.mdl-color-text--brown-100{color:#d7ccc8 !important}.mdl-color--brown-100{background-color:#d7ccc8 !important}.mdl-color-text--brown-200{color:#bcaaa4 !important}.mdl-color--brown-200{background-color:#bcaaa4 !important}.mdl-color-text--brown-300{color:#a1887f !important}.mdl-color--brown-300{background-color:#a1887f !important}.mdl-color-text--brown-400{color:#8d6e63 !important}.mdl-color--brown-400{background-color:#8d6e63 !important}.mdl-color-text--brown-500{color:#795548 !important}.mdl-color--brown-500{background-color:#795548 !important}.mdl-color-text--brown-600{color:#6d4c41 !important}.mdl-color--brown-600{background-color:#6d4c41 !important}.mdl-color-text--brown-700{color:#5d4037 !important}.mdl-color--brown-700{background-color:#5d4037 !important}.mdl-color-text--brown-800{color:#4e342e !important}.mdl-color--brown-800{background-color:#4e342e !important}.mdl-color-text--brown-900{color:#3e2723 !important}.mdl-color--brown-900{background-color:#3e2723 !important}.mdl-color-text--grey{color:#9e9e9e !important}.mdl-color--grey{background-color:#9e9e9e !important}.mdl-color-text--grey-50{color:#fafafa !important}.mdl-color--grey-50{background-color:#fafafa !important}.mdl-color-text--grey-100{color:#f5f5f5 !important}.mdl-color--grey-100{background-color:#f5f5f5 !important}.mdl-color-text--grey-200{color:#eee !important}.mdl-color--grey-200{background-color:#eee !important}.mdl-color-text--grey-300{color:#e0e0e0 !important}.mdl-color--grey-300{background-color:#e0e0e0 !important}.mdl-color-text--grey-400{color:#bdbdbd !important}.mdl-color--grey-400{background-color:#bdbdbd !important}.mdl-color-text--grey-500{color:#9e9e9e !important}.mdl-color--grey-500{background-color:#9e9e9e !important}.mdl-color-text--grey-600{color:#757575 !important}.mdl-color--grey-600{background-color:#757575 !important}.mdl-color-text--grey-700{color:#616161 !important}.mdl-color--grey-700{background-color:#616161 !important}.mdl-color-text--grey-800{color:#424242 !important}.mdl-color--grey-800{background-color:#424242 !important}.mdl-color-text--grey-900{color:#212121 !important}.mdl-color--grey-900{background-color:#212121 !important}.mdl-color-text--blue-grey{color:#607d8b !important}.mdl-color--blue-grey{background-color:#607d8b !important}.mdl-color-text--blue-grey-50{color:#eceff1 !important}.mdl-color--blue-grey-50{background-color:#eceff1 !important}.mdl-color-text--blue-grey-100{color:#cfd8dc !important}.mdl-color--blue-grey-100{background-color:#cfd8dc !important}.mdl-color-text--blue-grey-200{color:#b0bec5 !important}.mdl-color--blue-grey-200{background-color:#b0bec5 !important}.mdl-color-text--blue-grey-300{color:#90a4ae !important}.mdl-color--blue-grey-300{background-color:#90a4ae !important}.mdl-color-text--blue-grey-400{color:#78909c !important}.mdl-color--blue-grey-400{background-color:#78909c !important}.mdl-color-text--blue-grey-500{color:#607d8b !important}.mdl-color--blue-grey-500{background-color:#607d8b !important}.mdl-color-text--blue-grey-600{color:#546e7a !important}.mdl-color--blue-grey-600{background-color:#546e7a !important}.mdl-color-text--blue-grey-700{color:#455a64 !important}.mdl-color--blue-grey-700{background-color:#455a64 !important}.mdl-color-text--blue-grey-800{color:#37474f !important}.mdl-color--blue-grey-800{background-color:#37474f !important}.mdl-color-text--blue-grey-900{color:#263238 !important}.mdl-color--blue-grey-900{background-color:#263238 !important}.mdl-color--black{background-color:#000 !important}.mdl-color-text--black{color:#000 !important}.mdl-color--white{background-color:#fff !important}.mdl-color-text--white{color:#fff !important}.mdl-color--primary{background-color:#3f51b5 !important}.mdl-color--primary-contrast{background-color:#fff !important}.mdl-color--primary-dark{background-color:#303f9f !important}.mdl-color--accent{background-color:#ff4081 !important}.mdl-color--accent-contrast{background-color:#fff !important}.mdl-color-text--primary{color:#3f51b5 !important}.mdl-color-text--primary-contrast{color:#fff !important}.mdl-color-text--primary-dark{color:#303f9f !important}.mdl-color-text--accent{color:#ff4081 !important}.mdl-color-text--accent-contrast{color:#fff !important}.mdl-ripple{background:#000;border-radius:50%;height:50px;left:0;opacity:0;pointer-events:none;position:absolute;top:0;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);width:50px;overflow:hidden}.mdl-ripple.is-animating{transition:transform .3s cubic-bezier(0,0,.2,1),width .3s cubic-bezier(0,0,.2,1),height .3s cubic-bezier(0,0,.2,1),opacity .6s cubic-bezier(0,0,.2,1);transition:transform .3s cubic-bezier(0,0,.2,1),width .3s cubic-bezier(0,0,.2,1),height .3s cubic-bezier(0,0,.2,1),opacity .6s cubic-bezier(0,0,.2,1),-webkit-transform .3s cubic-bezier(0,0,.2,1)}.mdl-ripple.is-visible{opacity:.3}.mdl-animation--default,.mdl-animation--fast-out-slow-in{transition-timing-function:cubic-bezier(.4,0,.2,1)}.mdl-animation--linear-out-slow-in{transition-timing-function:cubic-bezier(0,0,.2,1)}.mdl-animation--fast-out-linear-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.mdl-badge{position:relative;white-space:nowrap;margin-right:24px}.mdl-badge:not([data-badge]){margin-right:auto}.mdl-badge[data-badge]:after{content:attr(data-badge);display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-content:center;-ms-flex-line-pack:center;align-content:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;position:absolute;top:-11px;right:-24px;font-family:"Roboto","Helvetica","Arial",sans-serif;font-weight:600;font-size:12px;width:22px;height:22px;border-radius:50%;background:#ff4081;color:#fff}.mdl-button .mdl-badge[data-badge]:after{top:-10px;right:-5px}.mdl-badge.mdl-badge--no-background[data-badge]:after{color:#ff4081;background:rgba(255,255,255,.2);box-shadow:0 0 1px gray}.mdl-badge.mdl-badge--overlap{margin-right:10px}.mdl-badge.mdl-badge--overlap:after{right:-10px}.mdl-button{background:0 0;border:none;border-radius:2px;color:#000;position:relative;height:36px;margin:0;min-width:64px;padding:0 16px;display:inline-block;font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:14px;font-weight:500;text-transform:uppercase;letter-spacing:0;overflow:hidden;will-change:box-shadow;transition:box-shadow .2s cubic-bezier(.4,0,1,1),background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1);outline:none;cursor:pointer;text-decoration:none;text-align:center;line-height:36px;vertical-align:middle}.mdl-button::-moz-focus-inner{border:0}.mdl-button:hover{background-color:rgba(158,158,158,.2)}.mdl-button:focus:not(:active){background-color:rgba(0,0,0,.12)}.mdl-button:active{background-color:rgba(158,158,158,.4)}.mdl-button.mdl-button--colored{color:#3f51b5}.mdl-button.mdl-button--colored:focus:not(:active){background-color:rgba(0,0,0,.12)}input.mdl-button[type="submit"]{-webkit-appearance:none}.mdl-button--raised{background:rgba(158,158,158,.2);box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.mdl-button--raised:active{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);background-color:rgba(158,158,158,.4)}.mdl-button--raised:focus:not(:active){box-shadow:0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36);background-color:rgba(158,158,158,.4)}.mdl-button--raised.mdl-button--colored{background:#3f51b5;color:#fff}.mdl-button--raised.mdl-button--colored:hover{background-color:#3f51b5}.mdl-button--raised.mdl-button--colored:active{background-color:#3f51b5}.mdl-button--raised.mdl-button--colored:focus:not(:active){background-color:#3f51b5}.mdl-button--raised.mdl-button--colored .mdl-ripple{background:#fff}.mdl-button--fab{border-radius:50%;font-size:24px;height:56px;margin:auto;min-width:56px;width:56px;padding:0;overflow:hidden;background:rgba(158,158,158,.2);box-shadow:0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24);position:relative;line-height:normal}.mdl-button--fab .material-icons{position:absolute;top:50%;left:50%;-webkit-transform:translate(-12px,-12px);transform:translate(-12px,-12px);line-height:24px;width:24px}.mdl-button--fab.mdl-button--mini-fab{height:40px;min-width:40px;width:40px}.mdl-button--fab .mdl-button__ripple-container{border-radius:50%;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-button--fab:active{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2);background-color:rgba(158,158,158,.4)}.mdl-button--fab:focus:not(:active){box-shadow:0 0 8px rgba(0,0,0,.18),0 8px 16px rgba(0,0,0,.36);background-color:rgba(158,158,158,.4)}.mdl-button--fab.mdl-button--colored{background:#ff4081;color:#fff}.mdl-button--fab.mdl-button--colored:hover{background-color:#ff4081}.mdl-button--fab.mdl-button--colored:focus:not(:active){background-color:#ff4081}.mdl-button--fab.mdl-button--colored:active{background-color:#ff4081}.mdl-button--fab.mdl-button--colored .mdl-ripple{background:#fff}.mdl-button--icon{border-radius:50%;font-size:24px;height:32px;margin-left:0;margin-right:0;min-width:32px;width:32px;padding:0;overflow:hidden;color:inherit;line-height:normal}.mdl-button--icon .material-icons{position:absolute;top:50%;left:50%;-webkit-transform:translate(-12px,-12px);transform:translate(-12px,-12px);line-height:24px;width:24px}.mdl-button--icon.mdl-button--mini-icon{height:24px;min-width:24px;width:24px}.mdl-button--icon.mdl-button--mini-icon .material-icons{top:0;left:0}.mdl-button--icon .mdl-button__ripple-container{border-radius:50%;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-button__ripple-container{display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:0;overflow:hidden}.mdl-button[disabled] .mdl-button__ripple-container .mdl-ripple,.mdl-button.mdl-button--disabled .mdl-button__ripple-container .mdl-ripple{background-color:transparent}.mdl-button--primary.mdl-button--primary{color:#3f51b5}.mdl-button--primary.mdl-button--primary .mdl-ripple{background:#fff}.mdl-button--primary.mdl-button--primary.mdl-button--raised,.mdl-button--primary.mdl-button--primary.mdl-button--fab{color:#fff;background-color:#3f51b5}.mdl-button--accent.mdl-button--accent{color:#ff4081}.mdl-button--accent.mdl-button--accent .mdl-ripple{background:#fff}.mdl-button--accent.mdl-button--accent.mdl-button--raised,.mdl-button--accent.mdl-button--accent.mdl-button--fab{color:#fff;background-color:#ff4081}.mdl-button[disabled][disabled],.mdl-button.mdl-button--disabled.mdl-button--disabled{color:rgba(0,0,0,.26);cursor:default;background-color:transparent}.mdl-button--fab[disabled][disabled],.mdl-button--fab.mdl-button--disabled.mdl-button--disabled{background-color:rgba(0,0,0,.12);color:rgba(0,0,0,.26)}.mdl-button--raised[disabled][disabled],.mdl-button--raised.mdl-button--disabled.mdl-button--disabled{background-color:rgba(0,0,0,.12);color:rgba(0,0,0,.26);box-shadow:none}.mdl-button--colored[disabled][disabled],.mdl-button--colored.mdl-button--disabled.mdl-button--disabled{color:rgba(0,0,0,.26)}.mdl-button .material-icons{vertical-align:middle}.mdl-card{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;font-size:16px;font-weight:400;min-height:200px;overflow:hidden;width:330px;z-index:1;position:relative;background:#fff;border-radius:2px;box-sizing:border-box}.mdl-card__media{background-color:#ff4081;background-repeat:repeat;background-position:50% 50%;background-size:cover;background-origin:padding-box;background-attachment:scroll;box-sizing:border-box}.mdl-card__title{-webkit-align-items:center;-ms-flex-align:center;align-items:center;color:#000;display:block;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:stretch;-ms-flex-pack:stretch;justify-content:stretch;line-height:normal;padding:16px;-webkit-perspective-origin:165px 56px;perspective-origin:165px 56px;-webkit-transform-origin:165px 56px;transform-origin:165px 56px;box-sizing:border-box}.mdl-card__title.mdl-card--border{border-bottom:1px solid rgba(0,0,0,.1)}.mdl-card__title-text{-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end;color:inherit;display:block;display:-webkit-flex;display:-ms-flexbox;display:flex;font-size:24px;font-weight:300;line-height:normal;overflow:hidden;-webkit-transform-origin:149px 48px;transform-origin:149px 48px;margin:0}.mdl-card__subtitle-text{font-size:14px;color:rgba(0,0,0,.54);margin:0}.mdl-card__supporting-text{color:rgba(0,0,0,.54);font-size:1rem;line-height:18px;overflow:hidden;padding:16px;width:90%}.mdl-card__actions{font-size:16px;line-height:normal;width:100%;background-color:transparent;padding:8px;box-sizing:border-box}.mdl-card__actions.mdl-card--border{border-top:1px solid rgba(0,0,0,.1)}.mdl-card--expand{-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.mdl-card__menu{position:absolute;right:16px;top:16px}.mdl-checkbox{position:relative;z-index:1;vertical-align:middle;display:inline-block;box-sizing:border-box;width:100%;height:24px;margin:0;padding:0}.mdl-checkbox.is-upgraded{padding-left:24px}.mdl-checkbox__input{line-height:24px}.mdl-checkbox.is-upgraded .mdl-checkbox__input{position:absolute;width:0;height:0;margin:0;padding:0;opacity:0;-ms-appearance:none;-moz-appearance:none;-webkit-appearance:none;appearance:none;border:none}.mdl-checkbox__box-outline{position:absolute;top:3px;left:0;display:inline-block;box-sizing:border-box;width:16px;height:16px;margin:0;cursor:pointer;overflow:hidden;border:2px solid rgba(0,0,0,.54);border-radius:2px;z-index:2}.mdl-checkbox.is-checked .mdl-checkbox__box-outline{border:2px solid #3f51b5}fieldset[disabled] .mdl-checkbox .mdl-checkbox__box-outline,.mdl-checkbox.is-disabled .mdl-checkbox__box-outline{border:2px solid rgba(0,0,0,.26);cursor:auto}.mdl-checkbox__focus-helper{position:absolute;top:3px;left:0;display:inline-block;box-sizing:border-box;width:16px;height:16px;border-radius:50%;background-color:transparent}.mdl-checkbox.is-focused .mdl-checkbox__focus-helper{box-shadow:0 0 0 8px rgba(0,0,0,.1);background-color:rgba(0,0,0,.1)}.mdl-checkbox.is-focused.is-checked .mdl-checkbox__focus-helper{box-shadow:0 0 0 8px rgba(63,81,181,.26);background-color:rgba(63,81,181,.26)}.mdl-checkbox__tick-outline{position:absolute;top:0;left:0;height:100%;width:100%;-webkit-mask:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8ZGVmcz4KICAgIDxjbGlwUGF0aCBpZD0iY2xpcCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIDAsMSAxLDEgMSwwIDAsMCB6IE0gMC44NTM0Mzc1LDAuMTY3MTg3NSAwLjk1OTY4NzUsMC4yNzMxMjUgMC40MjkzNzUsMC44MDM0Mzc1IDAuMzIzMTI1LDAuOTA5Njg3NSAwLjIxNzE4NzUsMC44MDM0Mzc1IDAuMDQwMzEyNSwwLjYyNjg3NSAwLjE0NjU2MjUsMC41MjA2MjUgMC4zMjMxMjUsMC42OTc1IDAuODUzNDM3NSwwLjE2NzE4NzUgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgICA8bWFzayBpZD0ibWFzayIgbWFza1VuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgbWFza0NvbnRlbnRVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giPgogICAgICA8cGF0aAogICAgICAgICBkPSJNIDAsMCAwLDEgMSwxIDEsMCAwLDAgeiBNIDAuODUzNDM3NSwwLjE2NzE4NzUgMC45NTk2ODc1LDAuMjczMTI1IDAuNDI5Mzc1LDAuODAzNDM3NSAwLjMyMzEyNSwwLjkwOTY4NzUgMC4yMTcxODc1LDAuODAzNDM3NSAwLjA0MDMxMjUsMC42MjY4NzUgMC4xNDY1NjI1LDAuNTIwNjI1IDAuMzIzMTI1LDAuNjk3NSAwLjg1MzQzNzUsMC4xNjcxODc1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiIC8+CiAgICA8L21hc2s+CiAgPC9kZWZzPgogIDxyZWN0CiAgICAgd2lkdGg9IjEiCiAgICAgaGVpZ2h0PSIxIgogICAgIHg9IjAiCiAgICAgeT0iMCIKICAgICBjbGlwLXBhdGg9InVybCgjY2xpcCkiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KPC9zdmc+Cg==");mask:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8ZGVmcz4KICAgIDxjbGlwUGF0aCBpZD0iY2xpcCI+CiAgICAgIDxwYXRoCiAgICAgICAgIGQ9Ik0gMCwwIDAsMSAxLDEgMSwwIDAsMCB6IE0gMC44NTM0Mzc1LDAuMTY3MTg3NSAwLjk1OTY4NzUsMC4yNzMxMjUgMC40MjkzNzUsMC44MDM0Mzc1IDAuMzIzMTI1LDAuOTA5Njg3NSAwLjIxNzE4NzUsMC44MDM0Mzc1IDAuMDQwMzEyNSwwLjYyNjg3NSAwLjE0NjU2MjUsMC41MjA2MjUgMC4zMjMxMjUsMC42OTc1IDAuODUzNDM3NSwwLjE2NzE4NzUgeiIKICAgICAgICAgc3R5bGU9ImZpbGw6I2ZmZmZmZjtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KICAgIDwvY2xpcFBhdGg+CiAgICA8bWFzayBpZD0ibWFzayIgbWFza1VuaXRzPSJvYmplY3RCb3VuZGluZ0JveCIgbWFza0NvbnRlbnRVbml0cz0ib2JqZWN0Qm91bmRpbmdCb3giPgogICAgICA8cGF0aAogICAgICAgICBkPSJNIDAsMCAwLDEgMSwxIDEsMCAwLDAgeiBNIDAuODUzNDM3NSwwLjE2NzE4NzUgMC45NTk2ODc1LDAuMjczMTI1IDAuNDI5Mzc1LDAuODAzNDM3NSAwLjMyMzEyNSwwLjkwOTY4NzUgMC4yMTcxODc1LDAuODAzNDM3NSAwLjA0MDMxMjUsMC42MjY4NzUgMC4xNDY1NjI1LDAuNTIwNjI1IDAuMzIzMTI1LDAuNjk3NSAwLjg1MzQzNzUsMC4xNjcxODc1IHoiCiAgICAgICAgIHN0eWxlPSJmaWxsOiNmZmZmZmY7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmUiIC8+CiAgICA8L21hc2s+CiAgPC9kZWZzPgogIDxyZWN0CiAgICAgd2lkdGg9IjEiCiAgICAgaGVpZ2h0PSIxIgogICAgIHg9IjAiCiAgICAgeT0iMCIKICAgICBjbGlwLXBhdGg9InVybCgjY2xpcCkiCiAgICAgc3R5bGU9ImZpbGw6IzAwMDAwMDtmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZSIgLz4KPC9zdmc+Cg==");background:0 0;transition-duration:.28s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:background}.mdl-checkbox.is-checked .mdl-checkbox__tick-outline{background:#3f51b5 url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K")}fieldset[disabled] .mdl-checkbox.is-checked .mdl-checkbox__tick-outline,.mdl-checkbox.is-checked.is-disabled .mdl-checkbox__tick-outline{background:rgba(0,0,0,.26)url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjxzdmcKICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIgogICB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiCiAgIHhtbG5zOnN2Zz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgdmVyc2lvbj0iMS4xIgogICB2aWV3Qm94PSIwIDAgMSAxIgogICBwcmVzZXJ2ZUFzcGVjdFJhdGlvPSJ4TWluWU1pbiBtZWV0Ij4KICA8cGF0aAogICAgIGQ9Ik0gMC4wNDAzODA1OSwwLjYyNjc3NjcgMC4xNDY0NDY2MSwwLjUyMDcxMDY4IDAuNDI5Mjg5MzIsMC44MDM1NTMzOSAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IE0gMC4yMTcxNTcyOSwwLjgwMzU1MzM5IDAuODUzNTUzMzksMC4xNjcxNTcyOSAwLjk1OTYxOTQxLDAuMjczMjIzMyAwLjMyMzIyMzMsMC45MDk2MTk0MSB6IgogICAgIGlkPSJyZWN0Mzc4MCIKICAgICBzdHlsZT0iZmlsbDojZmZmZmZmO2ZpbGwtb3BhY2l0eToxO3N0cm9rZTpub25lIiAvPgo8L3N2Zz4K")}.mdl-checkbox__label{position:relative;cursor:pointer;font-size:16px;line-height:24px;margin:0}fieldset[disabled] .mdl-checkbox .mdl-checkbox__label,.mdl-checkbox.is-disabled .mdl-checkbox__label{color:rgba(0,0,0,.26);cursor:auto}.mdl-checkbox__ripple-container{position:absolute;z-index:2;top:-6px;left:-10px;box-sizing:border-box;width:36px;height:36px;border-radius:50%;cursor:pointer;overflow:hidden;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-checkbox__ripple-container .mdl-ripple{background:#3f51b5}fieldset[disabled] .mdl-checkbox .mdl-checkbox__ripple-container,.mdl-checkbox.is-disabled .mdl-checkbox__ripple-container{cursor:auto}fieldset[disabled] .mdl-checkbox .mdl-checkbox__ripple-container .mdl-ripple,.mdl-checkbox.is-disabled .mdl-checkbox__ripple-container .mdl-ripple{background:0 0}.mdl-data-table{position:relative;border:1px solid rgba(0,0,0,.12);border-collapse:collapse;white-space:nowrap;font-size:13px;background-color:#fff}.mdl-data-table thead{padding-bottom:3px}.mdl-data-table thead .mdl-data-table__select{margin-top:0}.mdl-data-table tbody tr{position:relative;height:48px;transition-duration:.28s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:background-color}.mdl-data-table tbody tr.is-selected{background-color:#e0e0e0}.mdl-data-table tbody tr:hover{background-color:#eee}.mdl-data-table td{text-align:right}.mdl-data-table th{padding:0 18px 12px 18px;text-align:right}.mdl-data-table td:first-of-type,.mdl-data-table th:first-of-type{padding-left:24px}.mdl-data-table td:last-of-type,.mdl-data-table th:last-of-type{padding-right:24px}.mdl-data-table td{position:relative;height:48px;border-top:1px solid rgba(0,0,0,.12);border-bottom:1px solid rgba(0,0,0,.12);padding:12px 18px;box-sizing:border-box}.mdl-data-table td,.mdl-data-table td .mdl-data-table__select{vertical-align:middle}.mdl-data-table th{position:relative;vertical-align:bottom;text-overflow:ellipsis;font-weight:700;line-height:24px;letter-spacing:0;height:48px;font-size:12px;color:rgba(0,0,0,.54);padding-bottom:8px;box-sizing:border-box}.mdl-data-table th.mdl-data-table__header--sorted-ascending,.mdl-data-table th.mdl-data-table__header--sorted-descending{color:rgba(0,0,0,.87)}.mdl-data-table th.mdl-data-table__header--sorted-ascending:before,.mdl-data-table th.mdl-data-table__header--sorted-descending:before{font-family:'Material Icons';font-weight:400;font-style:normal;line-height:1;letter-spacing:normal;text-transform:none;display:inline-block;word-wrap:normal;-moz-font-feature-settings:'liga';font-feature-settings:'liga';-webkit-font-feature-settings:'liga';-webkit-font-smoothing:antialiased;font-size:16px;content:"\e5d8";margin-right:5px;vertical-align:sub}.mdl-data-table th.mdl-data-table__header--sorted-ascending:hover,.mdl-data-table th.mdl-data-table__header--sorted-descending:hover{cursor:pointer}.mdl-data-table th.mdl-data-table__header--sorted-ascending:hover:before,.mdl-data-table th.mdl-data-table__header--sorted-descending:hover:before{color:rgba(0,0,0,.26)}.mdl-data-table th.mdl-data-table__header--sorted-descending:before{content:"\e5db"}.mdl-data-table__select{width:16px}.mdl-data-table__cell--non-numeric.mdl-data-table__cell--non-numeric{text-align:left}.mdl-dialog{border:none;box-shadow:0 9px 46px 8px rgba(0,0,0,.14),0 11px 15px -7px rgba(0,0,0,.12),0 24px 38px 3px rgba(0,0,0,.2);width:280px}.mdl-dialog__title{padding:24px 24px 0;margin:0;font-size:2.5rem}.mdl-dialog__actions{padding:8px 8px 8px 24px;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row-reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap}.mdl-dialog__actions>*{margin-right:8px;height:36px}.mdl-dialog__actions>*:first-child{margin-right:0}.mdl-dialog__actions--full-width{padding:0 0 8px}.mdl-dialog__actions--full-width>*{height:48px;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;padding-right:16px;margin-right:0;text-align:right}.mdl-dialog__content{padding:20px 24px 24px;color:rgba(0,0,0,.54)}.mdl-mega-footer{padding:16px 40px;color:#9e9e9e;background-color:#424242}.mdl-mega-footer--top-section:after,.mdl-mega-footer--middle-section:after,.mdl-mega-footer--bottom-section:after,.mdl-mega-footer__top-section:after,.mdl-mega-footer__middle-section:after,.mdl-mega-footer__bottom-section:after{content:'';display:block;clear:both}.mdl-mega-footer--left-section,.mdl-mega-footer__left-section,.mdl-mega-footer--right-section,.mdl-mega-footer__right-section{margin-bottom:16px}.mdl-mega-footer--right-section a,.mdl-mega-footer__right-section a{display:block;margin-bottom:16px;color:inherit;text-decoration:none}@media screen and (min-width:760px){.mdl-mega-footer--left-section,.mdl-mega-footer__left-section{float:left}.mdl-mega-footer--right-section,.mdl-mega-footer__right-section{float:right}.mdl-mega-footer--right-section a,.mdl-mega-footer__right-section a{display:inline-block;margin-left:16px;line-height:36px;vertical-align:middle}}.mdl-mega-footer--social-btn,.mdl-mega-footer__social-btn{width:36px;height:36px;padding:0;margin:0;background-color:#9e9e9e;border:none}.mdl-mega-footer--drop-down-section,.mdl-mega-footer__drop-down-section{display:block;position:relative}@media screen and (min-width:760px){.mdl-mega-footer--drop-down-section,.mdl-mega-footer__drop-down-section{width:33%}.mdl-mega-footer--drop-down-section:nth-child(1),.mdl-mega-footer--drop-down-section:nth-child(2),.mdl-mega-footer__drop-down-section:nth-child(1),.mdl-mega-footer__drop-down-section:nth-child(2){float:left}.mdl-mega-footer--drop-down-section:nth-child(3),.mdl-mega-footer__drop-down-section:nth-child(3){float:right}.mdl-mega-footer--drop-down-section:nth-child(3):after,.mdl-mega-footer__drop-down-section:nth-child(3):after{clear:right}.mdl-mega-footer--drop-down-section:nth-child(4),.mdl-mega-footer__drop-down-section:nth-child(4){clear:right;float:right}.mdl-mega-footer--middle-section:after,.mdl-mega-footer__middle-section:after{content:'';display:block;clear:both}.mdl-mega-footer--bottom-section,.mdl-mega-footer__bottom-section{padding-top:0}}@media screen and (min-width:1024px){.mdl-mega-footer--drop-down-section,.mdl-mega-footer--drop-down-section:nth-child(3),.mdl-mega-footer--drop-down-section:nth-child(4),.mdl-mega-footer__drop-down-section,.mdl-mega-footer__drop-down-section:nth-child(3),.mdl-mega-footer__drop-down-section:nth-child(4){width:24%;float:left}}.mdl-mega-footer--heading-checkbox,.mdl-mega-footer__heading-checkbox{position:absolute;width:100%;height:55.8px;padding:32px;margin:-16px 0 0;cursor:pointer;z-index:1;opacity:0}.mdl-mega-footer--heading-checkbox+.mdl-mega-footer--heading:after,.mdl-mega-footer--heading-checkbox+.mdl-mega-footer__heading:after,.mdl-mega-footer__heading-checkbox+.mdl-mega-footer--heading:after,.mdl-mega-footer__heading-checkbox+.mdl-mega-footer__heading:after{font-family:'Material Icons';content:'\E5CE'}.mdl-mega-footer--heading-checkbox:checked~.mdl-mega-footer--link-list,.mdl-mega-footer--heading-checkbox:checked~.mdl-mega-footer__link-list,.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer--heading+.mdl-mega-footer--link-list,.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer__heading+.mdl-mega-footer__link-list,.mdl-mega-footer__heading-checkbox:checked~.mdl-mega-footer--link-list,.mdl-mega-footer__heading-checkbox:checked~.mdl-mega-footer__link-list,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer--heading+.mdl-mega-footer--link-list,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer__heading+.mdl-mega-footer__link-list{display:none}.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer--heading:after,.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer__heading:after,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer--heading:after,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer__heading:after{font-family:'Material Icons';content:'\E5CF'}.mdl-mega-footer--heading,.mdl-mega-footer__heading{position:relative;width:100%;padding-right:39.8px;margin-bottom:16px;box-sizing:border-box;font-size:14px;line-height:23.8px;font-weight:500;white-space:nowrap;text-overflow:ellipsis;overflow:hidden;color:#e0e0e0}.mdl-mega-footer--heading:after,.mdl-mega-footer__heading:after{content:'';position:absolute;top:0;right:0;display:block;width:23.8px;height:23.8px;background-size:cover}.mdl-mega-footer--link-list,.mdl-mega-footer__link-list{list-style:none;padding:0;margin:0 0 32px}.mdl-mega-footer--link-list:after,.mdl-mega-footer__link-list:after{clear:both;display:block;content:''}.mdl-mega-footer--link-list li,.mdl-mega-footer__link-list li{font-size:14px;font-weight:400;letter-spacing:0;line-height:20px}.mdl-mega-footer--link-list a,.mdl-mega-footer__link-list a{color:inherit;text-decoration:none;white-space:nowrap}@media screen and (min-width:760px){.mdl-mega-footer--heading-checkbox,.mdl-mega-footer__heading-checkbox{display:none}.mdl-mega-footer--heading-checkbox+.mdl-mega-footer--heading:after,.mdl-mega-footer--heading-checkbox+.mdl-mega-footer__heading:after,.mdl-mega-footer__heading-checkbox+.mdl-mega-footer--heading:after,.mdl-mega-footer__heading-checkbox+.mdl-mega-footer__heading:after{content:''}.mdl-mega-footer--heading-checkbox:checked~.mdl-mega-footer--link-list,.mdl-mega-footer--heading-checkbox:checked~.mdl-mega-footer__link-list,.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer__heading+.mdl-mega-footer__link-list,.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer--heading+.mdl-mega-footer--link-list,.mdl-mega-footer__heading-checkbox:checked~.mdl-mega-footer--link-list,.mdl-mega-footer__heading-checkbox:checked~.mdl-mega-footer__link-list,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer__heading+.mdl-mega-footer__link-list,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer--heading+.mdl-mega-footer--link-list{display:block}.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer--heading:after,.mdl-mega-footer--heading-checkbox:checked+.mdl-mega-footer__heading:after,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer--heading:after,.mdl-mega-footer__heading-checkbox:checked+.mdl-mega-footer__heading:after{content:''}}.mdl-mega-footer--bottom-section,.mdl-mega-footer__bottom-section{padding-top:16px;margin-bottom:16px}.mdl-logo{margin-bottom:16px;color:#fff}.mdl-mega-footer--bottom-section .mdl-mega-footer--link-list li,.mdl-mega-footer__bottom-section .mdl-mega-footer__link-list li{float:left;margin-bottom:0;margin-right:16px}@media screen and (min-width:760px){.mdl-logo{float:left;margin-bottom:0;margin-right:16px}}.mdl-mini-footer{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;padding:32px 16px;color:#9e9e9e;background-color:#424242}.mdl-mini-footer:after{content:'';display:block}.mdl-mini-footer .mdl-logo{line-height:36px}.mdl-mini-footer--link-list,.mdl-mini-footer__link-list{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:row nowrap;-ms-flex-flow:row nowrap;flex-flow:row nowrap;list-style:none;margin:0;padding:0}.mdl-mini-footer--link-list li,.mdl-mini-footer__link-list li{margin-bottom:0;margin-right:16px}@media screen and (min-width:760px){.mdl-mini-footer--link-list li,.mdl-mini-footer__link-list li{line-height:36px}}.mdl-mini-footer--link-list a,.mdl-mini-footer__link-list a{color:inherit;text-decoration:none;white-space:nowrap}.mdl-mini-footer--left-section,.mdl-mini-footer__left-section{display:inline-block;-webkit-order:0;-ms-flex-order:0;order:0}.mdl-mini-footer--right-section,.mdl-mini-footer__right-section{display:inline-block;-webkit-order:1;-ms-flex-order:1;order:1}.mdl-mini-footer--social-btn,.mdl-mini-footer__social-btn{width:36px;height:36px;padding:0;margin:0;background-color:#9e9e9e;border:none}.mdl-icon-toggle{position:relative;z-index:1;vertical-align:middle;display:inline-block;height:32px;margin:0;padding:0}.mdl-icon-toggle__input{line-height:32px}.mdl-icon-toggle.is-upgraded .mdl-icon-toggle__input{position:absolute;width:0;height:0;margin:0;padding:0;opacity:0;-ms-appearance:none;-moz-appearance:none;-webkit-appearance:none;appearance:none;border:none}.mdl-icon-toggle__label{display:inline-block;position:relative;cursor:pointer;height:32px;width:32px;min-width:32px;color:#616161;border-radius:50%;padding:0;margin-left:0;margin-right:0;text-align:center;background-color:transparent;will-change:background-color;transition:background-color .2s cubic-bezier(.4,0,.2,1),color .2s cubic-bezier(.4,0,.2,1)}.mdl-icon-toggle__label.material-icons{line-height:32px;font-size:24px}.mdl-icon-toggle.is-checked .mdl-icon-toggle__label{color:#3f51b5}.mdl-icon-toggle.is-disabled .mdl-icon-toggle__label{color:rgba(0,0,0,.26);cursor:auto;transition:none}.mdl-icon-toggle.is-focused .mdl-icon-toggle__label{background-color:rgba(0,0,0,.12)}.mdl-icon-toggle.is-focused.is-checked .mdl-icon-toggle__label{background-color:rgba(63,81,181,.26)}.mdl-icon-toggle__ripple-container{position:absolute;z-index:2;top:-2px;left:-2px;box-sizing:border-box;width:36px;height:36px;border-radius:50%;cursor:pointer;overflow:hidden;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-icon-toggle__ripple-container .mdl-ripple{background:#616161}.mdl-icon-toggle.is-disabled .mdl-icon-toggle__ripple-container{cursor:auto}.mdl-icon-toggle.is-disabled .mdl-icon-toggle__ripple-container .mdl-ripple{background:0 0}.mdl-list{display:block;padding:8px 0;list-style:none}.mdl-list__item{font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:16px;font-weight:400;letter-spacing:.04em;line-height:1;min-height:48px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;padding:16px;cursor:default;color:rgba(0,0,0,.87);overflow:hidden}.mdl-list__item,.mdl-list__item .mdl-list__item-primary-content{box-sizing:border-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-align-items:center;-ms-flex-align:center;align-items:center}.mdl-list__item .mdl-list__item-primary-content{-webkit-order:0;-ms-flex-order:0;order:0;-webkit-flex-grow:2;-ms-flex-positive:2;flex-grow:2;text-decoration:none}.mdl-list__item .mdl-list__item-primary-content .mdl-list__item-icon{margin-right:32px}.mdl-list__item .mdl-list__item-primary-content .mdl-list__item-avatar{margin-right:16px}.mdl-list__item .mdl-list__item-secondary-content{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:column;-ms-flex-flow:column;flex-flow:column;-webkit-align-items:flex-end;-ms-flex-align:end;align-items:flex-end;margin-left:16px}.mdl-list__item .mdl-list__item-secondary-content .mdl-list__item-secondary-action label{display:inline}.mdl-list__item .mdl-list__item-secondary-content .mdl-list__item-secondary-info{font-size:12px;font-weight:400;line-height:1;letter-spacing:0;color:rgba(0,0,0,.54)}.mdl-list__item .mdl-list__item-secondary-content .mdl-list__item-sub-header{padding:0 0 0 16px}.mdl-list__item-icon,.mdl-list__item-icon.material-icons{height:24px;width:24px;font-size:24px;box-sizing:border-box;color:#757575}.mdl-list__item-avatar,.mdl-list__item-avatar.material-icons{height:40px;width:40px;box-sizing:border-box;border-radius:50%;background-color:#757575;font-size:40px;color:#fff}.mdl-list__item--two-line{height:72px}.mdl-list__item--two-line .mdl-list__item-primary-content{height:36px;line-height:20px;display:block}.mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-avatar{float:left}.mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-icon{float:left;margin-top:6px}.mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-secondary-content{height:36px}.mdl-list__item--two-line .mdl-list__item-primary-content .mdl-list__item-sub-title{font-size:14px;font-weight:400;letter-spacing:0;line-height:18px;color:rgba(0,0,0,.54);display:block;padding:0}.mdl-list__item--three-line{height:88px}.mdl-list__item--three-line .mdl-list__item-primary-content{height:52px;line-height:20px;display:block}.mdl-list__item--three-line .mdl-list__item-primary-content .mdl-list__item-avatar,.mdl-list__item--three-line .mdl-list__item-primary-content .mdl-list__item-icon{float:left}.mdl-list__item--three-line .mdl-list__item-secondary-content{height:52px}.mdl-list__item--three-line .mdl-list__item-text-body{font-size:14px;font-weight:400;letter-spacing:0;line-height:18px;height:52px;color:rgba(0,0,0,.54);display:block;padding:0}.mdl-menu__container{display:block;margin:0;padding:0;border:none;position:absolute;overflow:visible;height:0;width:0;visibility:hidden;z-index:-1}.mdl-menu__container.is-visible,.mdl-menu__container.is-animating{z-index:999;visibility:visible}.mdl-menu__outline{display:block;background:#fff;margin:0;padding:0;border:none;border-radius:2px;position:absolute;top:0;left:0;overflow:hidden;opacity:0;-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:0 0;transform-origin:0 0;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);will-change:transform;transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1);transition:transform .3s cubic-bezier(.4,0,.2,1),opacity .2s cubic-bezier(.4,0,.2,1),-webkit-transform .3s cubic-bezier(.4,0,.2,1);z-index:-1}.mdl-menu__container.is-visible .mdl-menu__outline{opacity:1;-webkit-transform:scale(1);transform:scale(1);z-index:999}.mdl-menu__outline.mdl-menu--bottom-right{-webkit-transform-origin:100% 0;transform-origin:100% 0}.mdl-menu__outline.mdl-menu--top-left{-webkit-transform-origin:0 100%;transform-origin:0 100%}.mdl-menu__outline.mdl-menu--top-right{-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.mdl-menu{position:absolute;list-style:none;top:0;left:0;height:auto;width:auto;min-width:124px;padding:8px 0;margin:0;opacity:0;clip:rect(0 0 0 0);z-index:-1}.mdl-menu__container.is-visible .mdl-menu{opacity:1;z-index:999}.mdl-menu.is-animating{transition:opacity .2s cubic-bezier(.4,0,.2,1),clip .3s cubic-bezier(.4,0,.2,1)}.mdl-menu.mdl-menu--bottom-right{left:auto;right:0}.mdl-menu.mdl-menu--top-left{top:auto;bottom:0}.mdl-menu.mdl-menu--top-right{top:auto;left:auto;bottom:0;right:0}.mdl-menu.mdl-menu--unaligned{top:auto;left:auto}.mdl-menu__item{display:block;border:none;color:rgba(0,0,0,.87);background-color:transparent;text-align:left;margin:0;padding:0 16px;outline-color:#bdbdbd;position:relative;overflow:hidden;font-size:14px;font-weight:400;letter-spacing:0;text-decoration:none;cursor:pointer;height:48px;line-height:48px;white-space:nowrap;opacity:0;transition:opacity .2s cubic-bezier(.4,0,.2,1);-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdl-menu__container.is-visible .mdl-menu__item{opacity:1}.mdl-menu__item::-moz-focus-inner{border:0}.mdl-menu__item--full-bleed-divider{border-bottom:1px solid rgba(0,0,0,.12)}.mdl-menu__item[disabled],.mdl-menu__item[data-mdl-disabled]{color:#bdbdbd;background-color:transparent;cursor:auto}.mdl-menu__item[disabled]:hover,.mdl-menu__item[data-mdl-disabled]:hover{background-color:transparent}.mdl-menu__item[disabled]:focus,.mdl-menu__item[data-mdl-disabled]:focus{background-color:transparent}.mdl-menu__item[disabled] .mdl-ripple,.mdl-menu__item[data-mdl-disabled] .mdl-ripple{background:0 0}.mdl-menu__item:hover{background-color:#eee}.mdl-menu__item:focus{outline:none;background-color:#eee}.mdl-menu__item:active{background-color:#e0e0e0}.mdl-menu__item--ripple-container{display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:0;overflow:hidden}.mdl-progress{display:block;position:relative;height:4px;width:500px;max-width:100%}.mdl-progress>.bar{display:block;position:absolute;top:0;bottom:0;width:0%;transition:width .2s cubic-bezier(.4,0,.2,1)}.mdl-progress>.progressbar{background-color:#3f51b5;z-index:1;left:0}.mdl-progress>.bufferbar{background-image:linear-gradient(to right,rgba(255,255,255,.7),rgba(255,255,255,.7)),linear-gradient(to right,#3f51b5 ,#3f51b5);z-index:0;left:0}.mdl-progress>.auxbar{right:0}@supports (-webkit-appearance:none){.mdl-progress:not(.mdl-progress--indeterminate):not(.mdl-progress--indeterminate)>.auxbar,.mdl-progress:not(.mdl-progress__indeterminate):not(.mdl-progress__indeterminate)>.auxbar{background-image:linear-gradient(to right,rgba(255,255,255,.7),rgba(255,255,255,.7)),linear-gradient(to right,#3f51b5 ,#3f51b5);-webkit-mask:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgd2lkdGg9IjEyIiBoZWlnaHQ9IjQiIHZpZXdQb3J0PSIwIDAgMTIgNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxlbGxpcHNlIGN4PSIyIiBjeT0iMiIgcng9IjIiIHJ5PSIyIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImN4IiBmcm9tPSIyIiB0bz0iLTEwIiBkdXI9IjAuNnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiAvPgogIDwvZWxsaXBzZT4KICA8ZWxsaXBzZSBjeD0iMTQiIGN5PSIyIiByeD0iMiIgcnk9IjIiIGNsYXNzPSJsb2FkZXIiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3giIGZyb209IjE0IiB0bz0iMiIgZHVyPSIwLjZzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L2VsbGlwc2U+Cjwvc3ZnPgo=");mask:url("data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIj8+Cjxzdmcgd2lkdGg9IjEyIiBoZWlnaHQ9IjQiIHZpZXdQb3J0PSIwIDAgMTIgNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxlbGxpcHNlIGN4PSIyIiBjeT0iMiIgcng9IjIiIHJ5PSIyIj4KICAgIDxhbmltYXRlIGF0dHJpYnV0ZU5hbWU9ImN4IiBmcm9tPSIyIiB0bz0iLTEwIiBkdXI9IjAuNnMiIHJlcGVhdENvdW50PSJpbmRlZmluaXRlIiAvPgogIDwvZWxsaXBzZT4KICA8ZWxsaXBzZSBjeD0iMTQiIGN5PSIyIiByeD0iMiIgcnk9IjIiIGNsYXNzPSJsb2FkZXIiPgogICAgPGFuaW1hdGUgYXR0cmlidXRlTmFtZT0iY3giIGZyb209IjE0IiB0bz0iMiIgZHVyPSIwLjZzIiByZXBlYXRDb3VudD0iaW5kZWZpbml0ZSIgLz4KICA8L2VsbGlwc2U+Cjwvc3ZnPgo=")}}.mdl-progress:not(.mdl-progress--indeterminate)>.auxbar,.mdl-progress:not(.mdl-progress__indeterminate)>.auxbar{background-image:linear-gradient(to right,rgba(255,255,255,.9),rgba(255,255,255,.9)),linear-gradient(to right,#3f51b5 ,#3f51b5)}.mdl-progress.mdl-progress--indeterminate>.bar1,.mdl-progress.mdl-progress__indeterminate>.bar1{-webkit-animation-name:indeterminate1;animation-name:indeterminate1}.mdl-progress.mdl-progress--indeterminate>.bar1,.mdl-progress.mdl-progress__indeterminate>.bar1,.mdl-progress.mdl-progress--indeterminate>.bar3,.mdl-progress.mdl-progress__indeterminate>.bar3{background-color:#3f51b5;-webkit-animation-duration:2s;animation-duration:2s;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite;-webkit-animation-timing-function:linear;animation-timing-function:linear}.mdl-progress.mdl-progress--indeterminate>.bar3,.mdl-progress.mdl-progress__indeterminate>.bar3{background-image:none;-webkit-animation-name:indeterminate2;animation-name:indeterminate2}@-webkit-keyframes indeterminate1{0%{left:0%;width:0%}50%{left:25%;width:75%}75%{left:100%;width:0%}}@keyframes indeterminate1{0%{left:0%;width:0%}50%{left:25%;width:75%}75%{left:100%;width:0%}}@-webkit-keyframes indeterminate2{0%,50%{left:0%;width:0%}75%{left:0%;width:25%}100%{left:100%;width:0%}}@keyframes indeterminate2{0%,50%{left:0%;width:0%}75%{left:0%;width:25%}100%{left:100%;width:0%}}.mdl-navigation{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;box-sizing:border-box}.mdl-navigation__link{color:#424242;text-decoration:none;margin:0;font-size:14px;font-weight:400;line-height:24px;letter-spacing:0;opacity:.87}.mdl-navigation__link .material-icons{vertical-align:middle}.mdl-layout{width:100%;height:100%;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;overflow-y:auto;overflow-x:hidden;position:relative;-webkit-overflow-scrolling:touch}.mdl-layout.is-small-screen .mdl-layout--large-screen-only{display:none}.mdl-layout:not(.is-small-screen) .mdl-layout--small-screen-only{display:none}.mdl-layout__container{position:absolute;width:100%;height:100%}.mdl-layout__title,.mdl-layout-title{display:block;position:relative;font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:20px;line-height:1;letter-spacing:.02em;font-weight:400;box-sizing:border-box}.mdl-layout-spacer{-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1}.mdl-layout__drawer{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;width:240px;height:100%;max-height:100%;position:absolute;top:0;left:0;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);box-sizing:border-box;border-right:1px solid #e0e0e0;background:#fafafa;-webkit-transform:translateX(-250px);transform:translateX(-250px);-webkit-transform-style:preserve-3d;transform-style:preserve-3d;will-change:transform;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:transform;transition-property:transform,-webkit-transform;color:#424242;overflow:visible;overflow-y:auto;z-index:5}.mdl-layout__drawer.is-visible{-webkit-transform:translateX(0);transform:translateX(0)}.mdl-layout__drawer.is-visible~.mdl-layout__content.mdl-layout__content{overflow:hidden}.mdl-layout__drawer>*{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.mdl-layout__drawer>.mdl-layout__title,.mdl-layout__drawer>.mdl-layout-title{line-height:64px;padding-left:40px}@media screen and (max-width:1024px){.mdl-layout__drawer>.mdl-layout__title,.mdl-layout__drawer>.mdl-layout-title{line-height:56px;padding-left:16px}}.mdl-layout__drawer .mdl-navigation{-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-align-items:stretch;-ms-flex-align:stretch;-ms-grid-row-align:stretch;align-items:stretch;padding-top:16px}.mdl-layout__drawer .mdl-navigation .mdl-navigation__link{display:block;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;padding:16px 40px;margin:0;color:#757575}@media screen and (max-width:1024px){.mdl-layout__drawer .mdl-navigation .mdl-navigation__link{padding:16px}}.mdl-layout__drawer .mdl-navigation .mdl-navigation__link:hover{background-color:#e0e0e0}.mdl-layout__drawer .mdl-navigation .mdl-navigation__link--current{background-color:#000;color:#e0e0e0}@media screen and (min-width:1025px){.mdl-layout--fixed-drawer>.mdl-layout__drawer{-webkit-transform:translateX(0);transform:translateX(0)}}.mdl-layout__drawer-button{display:block;position:absolute;height:48px;width:48px;border:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;overflow:hidden;text-align:center;cursor:pointer;font-size:26px;line-height:50px;font-family:Helvetica,Arial,sans-serif;margin:10px 12px;top:0;left:0;color:#fff;z-index:4}.mdl-layout__header .mdl-layout__drawer-button{position:absolute;color:#fff;background-color:inherit}@media screen and (max-width:1024px){.mdl-layout__header .mdl-layout__drawer-button{margin:4px}}@media screen and (max-width:1024px){.mdl-layout__drawer-button{margin:4px;color:rgba(0,0,0,.5)}}@media screen and (min-width:1025px){.mdl-layout--fixed-drawer>.mdl-layout__drawer-button,.mdl-layout--no-desktop-drawer-button .mdl-layout__drawer-button{display:none}}.mdl-layout--no-drawer-button .mdl-layout__drawer-button{display:none}.mdl-layout__header{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:column;-ms-flex-direction:column;flex-direction:column;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-justify-content:flex-start;-ms-flex-pack:start;justify-content:flex-start;box-sizing:border-box;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;width:100%;margin:0;padding:0;border:none;min-height:64px;max-height:1000px;z-index:3;background-color:#3f51b5;color:#fff;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:max-height,box-shadow}@media screen and (max-width:1024px){.mdl-layout__header{min-height:56px}}.mdl-layout--fixed-drawer.is-upgraded:not(.is-small-screen)>.mdl-layout__header{margin-left:240px;width:calc(100% - 240px)}@media screen and (min-width:1025px){.mdl-layout--fixed-drawer>.mdl-layout__header .mdl-layout__header-row{padding-left:40px}}.mdl-layout__header>.mdl-layout-icon{position:absolute;left:40px;top:16px;height:32px;width:32px;overflow:hidden;z-index:3;display:block}@media screen and (max-width:1024px){.mdl-layout__header>.mdl-layout-icon{left:16px;top:12px}}.mdl-layout.has-drawer .mdl-layout__header>.mdl-layout-icon{display:none}.mdl-layout__header.is-compact{max-height:64px}@media screen and (max-width:1024px){.mdl-layout__header.is-compact{max-height:56px}}.mdl-layout__header.is-compact.has-tabs{height:112px}@media screen and (max-width:1024px){.mdl-layout__header.is-compact.has-tabs{min-height:104px}}@media screen and (max-width:1024px){.mdl-layout__header{display:none}.mdl-layout--fixed-header>.mdl-layout__header{display:-webkit-flex;display:-ms-flexbox;display:flex}}.mdl-layout__header--transparent.mdl-layout__header--transparent{background-color:transparent;box-shadow:none}.mdl-layout__header--seamed,.mdl-layout__header--scroll{box-shadow:none}.mdl-layout__header--waterfall{box-shadow:none;overflow:hidden}.mdl-layout__header--waterfall.is-casting-shadow{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.mdl-layout__header--waterfall.mdl-layout__header--waterfall-hide-top{-webkit-justify-content:flex-end;-ms-flex-pack:end;justify-content:flex-end}.mdl-layout__header-row{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-flex-wrap:nowrap;-ms-flex-wrap:nowrap;flex-wrap:nowrap;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;box-sizing:border-box;-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch;-webkit-align-items:center;-ms-flex-align:center;align-items:center;height:64px;margin:0;padding:0 40px 0 80px}.mdl-layout--no-drawer-button .mdl-layout__header-row{padding-left:40px}@media screen and (min-width:1025px){.mdl-layout--no-desktop-drawer-button .mdl-layout__header-row{padding-left:40px}}@media screen and (max-width:1024px){.mdl-layout__header-row{height:56px;padding:0 16px 0 72px}.mdl-layout--no-drawer-button .mdl-layout__header-row{padding-left:16px}}.mdl-layout__header-row>*{-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0}.mdl-layout__header--scroll .mdl-layout__header-row{width:100%}.mdl-layout__header-row .mdl-navigation{margin:0;padding:0;height:64px;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-align-items:center;-ms-flex-align:center;-ms-grid-row-align:center;align-items:center}@media screen and (max-width:1024px){.mdl-layout__header-row .mdl-navigation{height:56px}}.mdl-layout__header-row .mdl-navigation__link{display:block;color:#fff;line-height:64px;padding:0 24px}@media screen and (max-width:1024px){.mdl-layout__header-row .mdl-navigation__link{line-height:56px;padding:0 16px}}.mdl-layout__obfuscator{background-color:transparent;position:absolute;top:0;left:0;height:100%;width:100%;z-index:4;visibility:hidden;transition-property:background-color;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.mdl-layout__obfuscator.is-visible{background-color:rgba(0,0,0,.5);visibility:visible}@supports (pointer-events:auto){.mdl-layout__obfuscator{background-color:rgba(0,0,0,.5);opacity:0;transition-property:opacity;visibility:visible;pointer-events:none}.mdl-layout__obfuscator.is-visible{pointer-events:auto;opacity:1}}.mdl-layout__content{-ms-flex:0 1 auto;position:relative;display:inline-block;overflow-y:auto;overflow-x:hidden;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;z-index:1;-webkit-overflow-scrolling:touch}.mdl-layout--fixed-drawer>.mdl-layout__content{margin-left:240px}.mdl-layout__container.has-scrolling-header .mdl-layout__content{overflow:visible}@media screen and (max-width:1024px){.mdl-layout--fixed-drawer>.mdl-layout__content{margin-left:0}.mdl-layout__container.has-scrolling-header .mdl-layout__content{overflow-y:auto;overflow-x:hidden}}.mdl-layout__tab-bar{height:96px;margin:0;width:calc(100% - 112px);padding:0 0 0 56px;display:-webkit-flex;display:-ms-flexbox;display:flex;background-color:#3f51b5;overflow-y:hidden;overflow-x:scroll}.mdl-layout__tab-bar::-webkit-scrollbar{display:none}.mdl-layout--no-drawer-button .mdl-layout__tab-bar{padding-left:16px;width:calc(100% - 32px)}@media screen and (min-width:1025px){.mdl-layout--no-desktop-drawer-button .mdl-layout__tab-bar{padding-left:16px;width:calc(100% - 32px)}}@media screen and (max-width:1024px){.mdl-layout__tab-bar{width:calc(100% - 60px);padding:0 0 0 60px}.mdl-layout--no-drawer-button .mdl-layout__tab-bar{width:calc(100% - 8px);padding-left:4px}}.mdl-layout--fixed-tabs .mdl-layout__tab-bar{padding:0;overflow:hidden;width:100%}.mdl-layout__tab-bar-container{position:relative;height:48px;width:100%;border:none;margin:0;z-index:2;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;overflow:hidden}.mdl-layout__container>.mdl-layout__tab-bar-container{position:absolute;top:0;left:0}.mdl-layout__tab-bar-button{display:inline-block;position:absolute;top:0;height:48px;width:56px;z-index:4;text-align:center;background-color:#3f51b5;color:transparent;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdl-layout--no-desktop-drawer-button .mdl-layout__tab-bar-button,.mdl-layout--no-drawer-button .mdl-layout__tab-bar-button{width:16px}.mdl-layout--no-desktop-drawer-button .mdl-layout__tab-bar-button .material-icons,.mdl-layout--no-drawer-button .mdl-layout__tab-bar-button .material-icons{position:relative;left:-4px}@media screen and (max-width:1024px){.mdl-layout__tab-bar-button{display:none;width:60px}}.mdl-layout--fixed-tabs .mdl-layout__tab-bar-button{display:none}.mdl-layout__tab-bar-button .material-icons{line-height:48px}.mdl-layout__tab-bar-button.is-active{color:#fff}.mdl-layout__tab-bar-left-button{left:0}.mdl-layout__tab-bar-right-button{right:0}.mdl-layout__tab{margin:0;border:none;padding:0 24px;float:left;position:relative;display:block;-webkit-flex-grow:0;-ms-flex-positive:0;flex-grow:0;-webkit-flex-shrink:0;-ms-flex-negative:0;flex-shrink:0;text-decoration:none;height:48px;line-height:48px;text-align:center;font-weight:500;font-size:14px;text-transform:uppercase;color:rgba(255,255,255,.6);overflow:hidden}@media screen and (max-width:1024px){.mdl-layout__tab{padding:0 12px}}.mdl-layout--fixed-tabs .mdl-layout__tab{float:none;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;padding:0}.mdl-layout.is-upgraded .mdl-layout__tab.is-active{color:#fff}.mdl-layout.is-upgraded .mdl-layout__tab.is-active::after{height:2px;width:100%;display:block;content:" ";bottom:0;left:0;position:absolute;background:#ff4081;-webkit-animation:border-expand .2s cubic-bezier(.4,0,.4,1).01s alternate forwards;animation:border-expand .2s cubic-bezier(.4,0,.4,1).01s alternate forwards;transition:all 1s cubic-bezier(.4,0,1,1)}.mdl-layout__tab .mdl-layout__tab-ripple-container{display:block;position:absolute;height:100%;width:100%;left:0;top:0;z-index:1;overflow:hidden}.mdl-layout__tab .mdl-layout__tab-ripple-container .mdl-ripple{background-color:#fff}.mdl-layout__tab-panel{display:block}.mdl-layout.is-upgraded .mdl-layout__tab-panel{display:none}.mdl-layout.is-upgraded .mdl-layout__tab-panel.is-active{display:block}.mdl-radio{position:relative;font-size:16px;line-height:24px;display:inline-block;box-sizing:border-box;margin:0;padding-left:0}.mdl-radio.is-upgraded{padding-left:24px}.mdl-radio__button{line-height:24px}.mdl-radio.is-upgraded .mdl-radio__button{position:absolute;width:0;height:0;margin:0;padding:0;opacity:0;-ms-appearance:none;-moz-appearance:none;-webkit-appearance:none;appearance:none;border:none}.mdl-radio__outer-circle{position:absolute;top:4px;left:0;display:inline-block;box-sizing:border-box;width:16px;height:16px;margin:0;cursor:pointer;border:2px solid rgba(0,0,0,.54);border-radius:50%;z-index:2}.mdl-radio.is-checked .mdl-radio__outer-circle{border:2px solid #3f51b5}.mdl-radio__outer-circle fieldset[disabled] .mdl-radio,.mdl-radio.is-disabled .mdl-radio__outer-circle{border:2px solid rgba(0,0,0,.26);cursor:auto}.mdl-radio__inner-circle{position:absolute;z-index:1;margin:0;top:8px;left:4px;box-sizing:border-box;width:8px;height:8px;cursor:pointer;transition-duration:.28s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:transform;transition-property:transform,-webkit-transform;-webkit-transform:scale3d(0,0,0);transform:scale3d(0,0,0);border-radius:50%;background:#3f51b5}.mdl-radio.is-checked .mdl-radio__inner-circle{-webkit-transform:scale3d(1,1,1);transform:scale3d(1,1,1)}fieldset[disabled] .mdl-radio .mdl-radio__inner-circle,.mdl-radio.is-disabled .mdl-radio__inner-circle{background:rgba(0,0,0,.26);cursor:auto}.mdl-radio.is-focused .mdl-radio__inner-circle{box-shadow:0 0 0 10px rgba(0,0,0,.1)}.mdl-radio__label{cursor:pointer}fieldset[disabled] .mdl-radio .mdl-radio__label,.mdl-radio.is-disabled .mdl-radio__label{color:rgba(0,0,0,.26);cursor:auto}.mdl-radio__ripple-container{position:absolute;z-index:2;top:-9px;left:-13px;box-sizing:border-box;width:42px;height:42px;border-radius:50%;cursor:pointer;overflow:hidden;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000)}.mdl-radio__ripple-container .mdl-ripple{background:#3f51b5}fieldset[disabled] .mdl-radio .mdl-radio__ripple-container,.mdl-radio.is-disabled .mdl-radio__ripple-container{cursor:auto}fieldset[disabled] .mdl-radio .mdl-radio__ripple-container .mdl-ripple,.mdl-radio.is-disabled .mdl-radio__ripple-container .mdl-ripple{background:0 0}_:-ms-input-placeholder,:root .mdl-slider.mdl-slider.is-upgraded{-ms-appearance:none;height:32px;margin:0}.mdl-slider{width:calc(100% - 40px);margin:0 20px}.mdl-slider.is-upgraded{-webkit-appearance:none;-moz-appearance:none;appearance:none;height:2px;background:0 0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;outline:0;padding:0;color:#3f51b5;-webkit-align-self:center;-ms-flex-item-align:center;align-self:center;z-index:1;cursor:pointer}.mdl-slider.is-upgraded::-moz-focus-outer{border:0}.mdl-slider.is-upgraded::-ms-tooltip{display:none}.mdl-slider.is-upgraded::-webkit-slider-runnable-track{background:0 0}.mdl-slider.is-upgraded::-moz-range-track{background:0 0;border:none}.mdl-slider.is-upgraded::-ms-track{background:0 0;color:transparent;height:2px;width:100%;border:none}.mdl-slider.is-upgraded::-ms-fill-lower{padding:0;background:linear-gradient(to right,transparent,transparent 16px,#3f51b5 16px,#3f51b5 0)}.mdl-slider.is-upgraded::-ms-fill-upper{padding:0;background:linear-gradient(to left,transparent,transparent 16px,rgba(0,0,0,.26)16px,rgba(0,0,0,.26)0)}.mdl-slider.is-upgraded::-webkit-slider-thumb{-webkit-appearance:none;width:12px;height:12px;box-sizing:border-box;border-radius:50%;background:#3f51b5;border:none;transition:transform .18s cubic-bezier(.4,0,.2,1),border .18s cubic-bezier(.4,0,.2,1),box-shadow .18s cubic-bezier(.4,0,.2,1),background .28s cubic-bezier(.4,0,.2,1);transition:transform .18s cubic-bezier(.4,0,.2,1),border .18s cubic-bezier(.4,0,.2,1),box-shadow .18s cubic-bezier(.4,0,.2,1),background .28s cubic-bezier(.4,0,.2,1),-webkit-transform .18s cubic-bezier(.4,0,.2,1)}.mdl-slider.is-upgraded::-moz-range-thumb{-moz-appearance:none;width:12px;height:12px;box-sizing:border-box;border-radius:50%;background-image:none;background:#3f51b5;border:none}.mdl-slider.is-upgraded:focus:not(:active)::-webkit-slider-thumb{box-shadow:0 0 0 10px rgba(63,81,181,.26)}.mdl-slider.is-upgraded:focus:not(:active)::-moz-range-thumb{box-shadow:0 0 0 10px rgba(63,81,181,.26)}.mdl-slider.is-upgraded:active::-webkit-slider-thumb{background-image:none;background:#3f51b5;-webkit-transform:scale(1.5);transform:scale(1.5)}.mdl-slider.is-upgraded:active::-moz-range-thumb{background-image:none;background:#3f51b5;transform:scale(1.5)}.mdl-slider.is-upgraded::-ms-thumb{width:32px;height:32px;border:none;border-radius:50%;background:#3f51b5;transform:scale(.375);transition:transform .18s cubic-bezier(.4,0,.2,1),background .28s cubic-bezier(.4,0,.2,1);transition:transform .18s cubic-bezier(.4,0,.2,1),background .28s cubic-bezier(.4,0,.2,1),-webkit-transform .18s cubic-bezier(.4,0,.2,1)}.mdl-slider.is-upgraded:focus:not(:active)::-ms-thumb{background:radial-gradient(circle closest-side,#3f51b5 0%,#3f51b5 37.5%,rgba(63,81,181,.26)37.5%,rgba(63,81,181,.26)100%);transform:scale(1)}.mdl-slider.is-upgraded:active::-ms-thumb{background:#3f51b5;transform:scale(.5625)}.mdl-slider.is-upgraded.is-lowest-value::-webkit-slider-thumb{border:2px solid rgba(0,0,0,.26);background:0 0}.mdl-slider.is-upgraded.is-lowest-value::-moz-range-thumb{border:2px solid rgba(0,0,0,.26);background:0 0}.mdl-slider.is-upgraded.is-lowest-value+.mdl-slider__background-flex>.mdl-slider__background-upper{left:6px}.mdl-slider.is-upgraded.is-lowest-value:focus:not(:active)::-webkit-slider-thumb{box-shadow:0 0 0 10px rgba(0,0,0,.12);background:rgba(0,0,0,.12)}.mdl-slider.is-upgraded.is-lowest-value:focus:not(:active)::-moz-range-thumb{box-shadow:0 0 0 10px rgba(0,0,0,.12);background:rgba(0,0,0,.12)}.mdl-slider.is-upgraded.is-lowest-value:active::-webkit-slider-thumb{border:1.6px solid rgba(0,0,0,.26);-webkit-transform:scale(1.5);transform:scale(1.5)}.mdl-slider.is-upgraded.is-lowest-value:active+.mdl-slider__background-flex>.mdl-slider__background-upper{left:9px}.mdl-slider.is-upgraded.is-lowest-value:active::-moz-range-thumb{border:1.5px solid rgba(0,0,0,.26);transform:scale(1.5)}.mdl-slider.is-upgraded.is-lowest-value::-ms-thumb{background:radial-gradient(circle closest-side,transparent 0%,transparent 66.67%,rgba(0,0,0,.26)66.67%,rgba(0,0,0,.26)100%)}.mdl-slider.is-upgraded.is-lowest-value:focus:not(:active)::-ms-thumb{background:radial-gradient(circle closest-side,rgba(0,0,0,.12)0%,rgba(0,0,0,.12)25%,rgba(0,0,0,.26)25%,rgba(0,0,0,.26)37.5%,rgba(0,0,0,.12)37.5%,rgba(0,0,0,.12)100%);transform:scale(1)}.mdl-slider.is-upgraded.is-lowest-value:active::-ms-thumb{transform:scale(.5625);background:radial-gradient(circle closest-side,transparent 0%,transparent 77.78%,rgba(0,0,0,.26)77.78%,rgba(0,0,0,.26)100%)}.mdl-slider.is-upgraded.is-lowest-value::-ms-fill-lower{background:0 0}.mdl-slider.is-upgraded.is-lowest-value::-ms-fill-upper{margin-left:6px}.mdl-slider.is-upgraded.is-lowest-value:active::-ms-fill-upper{margin-left:9px}.mdl-slider.is-upgraded:disabled:focus::-webkit-slider-thumb,.mdl-slider.is-upgraded:disabled:active::-webkit-slider-thumb,.mdl-slider.is-upgraded:disabled::-webkit-slider-thumb{-webkit-transform:scale(.667);transform:scale(.667);background:rgba(0,0,0,.26)}.mdl-slider.is-upgraded:disabled:focus::-moz-range-thumb,.mdl-slider.is-upgraded:disabled:active::-moz-range-thumb,.mdl-slider.is-upgraded:disabled::-moz-range-thumb{transform:scale(.667);background:rgba(0,0,0,.26)}.mdl-slider.is-upgraded:disabled+.mdl-slider__background-flex>.mdl-slider__background-lower{background-color:rgba(0,0,0,.26);left:-6px}.mdl-slider.is-upgraded:disabled+.mdl-slider__background-flex>.mdl-slider__background-upper{left:6px}.mdl-slider.is-upgraded.is-lowest-value:disabled:focus::-webkit-slider-thumb,.mdl-slider.is-upgraded.is-lowest-value:disabled:active::-webkit-slider-thumb,.mdl-slider.is-upgraded.is-lowest-value:disabled::-webkit-slider-thumb{border:3px solid rgba(0,0,0,.26);background:0 0;-webkit-transform:scale(.667);transform:scale(.667)}.mdl-slider.is-upgraded.is-lowest-value:disabled:focus::-moz-range-thumb,.mdl-slider.is-upgraded.is-lowest-value:disabled:active::-moz-range-thumb,.mdl-slider.is-upgraded.is-lowest-value:disabled::-moz-range-thumb{border:3px solid rgba(0,0,0,.26);background:0 0;transform:scale(.667)}.mdl-slider.is-upgraded.is-lowest-value:disabled:active+.mdl-slider__background-flex>.mdl-slider__background-upper{left:6px}.mdl-slider.is-upgraded:disabled:focus::-ms-thumb,.mdl-slider.is-upgraded:disabled:active::-ms-thumb,.mdl-slider.is-upgraded:disabled::-ms-thumb{transform:scale(.25);background:rgba(0,0,0,.26)}.mdl-slider.is-upgraded.is-lowest-value:disabled:focus::-ms-thumb,.mdl-slider.is-upgraded.is-lowest-value:disabled:active::-ms-thumb,.mdl-slider.is-upgraded.is-lowest-value:disabled::-ms-thumb{transform:scale(.25);background:radial-gradient(circle closest-side,transparent 0%,transparent 50%,rgba(0,0,0,.26)50%,rgba(0,0,0,.26)100%)}.mdl-slider.is-upgraded:disabled::-ms-fill-lower{margin-right:6px;background:linear-gradient(to right,transparent,transparent 25px,rgba(0,0,0,.26)25px,rgba(0,0,0,.26)0)}.mdl-slider.is-upgraded:disabled::-ms-fill-upper{margin-left:6px}.mdl-slider.is-upgraded.is-lowest-value:disabled:active::-ms-fill-upper{margin-left:6px}.mdl-slider__ie-container{height:18px;overflow:visible;border:none;margin:none;padding:none}.mdl-slider__container{height:18px;position:relative;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row}.mdl-slider__container,.mdl-slider__background-flex{background:0 0;display:-webkit-flex;display:-ms-flexbox;display:flex}.mdl-slider__background-flex{position:absolute;height:2px;width:calc(100% - 52px);top:50%;left:0;margin:0 26px;overflow:hidden;border:0;padding:0;-webkit-transform:translate(0,-1px);transform:translate(0,-1px)}.mdl-slider__background-lower{background:#3f51b5}.mdl-slider__background-lower,.mdl-slider__background-upper{-webkit-flex:0;-ms-flex:0;flex:0;position:relative;border:0;padding:0}.mdl-slider__background-upper{background:rgba(0,0,0,.26);transition:left .18s cubic-bezier(.4,0,.2,1)}.mdl-snackbar{position:fixed;bottom:0;left:50%;cursor:default;background-color:#323232;z-index:3;display:block;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-justify-content:space-between;-ms-flex-pack:justify;justify-content:space-between;font-family:"Roboto","Helvetica","Arial",sans-serif;will-change:transform;-webkit-transform:translate(0,80px);transform:translate(0,80px);transition:transform .25s cubic-bezier(.4,0,1,1);transition:transform .25s cubic-bezier(.4,0,1,1),-webkit-transform .25s cubic-bezier(.4,0,1,1);pointer-events:none}@media (max-width:479px){.mdl-snackbar{width:100%;left:0;min-height:48px;max-height:80px}}@media (min-width:480px){.mdl-snackbar{min-width:288px;max-width:568px;border-radius:2px;-webkit-transform:translate(-50%,80px);transform:translate(-50%,80px)}}.mdl-snackbar--active{-webkit-transform:translate(0,0);transform:translate(0,0);pointer-events:auto;transition:transform .25s cubic-bezier(0,0,.2,1);transition:transform .25s cubic-bezier(0,0,.2,1),-webkit-transform .25s cubic-bezier(0,0,.2,1)}@media (min-width:480px){.mdl-snackbar--active{-webkit-transform:translate(-50%,0);transform:translate(-50%,0)}}.mdl-snackbar__text{padding:14px 12px 14px 24px;vertical-align:middle;color:#fff;float:left}.mdl-snackbar__action{background:0 0;border:none;color:#ff4081;float:right;padding:14px 24px 14px 12px;font-family:"Roboto","Helvetica","Arial",sans-serif;font-size:14px;font-weight:500;text-transform:uppercase;line-height:1;letter-spacing:0;overflow:hidden;outline:none;opacity:0;pointer-events:none;cursor:pointer;text-decoration:none;text-align:center;-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.mdl-snackbar__action::-moz-focus-inner{border:0}.mdl-snackbar__action:not([aria-hidden]){opacity:1;pointer-events:auto}.mdl-spinner{display:inline-block;position:relative;width:28px;height:28px}.mdl-spinner:not(.is-upgraded).is-active:after{content:"Loading..."}.mdl-spinner.is-upgraded.is-active{-webkit-animation:mdl-spinner__container-rotate 1568.23529412ms linear infinite;animation:mdl-spinner__container-rotate 1568.23529412ms linear infinite}@-webkit-keyframes mdl-spinner__container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes mdl-spinner__container-rotate{to{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}.mdl-spinner__layer{position:absolute;width:100%;height:100%;opacity:0}.mdl-spinner__layer-1{border-color:#42a5f5}.mdl-spinner--single-color .mdl-spinner__layer-1{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-1{-webkit-animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both;animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-1-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both}.mdl-spinner__layer-2{border-color:#f44336}.mdl-spinner--single-color .mdl-spinner__layer-2{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-2{-webkit-animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both;animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-2-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both}.mdl-spinner__layer-3{border-color:#fdd835}.mdl-spinner--single-color .mdl-spinner__layer-3{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-3{-webkit-animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both;animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-3-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both}.mdl-spinner__layer-4{border-color:#4caf50}.mdl-spinner--single-color .mdl-spinner__layer-4{border-color:#3f51b5}.mdl-spinner.is-active .mdl-spinner__layer-4{-webkit-animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both;animation:mdl-spinner__fill-unfill-rotate 5332ms cubic-bezier(.4,0,.2,1)infinite both,mdl-spinner__layer-4-fade-in-out 5332ms cubic-bezier(.4,0,.2,1)infinite both}@-webkit-keyframes mdl-spinner__fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@keyframes mdl-spinner__fill-unfill-rotate{12.5%{-webkit-transform:rotate(135deg);transform:rotate(135deg)}25%{-webkit-transform:rotate(270deg);transform:rotate(270deg)}37.5%{-webkit-transform:rotate(405deg);transform:rotate(405deg)}50%{-webkit-transform:rotate(540deg);transform:rotate(540deg)}62.5%{-webkit-transform:rotate(675deg);transform:rotate(675deg)}75%{-webkit-transform:rotate(810deg);transform:rotate(810deg)}87.5%{-webkit-transform:rotate(945deg);transform:rotate(945deg)}to{-webkit-transform:rotate(1080deg);transform:rotate(1080deg)}}@-webkit-keyframes mdl-spinner__layer-1-fade-in-out{from,25%{opacity:.99}26%,89%{opacity:0}90%,100%{opacity:.99}}@keyframes mdl-spinner__layer-1-fade-in-out{from,25%{opacity:.99}26%,89%{opacity:0}90%,100%{opacity:.99}}@-webkit-keyframes mdl-spinner__layer-2-fade-in-out{from,15%{opacity:0}25%,50%{opacity:.99}51%{opacity:0}}@keyframes mdl-spinner__layer-2-fade-in-out{from,15%{opacity:0}25%,50%{opacity:.99}51%{opacity:0}}@-webkit-keyframes mdl-spinner__layer-3-fade-in-out{from,40%{opacity:0}50%,75%{opacity:.99}76%{opacity:0}}@keyframes mdl-spinner__layer-3-fade-in-out{from,40%{opacity:0}50%,75%{opacity:.99}76%{opacity:0}}@-webkit-keyframes mdl-spinner__layer-4-fade-in-out{from,65%{opacity:0}75%,90%{opacity:.99}100%{opacity:0}}@keyframes mdl-spinner__layer-4-fade-in-out{from,65%{opacity:0}75%,90%{opacity:.99}100%{opacity:0}}.mdl-spinner__gap-patch{position:absolute;box-sizing:border-box;top:0;left:45%;width:10%;height:100%;overflow:hidden;border-color:inherit}.mdl-spinner__gap-patch .mdl-spinner__circle{width:1000%;left:-450%}.mdl-spinner__circle-clipper{display:inline-block;position:relative;width:50%;height:100%;overflow:hidden;border-color:inherit}.mdl-spinner__circle-clipper .mdl-spinner__circle{width:200%}.mdl-spinner__circle{box-sizing:border-box;height:100%;border-width:3px;border-style:solid;border-color:inherit;border-bottom-color:transparent!important;border-radius:50%;-webkit-animation:none;animation:none;position:absolute;top:0;right:0;bottom:0;left:0}.mdl-spinner__left .mdl-spinner__circle{border-right-color:transparent!important;-webkit-transform:rotate(129deg);transform:rotate(129deg)}.mdl-spinner.is-active .mdl-spinner__left .mdl-spinner__circle{-webkit-animation:mdl-spinner__left-spin 1333ms cubic-bezier(.4,0,.2,1)infinite both;animation:mdl-spinner__left-spin 1333ms cubic-bezier(.4,0,.2,1)infinite both}.mdl-spinner__right .mdl-spinner__circle{left:-100%;border-left-color:transparent!important;-webkit-transform:rotate(-129deg);transform:rotate(-129deg)}.mdl-spinner.is-active .mdl-spinner__right .mdl-spinner__circle{-webkit-animation:mdl-spinner__right-spin 1333ms cubic-bezier(.4,0,.2,1)infinite both;animation:mdl-spinner__right-spin 1333ms cubic-bezier(.4,0,.2,1)infinite both}@-webkit-keyframes mdl-spinner__left-spin{from{-webkit-transform:rotate(130deg);transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg);transform:rotate(130deg)}}@keyframes mdl-spinner__left-spin{from{-webkit-transform:rotate(130deg);transform:rotate(130deg)}50%{-webkit-transform:rotate(-5deg);transform:rotate(-5deg)}to{-webkit-transform:rotate(130deg);transform:rotate(130deg)}}@-webkit-keyframes mdl-spinner__right-spin{from{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}}@keyframes mdl-spinner__right-spin{from{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}50%{-webkit-transform:rotate(5deg);transform:rotate(5deg)}to{-webkit-transform:rotate(-130deg);transform:rotate(-130deg)}}.mdl-switch{position:relative;z-index:1;vertical-align:middle;display:inline-block;box-sizing:border-box;width:100%;height:24px;margin:0;padding:0;overflow:visible;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdl-switch.is-upgraded{padding-left:28px}.mdl-switch__input{line-height:24px}.mdl-switch.is-upgraded .mdl-switch__input{position:absolute;width:0;height:0;margin:0;padding:0;opacity:0;-ms-appearance:none;-moz-appearance:none;-webkit-appearance:none;appearance:none;border:none}.mdl-switch__track{background:rgba(0,0,0,.26);position:absolute;left:0;top:5px;height:14px;width:36px;border-radius:14px;cursor:pointer}.mdl-switch.is-checked .mdl-switch__track{background:rgba(63,81,181,.5)}.mdl-switch__track fieldset[disabled] .mdl-switch,.mdl-switch.is-disabled .mdl-switch__track{background:rgba(0,0,0,.12);cursor:auto}.mdl-switch__thumb{background:#fafafa;position:absolute;left:0;top:2px;height:20px;width:20px;border-radius:50%;cursor:pointer;box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12);transition-duration:.28s;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-property:left}.mdl-switch.is-checked .mdl-switch__thumb{background:#3f51b5;left:16px;box-shadow:0 3px 4px 0 rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.2),0 1px 8px 0 rgba(0,0,0,.12)}.mdl-switch__thumb fieldset[disabled] .mdl-switch,.mdl-switch.is-disabled .mdl-switch__thumb{background:#bdbdbd;cursor:auto}.mdl-switch__focus-helper{position:absolute;top:50%;left:50%;-webkit-transform:translate(-4px,-4px);transform:translate(-4px,-4px);display:inline-block;box-sizing:border-box;width:8px;height:8px;border-radius:50%;background-color:transparent}.mdl-switch.is-focused .mdl-switch__focus-helper{box-shadow:0 0 0 20px rgba(0,0,0,.1);background-color:rgba(0,0,0,.1)}.mdl-switch.is-focused.is-checked .mdl-switch__focus-helper{box-shadow:0 0 0 20px rgba(63,81,181,.26);background-color:rgba(63,81,181,.26)}.mdl-switch__label{position:relative;cursor:pointer;font-size:16px;line-height:24px;margin:0;left:24px}.mdl-switch__label fieldset[disabled] .mdl-switch,.mdl-switch.is-disabled .mdl-switch__label{color:#bdbdbd;cursor:auto}.mdl-switch__ripple-container{position:absolute;z-index:2;top:-12px;left:-14px;box-sizing:border-box;width:48px;height:48px;border-radius:50%;cursor:pointer;overflow:hidden;-webkit-mask-image:-webkit-radial-gradient(circle,#fff,#000);transition-duration:.4s;transition-timing-function:step-end;transition-property:left}.mdl-switch__ripple-container .mdl-ripple{background:#3f51b5}.mdl-switch__ripple-container fieldset[disabled] .mdl-switch,.mdl-switch.is-disabled .mdl-switch__ripple-container{cursor:auto}fieldset[disabled] .mdl-switch .mdl-switch__ripple-container .mdl-ripple,.mdl-switch.is-disabled .mdl-switch__ripple-container .mdl-ripple{background:0 0}.mdl-switch.is-checked .mdl-switch__ripple-container{left:2px}.mdl-tabs{display:block;width:100%}.mdl-tabs__tab-bar{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-direction:row;-ms-flex-direction:row;flex-direction:row;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;-webkit-align-content:space-between;-ms-flex-line-pack:justify;align-content:space-between;-webkit-align-items:flex-start;-ms-flex-align:start;align-items:flex-start;height:48px;padding:0;margin:0;border-bottom:1px solid #e0e0e0}.mdl-tabs__tab{margin:0;border:none;padding:0 24px;float:left;position:relative;display:block;text-decoration:none;height:48px;line-height:48px;text-align:center;font-weight:500;font-size:14px;text-transform:uppercase;color:rgba(0,0,0,.54);overflow:hidden}.mdl-tabs.is-upgraded .mdl-tabs__tab.is-active{color:rgba(0,0,0,.87)}.mdl-tabs.is-upgraded .mdl-tabs__tab.is-active:after{height:2px;width:100%;display:block;content:" ";bottom:0;left:0;position:absolute;background:#3f51b5;-webkit-animation:border-expand .2s cubic-bezier(.4,0,.4,1).01s alternate forwards;animation:border-expand .2s cubic-bezier(.4,0,.4,1).01s alternate forwards;transition:all 1s cubic-bezier(.4,0,1,1)}.mdl-tabs__tab .mdl-tabs__ripple-container{display:block;position:absolute;height:100%;width:100%;left:0;top:0;z-index:1;overflow:hidden}.mdl-tabs__tab .mdl-tabs__ripple-container .mdl-ripple{background:#3f51b5}.mdl-tabs__panel{display:block}.mdl-tabs.is-upgraded .mdl-tabs__panel{display:none}.mdl-tabs.is-upgraded .mdl-tabs__panel.is-active{display:block}@-webkit-keyframes border-expand{0%{opacity:0;width:0}100%{opacity:1;width:100%}}@keyframes border-expand{0%{opacity:0;width:0}100%{opacity:1;width:100%}}.mdl-textfield{position:relative;font-size:16px;display:inline-block;box-sizing:border-box;width:300px;max-width:100%;margin:0;padding:20px 0}.mdl-textfield .mdl-button{position:absolute;bottom:20px}.mdl-textfield--align-right{text-align:right}.mdl-textfield--full-width{width:100%}.mdl-textfield--expandable{min-width:32px;width:auto;min-height:32px}.mdl-textfield__input{border:none;border-bottom:1px solid rgba(0,0,0,.12);display:block;font-size:16px;font-family:"Helvetica","Arial",sans-serif;margin:0;padding:4px 0;width:100%;background:0 0;text-align:left;color:inherit}.mdl-textfield__input[type="number"]{-moz-appearance:textfield}.mdl-textfield__input[type="number"]::-webkit-inner-spin-button,.mdl-textfield__input[type="number"]::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.mdl-textfield.is-focused .mdl-textfield__input{outline:none}.mdl-textfield.is-invalid .mdl-textfield__input{border-color:#d50000;box-shadow:none}fieldset[disabled] .mdl-textfield .mdl-textfield__input,.mdl-textfield.is-disabled .mdl-textfield__input{background-color:transparent;border-bottom:1px dotted rgba(0,0,0,.12);color:rgba(0,0,0,.26)}.mdl-textfield textarea.mdl-textfield__input{display:block}.mdl-textfield__label{bottom:0;color:rgba(0,0,0,.26);font-size:16px;left:0;right:0;pointer-events:none;position:absolute;display:block;top:24px;width:100%;overflow:hidden;white-space:nowrap;text-align:left}.mdl-textfield.is-dirty .mdl-textfield__label,.mdl-textfield.has-placeholder .mdl-textfield__label{visibility:hidden}.mdl-textfield--floating-label .mdl-textfield__label{transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1)}.mdl-textfield--floating-label.has-placeholder .mdl-textfield__label{transition:none}fieldset[disabled] .mdl-textfield .mdl-textfield__label,.mdl-textfield.is-disabled.is-disabled .mdl-textfield__label{color:rgba(0,0,0,.26)}.mdl-textfield--floating-label.is-focused .mdl-textfield__label,.mdl-textfield--floating-label.is-dirty .mdl-textfield__label,.mdl-textfield--floating-label.has-placeholder .mdl-textfield__label{color:#3f51b5;font-size:12px;top:4px;visibility:visible}.mdl-textfield--floating-label.is-focused .mdl-textfield__expandable-holder .mdl-textfield__label,.mdl-textfield--floating-label.is-dirty .mdl-textfield__expandable-holder .mdl-textfield__label,.mdl-textfield--floating-label.has-placeholder .mdl-textfield__expandable-holder .mdl-textfield__label{top:-16px}.mdl-textfield--floating-label.is-invalid .mdl-textfield__label{color:#d50000;font-size:12px}.mdl-textfield__label:after{background-color:#3f51b5;bottom:20px;content:'';height:2px;left:45%;position:absolute;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);visibility:hidden;width:10px}.mdl-textfield.is-focused .mdl-textfield__label:after{left:0;visibility:visible;width:100%}.mdl-textfield.is-invalid .mdl-textfield__label:after{background-color:#d50000}.mdl-textfield__error{color:#d50000;position:absolute;font-size:12px;margin-top:3px;visibility:hidden;display:block}.mdl-textfield.is-invalid .mdl-textfield__error{visibility:visible}.mdl-textfield__expandable-holder{display:inline-block;position:relative;margin-left:32px;transition-duration:.2s;transition-timing-function:cubic-bezier(.4,0,.2,1);display:inline-block;max-width:.1px}.mdl-textfield.is-focused .mdl-textfield__expandable-holder,.mdl-textfield.is-dirty .mdl-textfield__expandable-holder{max-width:600px}.mdl-textfield__expandable-holder .mdl-textfield__label:after{bottom:0}.mdl-tooltip{-webkit-transform:scale(0);transform:scale(0);-webkit-transform-origin:top center;transform-origin:top center;will-change:transform;z-index:999;background:rgba(97,97,97,.9);border-radius:2px;color:#fff;display:inline-block;font-size:10px;font-weight:500;line-height:14px;max-width:170px;position:fixed;top:-500px;left:-500px;padding:8px;text-align:center}.mdl-tooltip.is-active{-webkit-animation:pulse 200ms cubic-bezier(0,0,.2,1)forwards;animation:pulse 200ms cubic-bezier(0,0,.2,1)forwards}.mdl-tooltip--large{line-height:14px;font-size:14px;padding:16px}@-webkit-keyframes pulse{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0}50%{-webkit-transform:scale(.99);transform:scale(.99)}100%{-webkit-transform:scale(1);transform:scale(1);opacity:1;visibility:visible}}@keyframes pulse{0%{-webkit-transform:scale(0);transform:scale(0);opacity:0}50%{-webkit-transform:scale(.99);transform:scale(.99)}100%{-webkit-transform:scale(1);transform:scale(1);opacity:1;visibility:visible}}.mdl-shadow--2dp{box-shadow:0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12)}.mdl-shadow--3dp{box-shadow:0 3px 4px 0 rgba(0,0,0,.14),0 3px 3px -2px rgba(0,0,0,.2),0 1px 8px 0 rgba(0,0,0,.12)}.mdl-shadow--4dp{box-shadow:0 4px 5px 0 rgba(0,0,0,.14),0 1px 10px 0 rgba(0,0,0,.12),0 2px 4px -1px rgba(0,0,0,.2)}.mdl-shadow--6dp{box-shadow:0 6px 10px 0 rgba(0,0,0,.14),0 1px 18px 0 rgba(0,0,0,.12),0 3px 5px -1px rgba(0,0,0,.2)}.mdl-shadow--8dp{box-shadow:0 8px 10px 1px rgba(0,0,0,.14),0 3px 14px 2px rgba(0,0,0,.12),0 5px 5px -3px rgba(0,0,0,.2)}.mdl-shadow--16dp{box-shadow:0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12),0 8px 10px -5px rgba(0,0,0,.2)}.mdl-shadow--24dp{box-shadow:0 9px 46px 8px rgba(0,0,0,.14),0 11px 15px -7px rgba(0,0,0,.12),0 24px 38px 3px rgba(0,0,0,.2)}.mdl-grid{display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-flow:row wrap;-ms-flex-flow:row wrap;flex-flow:row wrap;margin:0 auto;-webkit-align-items:stretch;-ms-flex-align:stretch;align-items:stretch}.mdl-grid.mdl-grid--no-spacing{padding:0}.mdl-cell{box-sizing:border-box}.mdl-cell--top{-webkit-align-self:flex-start;-ms-flex-item-align:start;align-self:flex-start}.mdl-cell--middle{-webkit-align-self:center;-ms-flex-item-align:center;align-self:center}.mdl-cell--bottom{-webkit-align-self:flex-end;-ms-flex-item-align:end;align-self:flex-end}.mdl-cell--stretch{-webkit-align-self:stretch;-ms-flex-item-align:stretch;align-self:stretch}.mdl-grid.mdl-grid--no-spacing>.mdl-cell{margin:0}.mdl-cell--order-1{-webkit-order:1;-ms-flex-order:1;order:1}.mdl-cell--order-2{-webkit-order:2;-ms-flex-order:2;order:2}.mdl-cell--order-3{-webkit-order:3;-ms-flex-order:3;order:3}.mdl-cell--order-4{-webkit-order:4;-ms-flex-order:4;order:4}.mdl-cell--order-5{-webkit-order:5;-ms-flex-order:5;order:5}.mdl-cell--order-6{-webkit-order:6;-ms-flex-order:6;order:6}.mdl-cell--order-7{-webkit-order:7;-ms-flex-order:7;order:7}.mdl-cell--order-8{-webkit-order:8;-ms-flex-order:8;order:8}.mdl-cell--order-9{-webkit-order:9;-ms-flex-order:9;order:9}.mdl-cell--order-10{-webkit-order:10;-ms-flex-order:10;order:10}.mdl-cell--order-11{-webkit-order:11;-ms-flex-order:11;order:11}.mdl-cell--order-12{-webkit-order:12;-ms-flex-order:12;order:12}@media (max-width:479px){.mdl-grid{padding:8px}.mdl-cell{margin:8px;width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell{width:100%}.mdl-cell--hide-phone{display:none!important}.mdl-cell--order-1-phone.mdl-cell--order-1-phone{-webkit-order:1;-ms-flex-order:1;order:1}.mdl-cell--order-2-phone.mdl-cell--order-2-phone{-webkit-order:2;-ms-flex-order:2;order:2}.mdl-cell--order-3-phone.mdl-cell--order-3-phone{-webkit-order:3;-ms-flex-order:3;order:3}.mdl-cell--order-4-phone.mdl-cell--order-4-phone{-webkit-order:4;-ms-flex-order:4;order:4}.mdl-cell--order-5-phone.mdl-cell--order-5-phone{-webkit-order:5;-ms-flex-order:5;order:5}.mdl-cell--order-6-phone.mdl-cell--order-6-phone{-webkit-order:6;-ms-flex-order:6;order:6}.mdl-cell--order-7-phone.mdl-cell--order-7-phone{-webkit-order:7;-ms-flex-order:7;order:7}.mdl-cell--order-8-phone.mdl-cell--order-8-phone{-webkit-order:8;-ms-flex-order:8;order:8}.mdl-cell--order-9-phone.mdl-cell--order-9-phone{-webkit-order:9;-ms-flex-order:9;order:9}.mdl-cell--order-10-phone.mdl-cell--order-10-phone{-webkit-order:10;-ms-flex-order:10;order:10}.mdl-cell--order-11-phone.mdl-cell--order-11-phone{-webkit-order:11;-ms-flex-order:11;order:11}.mdl-cell--order-12-phone.mdl-cell--order-12-phone{-webkit-order:12;-ms-flex-order:12;order:12}.mdl-cell--1-col,.mdl-cell--1-col-phone.mdl-cell--1-col-phone{width:calc(25% - 16px)}.mdl-grid--no-spacing>.mdl-cell--1-col,.mdl-grid--no-spacing>.mdl-cell--1-col-phone.mdl-cell--1-col-phone{width:25%}.mdl-cell--2-col,.mdl-cell--2-col-phone.mdl-cell--2-col-phone{width:calc(50% - 16px)}.mdl-grid--no-spacing>.mdl-cell--2-col,.mdl-grid--no-spacing>.mdl-cell--2-col-phone.mdl-cell--2-col-phone{width:50%}.mdl-cell--3-col,.mdl-cell--3-col-phone.mdl-cell--3-col-phone{width:calc(75% - 16px)}.mdl-grid--no-spacing>.mdl-cell--3-col,.mdl-grid--no-spacing>.mdl-cell--3-col-phone.mdl-cell--3-col-phone{width:75%}.mdl-cell--4-col,.mdl-cell--4-col-phone.mdl-cell--4-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--4-col,.mdl-grid--no-spacing>.mdl-cell--4-col-phone.mdl-cell--4-col-phone{width:100%}.mdl-cell--5-col,.mdl-cell--5-col-phone.mdl-cell--5-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--5-col,.mdl-grid--no-spacing>.mdl-cell--5-col-phone.mdl-cell--5-col-phone{width:100%}.mdl-cell--6-col,.mdl-cell--6-col-phone.mdl-cell--6-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--6-col,.mdl-grid--no-spacing>.mdl-cell--6-col-phone.mdl-cell--6-col-phone{width:100%}.mdl-cell--7-col,.mdl-cell--7-col-phone.mdl-cell--7-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--7-col,.mdl-grid--no-spacing>.mdl-cell--7-col-phone.mdl-cell--7-col-phone{width:100%}.mdl-cell--8-col,.mdl-cell--8-col-phone.mdl-cell--8-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--8-col,.mdl-grid--no-spacing>.mdl-cell--8-col-phone.mdl-cell--8-col-phone{width:100%}.mdl-cell--9-col,.mdl-cell--9-col-phone.mdl-cell--9-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--9-col,.mdl-grid--no-spacing>.mdl-cell--9-col-phone.mdl-cell--9-col-phone{width:100%}.mdl-cell--10-col,.mdl-cell--10-col-phone.mdl-cell--10-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--10-col,.mdl-grid--no-spacing>.mdl-cell--10-col-phone.mdl-cell--10-col-phone{width:100%}.mdl-cell--11-col,.mdl-cell--11-col-phone.mdl-cell--11-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--11-col,.mdl-grid--no-spacing>.mdl-cell--11-col-phone.mdl-cell--11-col-phone{width:100%}.mdl-cell--12-col,.mdl-cell--12-col-phone.mdl-cell--12-col-phone{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--12-col,.mdl-grid--no-spacing>.mdl-cell--12-col-phone.mdl-cell--12-col-phone{width:100%}.mdl-cell--1-offset,.mdl-cell--1-offset-phone.mdl-cell--1-offset-phone{margin-left:calc(25% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--1-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--1-offset-phone.mdl-cell--1-offset-phone{margin-left:25%}.mdl-cell--2-offset,.mdl-cell--2-offset-phone.mdl-cell--2-offset-phone{margin-left:calc(50% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--2-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--2-offset-phone.mdl-cell--2-offset-phone{margin-left:50%}.mdl-cell--3-offset,.mdl-cell--3-offset-phone.mdl-cell--3-offset-phone{margin-left:calc(75% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--3-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--3-offset-phone.mdl-cell--3-offset-phone{margin-left:75%}}@media (min-width:480px) and (max-width:839px){.mdl-grid{padding:8px}.mdl-cell{margin:8px;width:calc(50% - 16px)}.mdl-grid--no-spacing>.mdl-cell{width:50%}.mdl-cell--hide-tablet{display:none!important}.mdl-cell--order-1-tablet.mdl-cell--order-1-tablet{-webkit-order:1;-ms-flex-order:1;order:1}.mdl-cell--order-2-tablet.mdl-cell--order-2-tablet{-webkit-order:2;-ms-flex-order:2;order:2}.mdl-cell--order-3-tablet.mdl-cell--order-3-tablet{-webkit-order:3;-ms-flex-order:3;order:3}.mdl-cell--order-4-tablet.mdl-cell--order-4-tablet{-webkit-order:4;-ms-flex-order:4;order:4}.mdl-cell--order-5-tablet.mdl-cell--order-5-tablet{-webkit-order:5;-ms-flex-order:5;order:5}.mdl-cell--order-6-tablet.mdl-cell--order-6-tablet{-webkit-order:6;-ms-flex-order:6;order:6}.mdl-cell--order-7-tablet.mdl-cell--order-7-tablet{-webkit-order:7;-ms-flex-order:7;order:7}.mdl-cell--order-8-tablet.mdl-cell--order-8-tablet{-webkit-order:8;-ms-flex-order:8;order:8}.mdl-cell--order-9-tablet.mdl-cell--order-9-tablet{-webkit-order:9;-ms-flex-order:9;order:9}.mdl-cell--order-10-tablet.mdl-cell--order-10-tablet{-webkit-order:10;-ms-flex-order:10;order:10}.mdl-cell--order-11-tablet.mdl-cell--order-11-tablet{-webkit-order:11;-ms-flex-order:11;order:11}.mdl-cell--order-12-tablet.mdl-cell--order-12-tablet{-webkit-order:12;-ms-flex-order:12;order:12}.mdl-cell--1-col,.mdl-cell--1-col-tablet.mdl-cell--1-col-tablet{width:calc(12.5% - 16px)}.mdl-grid--no-spacing>.mdl-cell--1-col,.mdl-grid--no-spacing>.mdl-cell--1-col-tablet.mdl-cell--1-col-tablet{width:12.5%}.mdl-cell--2-col,.mdl-cell--2-col-tablet.mdl-cell--2-col-tablet{width:calc(25% - 16px)}.mdl-grid--no-spacing>.mdl-cell--2-col,.mdl-grid--no-spacing>.mdl-cell--2-col-tablet.mdl-cell--2-col-tablet{width:25%}.mdl-cell--3-col,.mdl-cell--3-col-tablet.mdl-cell--3-col-tablet{width:calc(37.5% - 16px)}.mdl-grid--no-spacing>.mdl-cell--3-col,.mdl-grid--no-spacing>.mdl-cell--3-col-tablet.mdl-cell--3-col-tablet{width:37.5%}.mdl-cell--4-col,.mdl-cell--4-col-tablet.mdl-cell--4-col-tablet{width:calc(50% - 16px)}.mdl-grid--no-spacing>.mdl-cell--4-col,.mdl-grid--no-spacing>.mdl-cell--4-col-tablet.mdl-cell--4-col-tablet{width:50%}.mdl-cell--5-col,.mdl-cell--5-col-tablet.mdl-cell--5-col-tablet{width:calc(62.5% - 16px)}.mdl-grid--no-spacing>.mdl-cell--5-col,.mdl-grid--no-spacing>.mdl-cell--5-col-tablet.mdl-cell--5-col-tablet{width:62.5%}.mdl-cell--6-col,.mdl-cell--6-col-tablet.mdl-cell--6-col-tablet{width:calc(75% - 16px)}.mdl-grid--no-spacing>.mdl-cell--6-col,.mdl-grid--no-spacing>.mdl-cell--6-col-tablet.mdl-cell--6-col-tablet{width:75%}.mdl-cell--7-col,.mdl-cell--7-col-tablet.mdl-cell--7-col-tablet{width:calc(87.5% - 16px)}.mdl-grid--no-spacing>.mdl-cell--7-col,.mdl-grid--no-spacing>.mdl-cell--7-col-tablet.mdl-cell--7-col-tablet{width:87.5%}.mdl-cell--8-col,.mdl-cell--8-col-tablet.mdl-cell--8-col-tablet{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--8-col,.mdl-grid--no-spacing>.mdl-cell--8-col-tablet.mdl-cell--8-col-tablet{width:100%}.mdl-cell--9-col,.mdl-cell--9-col-tablet.mdl-cell--9-col-tablet{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--9-col,.mdl-grid--no-spacing>.mdl-cell--9-col-tablet.mdl-cell--9-col-tablet{width:100%}.mdl-cell--10-col,.mdl-cell--10-col-tablet.mdl-cell--10-col-tablet{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--10-col,.mdl-grid--no-spacing>.mdl-cell--10-col-tablet.mdl-cell--10-col-tablet{width:100%}.mdl-cell--11-col,.mdl-cell--11-col-tablet.mdl-cell--11-col-tablet{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--11-col,.mdl-grid--no-spacing>.mdl-cell--11-col-tablet.mdl-cell--11-col-tablet{width:100%}.mdl-cell--12-col,.mdl-cell--12-col-tablet.mdl-cell--12-col-tablet{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--12-col,.mdl-grid--no-spacing>.mdl-cell--12-col-tablet.mdl-cell--12-col-tablet{width:100%}.mdl-cell--1-offset,.mdl-cell--1-offset-tablet.mdl-cell--1-offset-tablet{margin-left:calc(12.5% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--1-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--1-offset-tablet.mdl-cell--1-offset-tablet{margin-left:12.5%}.mdl-cell--2-offset,.mdl-cell--2-offset-tablet.mdl-cell--2-offset-tablet{margin-left:calc(25% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--2-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--2-offset-tablet.mdl-cell--2-offset-tablet{margin-left:25%}.mdl-cell--3-offset,.mdl-cell--3-offset-tablet.mdl-cell--3-offset-tablet{margin-left:calc(37.5% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--3-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--3-offset-tablet.mdl-cell--3-offset-tablet{margin-left:37.5%}.mdl-cell--4-offset,.mdl-cell--4-offset-tablet.mdl-cell--4-offset-tablet{margin-left:calc(50% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--4-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--4-offset-tablet.mdl-cell--4-offset-tablet{margin-left:50%}.mdl-cell--5-offset,.mdl-cell--5-offset-tablet.mdl-cell--5-offset-tablet{margin-left:calc(62.5% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--5-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--5-offset-tablet.mdl-cell--5-offset-tablet{margin-left:62.5%}.mdl-cell--6-offset,.mdl-cell--6-offset-tablet.mdl-cell--6-offset-tablet{margin-left:calc(75% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--6-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--6-offset-tablet.mdl-cell--6-offset-tablet{margin-left:75%}.mdl-cell--7-offset,.mdl-cell--7-offset-tablet.mdl-cell--7-offset-tablet{margin-left:calc(87.5% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--7-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--7-offset-tablet.mdl-cell--7-offset-tablet{margin-left:87.5%}}@media (min-width:840px){.mdl-grid{padding:8px}.mdl-cell{margin:8px;width:calc(33.3333333333% - 16px)}.mdl-grid--no-spacing>.mdl-cell{width:33.3333333333%}.mdl-cell--hide-desktop{display:none!important}.mdl-cell--order-1-desktop.mdl-cell--order-1-desktop{-webkit-order:1;-ms-flex-order:1;order:1}.mdl-cell--order-2-desktop.mdl-cell--order-2-desktop{-webkit-order:2;-ms-flex-order:2;order:2}.mdl-cell--order-3-desktop.mdl-cell--order-3-desktop{-webkit-order:3;-ms-flex-order:3;order:3}.mdl-cell--order-4-desktop.mdl-cell--order-4-desktop{-webkit-order:4;-ms-flex-order:4;order:4}.mdl-cell--order-5-desktop.mdl-cell--order-5-desktop{-webkit-order:5;-ms-flex-order:5;order:5}.mdl-cell--order-6-desktop.mdl-cell--order-6-desktop{-webkit-order:6;-ms-flex-order:6;order:6}.mdl-cell--order-7-desktop.mdl-cell--order-7-desktop{-webkit-order:7;-ms-flex-order:7;order:7}.mdl-cell--order-8-desktop.mdl-cell--order-8-desktop{-webkit-order:8;-ms-flex-order:8;order:8}.mdl-cell--order-9-desktop.mdl-cell--order-9-desktop{-webkit-order:9;-ms-flex-order:9;order:9}.mdl-cell--order-10-desktop.mdl-cell--order-10-desktop{-webkit-order:10;-ms-flex-order:10;order:10}.mdl-cell--order-11-desktop.mdl-cell--order-11-desktop{-webkit-order:11;-ms-flex-order:11;order:11}.mdl-cell--order-12-desktop.mdl-cell--order-12-desktop{-webkit-order:12;-ms-flex-order:12;order:12}.mdl-cell--1-col,.mdl-cell--1-col-desktop.mdl-cell--1-col-desktop{width:calc(8.3333333333% - 16px)}.mdl-grid--no-spacing>.mdl-cell--1-col,.mdl-grid--no-spacing>.mdl-cell--1-col-desktop.mdl-cell--1-col-desktop{width:8.3333333333%}.mdl-cell--2-col,.mdl-cell--2-col-desktop.mdl-cell--2-col-desktop{width:calc(16.6666666667% - 16px)}.mdl-grid--no-spacing>.mdl-cell--2-col,.mdl-grid--no-spacing>.mdl-cell--2-col-desktop.mdl-cell--2-col-desktop{width:16.6666666667%}.mdl-cell--3-col,.mdl-cell--3-col-desktop.mdl-cell--3-col-desktop{width:calc(25% - 16px)}.mdl-grid--no-spacing>.mdl-cell--3-col,.mdl-grid--no-spacing>.mdl-cell--3-col-desktop.mdl-cell--3-col-desktop{width:25%}.mdl-cell--4-col,.mdl-cell--4-col-desktop.mdl-cell--4-col-desktop{width:calc(33.3333333333% - 16px)}.mdl-grid--no-spacing>.mdl-cell--4-col,.mdl-grid--no-spacing>.mdl-cell--4-col-desktop.mdl-cell--4-col-desktop{width:33.3333333333%}.mdl-cell--5-col,.mdl-cell--5-col-desktop.mdl-cell--5-col-desktop{width:calc(41.6666666667% - 16px)}.mdl-grid--no-spacing>.mdl-cell--5-col,.mdl-grid--no-spacing>.mdl-cell--5-col-desktop.mdl-cell--5-col-desktop{width:41.6666666667%}.mdl-cell--6-col,.mdl-cell--6-col-desktop.mdl-cell--6-col-desktop{width:calc(50% - 16px)}.mdl-grid--no-spacing>.mdl-cell--6-col,.mdl-grid--no-spacing>.mdl-cell--6-col-desktop.mdl-cell--6-col-desktop{width:50%}.mdl-cell--7-col,.mdl-cell--7-col-desktop.mdl-cell--7-col-desktop{width:calc(58.3333333333% - 16px)}.mdl-grid--no-spacing>.mdl-cell--7-col,.mdl-grid--no-spacing>.mdl-cell--7-col-desktop.mdl-cell--7-col-desktop{width:58.3333333333%}.mdl-cell--8-col,.mdl-cell--8-col-desktop.mdl-cell--8-col-desktop{width:calc(66.6666666667% - 16px)}.mdl-grid--no-spacing>.mdl-cell--8-col,.mdl-grid--no-spacing>.mdl-cell--8-col-desktop.mdl-cell--8-col-desktop{width:66.6666666667%}.mdl-cell--9-col,.mdl-cell--9-col-desktop.mdl-cell--9-col-desktop{width:calc(75% - 16px)}.mdl-grid--no-spacing>.mdl-cell--9-col,.mdl-grid--no-spacing>.mdl-cell--9-col-desktop.mdl-cell--9-col-desktop{width:75%}.mdl-cell--10-col,.mdl-cell--10-col-desktop.mdl-cell--10-col-desktop{width:calc(83.3333333333% - 16px)}.mdl-grid--no-spacing>.mdl-cell--10-col,.mdl-grid--no-spacing>.mdl-cell--10-col-desktop.mdl-cell--10-col-desktop{width:83.3333333333%}.mdl-cell--11-col,.mdl-cell--11-col-desktop.mdl-cell--11-col-desktop{width:calc(91.6666666667% - 16px)}.mdl-grid--no-spacing>.mdl-cell--11-col,.mdl-grid--no-spacing>.mdl-cell--11-col-desktop.mdl-cell--11-col-desktop{width:91.6666666667%}.mdl-cell--12-col,.mdl-cell--12-col-desktop.mdl-cell--12-col-desktop{width:calc(100% - 16px)}.mdl-grid--no-spacing>.mdl-cell--12-col,.mdl-grid--no-spacing>.mdl-cell--12-col-desktop.mdl-cell--12-col-desktop{width:100%}.mdl-cell--1-offset,.mdl-cell--1-offset-desktop.mdl-cell--1-offset-desktop{margin-left:calc(8.3333333333% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--1-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--1-offset-desktop.mdl-cell--1-offset-desktop{margin-left:8.3333333333%}.mdl-cell--2-offset,.mdl-cell--2-offset-desktop.mdl-cell--2-offset-desktop{margin-left:calc(16.6666666667% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--2-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--2-offset-desktop.mdl-cell--2-offset-desktop{margin-left:16.6666666667%}.mdl-cell--3-offset,.mdl-cell--3-offset-desktop.mdl-cell--3-offset-desktop{margin-left:calc(25% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--3-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--3-offset-desktop.mdl-cell--3-offset-desktop{margin-left:25%}.mdl-cell--4-offset,.mdl-cell--4-offset-desktop.mdl-cell--4-offset-desktop{margin-left:calc(33.3333333333% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--4-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--4-offset-desktop.mdl-cell--4-offset-desktop{margin-left:33.3333333333%}.mdl-cell--5-offset,.mdl-cell--5-offset-desktop.mdl-cell--5-offset-desktop{margin-left:calc(41.6666666667% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--5-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--5-offset-desktop.mdl-cell--5-offset-desktop{margin-left:41.6666666667%}.mdl-cell--6-offset,.mdl-cell--6-offset-desktop.mdl-cell--6-offset-desktop{margin-left:calc(50% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--6-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--6-offset-desktop.mdl-cell--6-offset-desktop{margin-left:50%}.mdl-cell--7-offset,.mdl-cell--7-offset-desktop.mdl-cell--7-offset-desktop{margin-left:calc(58.3333333333% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--7-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--7-offset-desktop.mdl-cell--7-offset-desktop{margin-left:58.3333333333%}.mdl-cell--8-offset,.mdl-cell--8-offset-desktop.mdl-cell--8-offset-desktop{margin-left:calc(66.6666666667% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--8-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--8-offset-desktop.mdl-cell--8-offset-desktop{margin-left:66.6666666667%}.mdl-cell--9-offset,.mdl-cell--9-offset-desktop.mdl-cell--9-offset-desktop{margin-left:calc(75% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--9-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--9-offset-desktop.mdl-cell--9-offset-desktop{margin-left:75%}.mdl-cell--10-offset,.mdl-cell--10-offset-desktop.mdl-cell--10-offset-desktop{margin-left:calc(83.3333333333% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--10-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--10-offset-desktop.mdl-cell--10-offset-desktop{margin-left:83.3333333333%}.mdl-cell--11-offset,.mdl-cell--11-offset-desktop.mdl-cell--11-offset-desktop{margin-left:calc(91.6666666667% + 8px)}.mdl-grid.mdl-grid--no-spacing>.mdl-cell--11-offset,.mdl-grid.mdl-grid--no-spacing>.mdl-cell--11-offset-desktop.mdl-cell--11-offset-desktop{margin-left:91.6666666667%}} +/*# sourceMappingURL=material.min.css.map */ diff --git a/etc/cli.angular.io/theme.css b/etc/cli.angular.io/theme.css new file mode 100644 index 000000000000..b6a336e98b0c --- /dev/null +++ b/etc/cli.angular.io/theme.css @@ -0,0 +1 @@ +.console{width:360px;max-width:92vw;margin-left:15px;margin-right:40px;text-align:left;border-radius:5px;margin-bottom:10px}@media (max-width:830px){.console{margin-right:auto;margin-left:auto}}.console__head{overflow:hidden;background-color:#d5d5d5;padding:8px 15px;border-top-left-radius:5px;border-top-right-radius:5px}.console__dot{float:left;width:12px;height:12px;border-radius:50%;margin-right:7px;box-shadow:0 1px 1px 0 rgba(0,0,0,.2)}.console__dot--red{background-color:#ff6057}.console__dot--yellow{background-color:#ffc22e}.console__dot--green{background-color:#28ca40}.console__body{background-color:#1e1e1e;padding:30px 17px 20px;border-bottom-left-radius:5px;border-bottom-right-radius:5px}.console__prompt{display:block;margin-bottom:15px;font-family:"Source Code Pro",monospace;font-size:15px}.console__prompt::before{content:">";padding-right:15px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mdl-base{height:100vh} diff --git a/lib/bootstrap-local.js b/lib/bootstrap-local.js index 977eccade98d..e0772ea11740 100644 --- a/lib/bootstrap-local.js +++ b/lib/bootstrap-local.js @@ -1,24 +1,78 @@ +/** + * @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 + */ /* eslint-disable no-console */ 'use strict'; +const child_process = require('child_process'); const fs = require('fs'); const path = require('path'); +const temp = require('temp'); const ts = require('typescript'); +const tmpRoot = temp.mkdirSync('angular-devkit-'); -Error.stackTraceLimit = Infinity; +let _istanbulRequireHook = null; +if (process.env['CODE_COVERAGE'] || process.argv.indexOf('--code-coverage') !== -1) { + _istanbulRequireHook = require('./istanbul-local').istanbulRequireHook; +} + + +// Check if we need to profile this CLI run. +let profiler = null; +if (process.env['DEVKIT_PROFILING']) { + try { + profiler = require('v8-profiler-node8'); + } catch (err) { + throw new Error(`Could not require 'v8-profiler-node8'. You must install it separetely with` + + `'npm install v8-profiler-node8 --no-save.\n\nOriginal error:\n\n${err}`); + } + + profiler.startProfiling(); + + function exitHandler(options, _err) { + if (options.cleanup) { + const cpuProfile = profiler.stopProfiling(); + const profileData = JSON.stringify(cpuProfile); + const filePath = path.resolve(process.cwd(), process.env.DEVKIT_PROFILING) + '.cpuprofile'; + + console.log(`Profiling data saved in "${filePath}": ${profileData.length} bytes`); + fs.writeFileSync(filePath, profileData); + } + + if (options.exit) { + process.exit(); + } + } + + process.on('exit', exitHandler.bind(null, { cleanup: true })); + process.on('SIGINT', exitHandler.bind(null, { exit: true })); + process.on('uncaughtException', exitHandler.bind(null, { exit: true })); +} + +if (process.env['DEVKIT_LONG_STACK_TRACE']) { + Error.stackTraceLimit = Infinity; +} + +global._DevKitIsLocal = true; +global._DevKitRoot = path.resolve(__dirname, '..'); -global.angularCliIsLocal = true; -global.angularCliPackages = require('./packages').packages; -const compilerOptions = JSON.parse(fs.readFileSync(path.join(__dirname, '../tsconfig.json'))); +const compilerOptions = ts.readConfigFile(path.join(__dirname, '../tsconfig.json'), p => { + return fs.readFileSync(p, 'utf-8'); +}).config; + const oldRequireTs = require.extensions['.ts']; require.extensions['.ts'] = function (m, filename) { // If we're in node module, either call the old hook or simply compile the // file without transpilation. We do not touch node_modules/**. - // We do touch `Angular CLI` files anywhere though. - if (!filename.match(/@angular\/cli/) && filename.match(/node_modules/)) { + // We do touch `Angular DevK` files anywhere though. + if (!filename.match(/@angular\/cli\b/) && filename.match(/node_modules/)) { if (oldRequireTs) { return oldRequireTs(m, filename); } @@ -29,7 +83,11 @@ require.extensions['.ts'] = function (m, filename) { const source = fs.readFileSync(filename).toString(); try { - const result = ts.transpile(source, compilerOptions['compilerOptions']); + let result = ts.transpile(source, compilerOptions['compilerOptions'], filename); + + if (_istanbulRequireHook) { + result = _istanbulRequireHook(result, filename); + } // Send it to node to execute. return m._compile(result, filename); @@ -40,55 +98,109 @@ require.extensions['.ts'] = function (m, filename) { } }; -// -// require('ts-node').register({ -// project: path.dirname(__dirname), -// lazy: true -// }); - -const resolve = require('resolve'); - -// Look if there's a .angular-cli.json file, and if so toggle process.cwd() resolution. -const isAngularProject = fs.existsSync(path.join(process.cwd(), '.angular-cli.json')) - || fs.existsSync(path.join(process.cwd(), 'angular-cli.json')); +require.extensions['.ejs'] = function (m, filename) { + const source = fs.readFileSync(filename).toString(); + const template = require('@angular-devkit/core').template; + const result = template(source, { sourceURL: filename, sourceMap: true }); + return m._compile(result.source.replace(/return/, 'module.exports.default = '), filename); +}; +const builtinModules = Object.keys(process.binding('natives')); +const packages = require('./packages').packages; // If we're running locally, meaning npm linked. This is basically "developer mode". if (!__dirname.match(new RegExp(`\\${path.sep}node_modules\\${path.sep}`))) { - const packages = require('./packages').packages; // We mock the module loader so that we can fake our packages when running locally. const Module = require('module'); const oldLoad = Module._load; - Module._load = function (request, parent) { - if (request.match(/ts-node/) && parent && parent.id && parent.id.match(/karma/)) { - throw new Error(); + const oldResolve = Module._resolveFilename; + + Module._resolveFilename = function (request, parent) { + let resolved = null; + let exception; + try { + resolved = oldResolve.call(this, request, parent); + } catch (e) { + exception = e; } + if (request in packages) { - return oldLoad.call(this, packages[request].main, parent); - } else if (request.startsWith('@angular/cli/')) { - // We allow deep imports (for now). - // TODO: move tests to inside @angular/cli package so they don't have to deep import. - const dir = path.dirname(parent.filename); - const newRequest = path.relative(dir, path.join(__dirname, '../packages', request)); - return oldLoad.call(this, newRequest, parent); + return packages[request].main; + } else if (builtinModules.includes(request)) { + // It's a native Node module. + return oldResolve.call(this, request, parent); + } else if (resolved && resolved.match(/[\\\/]node_modules[\\\/]/)) { + return resolved; } else { - let match = Object.keys(packages).find(pkgName => request.startsWith(pkgName + '/')); + const match = Object.keys(packages).find(pkgName => request.startsWith(pkgName + '/')); if (match) { const p = path.join(packages[match].root, request.substr(match.length)); - return oldLoad.call(this, p, parent); + return oldResolve.call(this, p, parent); + } else if (!resolved) { + if (exception) { + throw exception; + } else { + return resolved; + } } else { - try { - if (isAngularProject) { - return oldLoad.call(this, resolve.sync(request, { basedir: process.cwd() }), parent); + // Because loading `.ts` ends up AFTER `.json` in the require() logic, requiring a file that has both `.json` + // and `.ts` versions will only get the `.json` content (which wouldn't happen if the .ts was compiled to + // JavaScript). We load `.ts` files first here to avoid this conflict. It's hacky, but so is the rest of this + // file. + const maybeTsPath = resolved.endsWith('.json') && resolved.replace(/\.json$/, '.ts'); + if (maybeTsPath && !request.endsWith('.json')) { + // If the file exists, return its path. If it doesn't, run the quicktype runner on it and return the content. + if (fs.existsSync(maybeTsPath)) { + return maybeTsPath; + } else { + // This script has the be synchronous, so we spawnSync instead of, say, requiring the runner and calling + // the method directly. + const tmpJsonSchemaPath = path.join(tmpRoot, maybeTsPath.replace(/[^0-9a-zA-Z.]/g, '_')); + try { + if (!fs.existsSync(tmpJsonSchemaPath)) { + const quicktypeRunnerPath = path.join(__dirname, '../tools/quicktype_runner.js'); + child_process.spawnSync('node', [quicktypeRunnerPath, resolved, tmpJsonSchemaPath]); + } + + return tmpJsonSchemaPath; + } catch (_) { + // Just return resolvedPath and let Node deals with it. + console.log(_); + process.exit(99); + } } - } catch (e) { - // Do nothing. Fallback to the old method. } - return oldLoad.apply(this, arguments); + return resolved; } } }; } + + +// Set the resolve hook to allow resolution of packages from a local dev environment. +require('@angular-devkit/core/node/resolve').setResolveHook(function(request, options) { + try { + if (request in packages) { + if (options.resolvePackageJson) { + return path.join(packages[request].root, 'package.json'); + } else { + return packages[request].main; + } + } else { + const match = Object.keys(packages).find(function(pkgName) { + return request.startsWith(pkgName + '/'); + }); + + if (match) { + return path.join(packages[match].root, request.substr(match[0].length)); + } else { + return null; + } + } + } catch (_) { + return null; + } +}); diff --git a/lib/istanbul-local.js b/lib/istanbul-local.js new file mode 100644 index 000000000000..ef5782661a92 --- /dev/null +++ b/lib/istanbul-local.js @@ -0,0 +1,57 @@ +/** + * @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 + */ +const { SourceMapConsumer } = require('source-map'); +const Istanbul = require('istanbul'); + +const inlineSourceMapRe = /\/\/# sourceMappingURL=data:application\/json;base64,(\S+)$/; + + +// Use the internal DevKit Hook of the require extension installed by our bootstrapping code to add +// Istanbul (not Constantinople) collection to the code. +const codeMap = new Map(); +exports.codeMap = codeMap; + +exports.istanbulRequireHook = function(code, filename) { + // Skip spec files. + if (filename.match(/_spec(_large)?\.ts$/)) { + return code; + } + const codeFile = codeMap.get(filename); + if (codeFile) { + return codeFile.code; + } + + const instrumenter = new Istanbul.Instrumenter({ + esModules: true, + codeGenerationOptions: { + sourceMap: filename, + sourceMapWithCode: true, + }, + }); + let instrumentedCode = instrumenter.instrumentSync(code, filename); + const match = code.match(inlineSourceMapRe); + + if (match) { + const sourceMapGenerator = instrumenter.sourceMap; + // Fix source maps for exception reporting (since the exceptions happen in the instrumented + // code. + const sourceMapJson = JSON.parse(Buffer.from(match[1], 'base64').toString()); + const consumer = new SourceMapConsumer(sourceMapJson); + sourceMapGenerator.applySourceMap(consumer, filename); + + instrumentedCode = instrumentedCode.replace(inlineSourceMapRe, '') + + '//# sourceMappingURL=data:application/json;base64,' + + new Buffer(sourceMapGenerator.toString()).toString('base64'); + + // Keep the consumer from the original source map, because the reports from Istanbul (not + // Constantinople) are already mapped against the code. + codeMap.set(filename, { code: instrumentedCode, map: consumer }); + } + + return instrumentedCode; +}; diff --git a/lib/packages.js b/lib/packages.js deleted file mode 100644 index 7338301873ae..000000000000 --- a/lib/packages.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -const fs = require('fs'); -const glob = require('glob'); -const path = require('path'); - -const packageRoot = path.join(__dirname, '../packages'); -const toolsRoot = path.join(__dirname, '../tools'); -const distRoot = path.join(__dirname, '../dist'); - - -// All the supported packages. Go through the packages directory and create a map of -// name => fullPath. -const packages = - glob.sync(path.join(packageRoot, '**/package.json')) - .filter(p => !p.match(/blueprints/)) - .map(pkgPath => path.relative(packageRoot, path.dirname(pkgPath))) - .map(pkgName => { - return { name: pkgName, root: path.join(packageRoot, pkgName) }; - }) - .reduce((packages, pkg) => { - let pkgJson = JSON.parse(fs.readFileSync(path.join(pkg.root, 'package.json'), 'utf8')); - let name = pkgJson['name']; - - packages[name] = { - dist: path.join(distRoot, pkg.name), - packageJson: path.join(pkg.root, 'package.json'), - distPackageJson: path.join(distRoot, pkg.name, 'package.json'), - root: pkg.root, - relative: path.relative(path.dirname(__dirname), pkg.root), - main: path.resolve(pkg.root, 'src/index.ts'), - tar: path.join(distRoot, pkg.name.replace('/', '_') + '.tgz') - }; - return packages; - }, {}); - -const tools = glob.sync(path.join(toolsRoot, '**/package.json')) - .map(toolPath => path.relative(toolsRoot, path.dirname(toolPath))) - .map(toolName => { - const root = path.join(toolsRoot, toolName); - const pkgJson = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8')); - const name = pkgJson['name']; - const dist = path.join(distRoot, toolName); - - return { - name, - main: path.join(dist, pkgJson['main']), - mainTs: path.join(toolsRoot, toolName, pkgJson['main'].replace(/\.js$/, '.ts')), - root, - packageJson: path.join(toolsRoot, toolName, 'package.json'), - dist - }; - }) - .reduce((tools, tool) => { - tools[tool.name] = tool; - return tools; - }, {}); - - -module.exports = { packages, tools }; - - -// If we run this from the command line, just output the list of modules neatly formatted. -if (require.main === module) { - /* eslint-disable no-console */ - console.log('Packages:'); - console.log(JSON.stringify(packages, null, 2)); - console.log(''); - console.log('Tools:'); - console.log(JSON.stringify(tools, null, 2)); -} diff --git a/lib/packages.ts b/lib/packages.ts new file mode 100644 index 000000000000..ef9b82589ca7 --- /dev/null +++ b/lib/packages.ts @@ -0,0 +1,263 @@ +/** + * @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 + */ +// tslint:disable-next-line:no-implicit-dependencies +import { JsonObject } from '@angular-devkit/core'; +import { execSync } from 'child_process'; +import * as crypto from 'crypto'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as ts from 'typescript'; + +const glob = require('glob'); +const distRoot = path.join(__dirname, '../dist'); +const { packages: monorepoPackages } = require('../.monorepo.json'); + + +export interface PackageInfo { + name: string; + root: string; + bin: { [name: string]: string}; + relative: string; + main: string; + dist: string; + build: string; + tar: string; + private: boolean; + packageJson: JsonObject; + dependencies: string[]; + + snapshot: boolean; + snapshotRepo: string; + snapshotHash: string; + + dirty: boolean; + hash: string; + version: string; +} +export type PackageMap = { [name: string]: PackageInfo }; + + +const hashCache: {[name: string]: string | null} = {}; +function _getHashOf(pkg: PackageInfo): string { + if (!(pkg.name in hashCache)) { + hashCache[pkg.name] = null; + const md5Stream = crypto.createHash('md5'); + + // Update the stream with all files content. + const files: string[] = glob.sync(path.join(pkg.root, '**'), { nodir: true }); + files.forEach(filePath => { + md5Stream.write(`\0${filePath}\0`); + md5Stream.write(fs.readFileSync(filePath)); + }); + // Update the stream with all versions of upstream dependencies. + pkg.dependencies.forEach(depName => { + md5Stream.write(`\0${depName}\0${_getHashOf(packages[depName])}\0`); + }); + + md5Stream.end(); + + hashCache[pkg.name] = (md5Stream.read() as Buffer).toString('hex'); + } + + const value = hashCache[pkg.name]; + if (!value) { + // Protect against circular dependency. + throw new Error('Circular dependency detected between the following packages: ' + + Object.keys(hashCache).filter(key => hashCache[key] == null).join(', ')); + } + + return value; +} + + +function loadPackageJson(p: string) { + const root = require('../package.json'); + const pkg = require(p); + + for (const key of Object.keys(root)) { + switch (key) { + // Keep the following keys from the package.json of the package itself. + case 'bin': + case 'description': + case 'dependencies': + case 'name': + case 'main': + case 'peerDependencies': + case 'optionalDependencies': + case 'typings': + case 'version': + case 'private': + case 'workspaces': + case 'resolutions': + continue; + + // Remove the following keys from the package.json. + case 'devDependencies': + case 'scripts': + delete pkg[key]; + continue; + + // Merge the following keys with the root package.json. + case 'keywords': + const a = pkg[key] || []; + const b = Object.keys( + root[key].concat(a).reduce((acc: {[k: string]: boolean}, curr: string) => { + acc[curr] = true; + + return acc; + }, {})); + pkg[key] = b; + break; + + // Overwrite engines to a common default. + case 'engines': + pkg['engines'] = { + 'node': '>= 8.9.0', + 'npm': '>= 5.5.1', + }; + break; + + // Overwrite the package's key with to root one. + default: + pkg[key] = root[key]; + } + } + + return pkg; +} + + +function _findAllPackageJson(dir: string, exclude: RegExp): string[] { + const result: string[] = []; + fs.readdirSync(dir) + .forEach(fileName => { + const p = path.join(dir, fileName); + + if (exclude.test(p)) { + return; + } else if (/[\/\\]node_modules[\/\\]/.test(p)) { + return; + } else if (fileName == 'package.json') { + result.push(p); + } else if (fs.statSync(p).isDirectory() && fileName != 'node_modules') { + result.push(..._findAllPackageJson(p, exclude)); + } + }); + + return result; +} + + +const tsConfigPath = path.join(__dirname, '../tsconfig.json'); +const tsConfig = ts.readConfigFile(tsConfigPath, ts.sys.readFile); +const pattern = '^(' + + (tsConfig.config.exclude as string[]) + .map(ex => path.join(path.dirname(tsConfigPath), ex)) + .map(ex => '(' + + ex + .replace(/[\-\[\]{}()+?./\\^$|]/g, '\\$&') + .replace(/(\\\\|\\\/)\*\*/g, '((\/|\\\\).+?)?') + .replace(/\*/g, '[^/\\\\]*') + + ')') + .join('|') + + ')($|/|\\\\)'; +const excludeRe = new RegExp(pattern); + +// Find all the package.json that aren't excluded from tsconfig. +const packageJsonPaths = _findAllPackageJson(path.join(__dirname, '..'), excludeRe) + // Remove the root package.json. + .filter(p => p != path.join(__dirname, '../package.json')); + + +let gitShaCache: string; +function _getSnapshotHash(_pkg: PackageInfo): string { + if (!gitShaCache) { + gitShaCache = execSync('git log --format=%h -n1').toString().trim(); + } + + return gitShaCache; +} + + +// All the supported packages. Go through the packages directory and create a map of +// name => PackageInfo. This map is partial as it lacks some information that requires the +// map itself to finish building. +export const packages: PackageMap = + packageJsonPaths + .map(pkgPath => ({ root: path.dirname(pkgPath) })) + .reduce((packages: PackageMap, pkg) => { + const pkgRoot = pkg.root; + const packageJson = loadPackageJson(path.join(pkgRoot, 'package.json')); + const name = packageJson['name']; + if (!name) { + // Only build the entry if there's a package name. + return packages; + } + if (!(name in monorepoPackages)) { + throw new Error( + `Package ${name} found in ${JSON.stringify(pkg.root)}, not found in .monorepo.json.`, + ); + } + + const bin: {[name: string]: string} = {}; + Object.keys(packageJson['bin'] || {}).forEach(binName => { + let p = path.resolve(pkg.root, packageJson['bin'][binName]); + if (!fs.existsSync(p)) { + p = p.replace(/\.js$/, '.ts'); + } + bin[binName] = p; + }); + + packages[name] = { + build: path.join(distRoot, pkgRoot.substr(path.dirname(__dirname).length)), + dist: path.join(distRoot, name), + root: pkgRoot, + relative: path.relative(path.dirname(__dirname), pkgRoot), + main: path.resolve(pkgRoot, 'src/index.ts'), + private: packageJson.private, + // yarn doesn't take kindly to @ in tgz filenames + // https://github.com/yarnpkg/yarn/issues/6339 + tar: path.join(distRoot, name.replace(/\/|@/g, '_') + '.tgz'), + bin, + name, + packageJson, + + snapshot: !!monorepoPackages[name].snapshotRepo, + snapshotRepo: monorepoPackages[name].snapshotRepo, + get snapshotHash() { + return _getSnapshotHash(this); + }, + + dependencies: [], + hash: '', + dirty: false, + version: monorepoPackages[name] && monorepoPackages[name].version || '0.0.0', + }; + + return packages; + }, {}); + + +// Update with dependencies. +for (const pkgName of Object.keys(packages)) { + const pkg = packages[pkgName]; + const pkgJson = require(path.join(pkg.root, 'package.json')); + pkg.dependencies = Object.keys(packages).filter(name => { + return name in (pkgJson.dependencies || {}) + || name in (pkgJson.devDependencies || {}); + }); +} + + +// Update the hash values of each. +for (const pkgName of Object.keys(packages)) { + packages[pkgName].hash = _getHashOf(packages[pkgName]); + if (!monorepoPackages[pkgName] || packages[pkgName].hash != monorepoPackages[pkgName].hash) { + packages[pkgName].dirty = true; + } +} diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 28e68ef39edb..000000000000 --- a/package-lock.json +++ /dev/null @@ -1,9633 +0,0 @@ -{ - "name": "@angular/cli", - "version": "1.6.0-beta.2", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@angular-devkit/build-optimizer": { - "version": "0.0.28", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-optimizer/-/build-optimizer-0.0.28.tgz", - "integrity": "sha512-rG5sGV5a2F3R5E+8WRnvq/UPDY2uN5iQjMBDsId1oILjBSAUSwOZM10zQ3De+sd89CmT/R6aSkr6YtbkYn8G0Q==", - "requires": { - "loader-utils": "1.1.0", - "source-map": "0.5.7", - "typescript": "2.4.2", - "webpack-sources": "1.0.1" - } - }, - "@angular-devkit/core": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-0.0.20.tgz", - "integrity": "sha512-lg5BvMxOfbVD//SOQvpq6TPIKTXYNMj0I9N/kfXbXkUGgiBGFLyFMf2fc+qNvDoa7lulKMPT8OJWS1YlGt93eg==", - "requires": { - "source-map": "0.5.7" - } - }, - "@angular-devkit/schematics": { - "version": "0.0.35", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-0.0.35.tgz", - "integrity": "sha512-+qGUWhmMpHqHkYKMk1yKQDjXb/vqXGkzbMiRs/u5rSnlrH+/TzkCO0UsM7/p9WPcModuDxkf5FItpw/AgdcPeQ==", - "requires": { - "@angular-devkit/core": "0.0.20", - "@ngtools/json-schema": "1.1.0", - "minimist": "1.2.0", - "rxjs": "5.5.2" - } - }, - "@angular/compiler": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-5.0.0.tgz", - "integrity": "sha1-uf+/GMijnYt9rOxHMZOpDiTMK8k=", - "dev": true, - "requires": { - "tslib": "1.7.1" - } - }, - "@angular/compiler-cli": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-5.0.0.tgz", - "integrity": "sha1-Dsu5N9hKT43ZTwwqR7B9LkaUyFM=", - "dev": true, - "requires": { - "chokidar": "1.7.0", - "minimist": "1.2.0", - "reflect-metadata": "0.1.10", - "tsickle": "0.24.1" - } - }, - "@angular/core": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-5.0.0.tgz", - "integrity": "sha1-T5dqIl993fNJkvLK2CTJVDpG9Mg=", - "dev": true, - "requires": { - "tslib": "1.7.1" - } - }, - "@angular/service-worker": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-5.0.0.tgz", - "integrity": "sha1-maL103A1BivRBWEgzP9D1jI8OYc=", - "dev": true, - "requires": { - "tslib": "1.7.1" - } - }, - "@ngtools/json-schema": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@ngtools/json-schema/-/json-schema-1.1.0.tgz", - "integrity": "sha1-w6DFRNYjkqzCgTpCyKDcb1j4aSI=" - }, - "@schematics/angular": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-0.1.0.tgz", - "integrity": "sha512-+Yy72J55uImsROxwyyEMso+HJIvx7+ffT8o8HzdNOZyLg4jj7G/ZDiCsCmhRtTYOmOof4OqvF2VecJyXVi0oHA==", - "requires": { - "@angular-devkit/core": "0.0.20" - } - }, - "@types/common-tags": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@types/common-tags/-/common-tags-1.4.0.tgz", - "integrity": "sha512-HI1tSO87vmd1sPS3DOVSK4gvVKROvCBFvAnXlLiQtAus/+1xXMQcNyu9TX2ChwRXFeQZeB9+f+nMo99xLd5DdA==", - "dev": true - }, - "@types/copy-webpack-plugin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/copy-webpack-plugin/-/copy-webpack-plugin-4.0.1.tgz", - "integrity": "sha512-+R4A5pYLCUhchrZdmTt9FRhtHAACxkgtENPTrciuSlk9+bloMqKAri97+41rbNlboAuV9OQLjz90aTvbzR/S+A==", - "dev": true, - "requires": { - "@types/minimatch": "3.0.1", - "@types/webpack": "3.0.11" - } - }, - "@types/denodeify": { - "version": "1.2.31", - "resolved": "https://registry.npmjs.org/@types/denodeify/-/denodeify-1.2.31.tgz", - "integrity": "sha512-Jgy3dvCyIxhNb5RstVJkubeHZifw8KJXca13ov8OO4IqhDLPRHiJJ6VArJbZZ4HuEMJEB83yCuABodNMlYylzQ==", - "dev": true - }, - "@types/express": { - "version": "4.0.37", - "resolved": "https://registry.npmjs.org/@types/express/-/express-4.0.37.tgz", - "integrity": "sha512-tIULTLzQpFFs5/PKnFIAFOsXQxss76glppbVKR3/jddPK26SBsD5HF5grn5G2jOGtpRWSBvYmDYoduVv+3wOXg==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "4.0.53", - "@types/serve-static": "1.7.32" - } - }, - "@types/express-serve-static-core": { - "version": "4.0.53", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.0.53.tgz", - "integrity": "sha512-zaGeOpEYp5G2EhjaUFdVwysDrfEYc6Q6iPhd3Kl4ip30x0tvVv7SuJvY3yzCUSuFlzAG8N5KsyY6BJg93/cn+Q==", - "dev": true, - "requires": { - "@types/node": "6.0.88" - } - }, - "@types/form-data": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@types/form-data/-/form-data-2.2.0.tgz", - "integrity": "sha512-vm5OGsKc61Sx/GTRMQ9d0H0PYCDebT78/bdIBPCoPEHdgp0etaH1RzMmkDygymUmyXTj3rdWQn0sRUpYKZzljA==", - "dev": true, - "requires": { - "@types/node": "6.0.88" - } - }, - "@types/fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha512-Id1hnmfd+7G9K+jWz2syfMcpymx2mj6B1y4C72vAoYQzxOA79UhY/kNvOCyb9yYR1SoSaHyhwcYtWKKqUiLTZA==", - "dev": true, - "requires": { - "@types/node": "6.0.88" - } - }, - "@types/glob": { - "version": "5.0.32", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.32.tgz", - "integrity": "sha512-DMcj5b67Alb/e4KhpzyvphC5nVDHn1oCOGZao3oBddZVMH5vgI/cvdp+O/kcxZGZaPqs0ZLAsK4YrjbtZHO05g==", - "dev": true, - "requires": { - "@types/minimatch": "3.0.1", - "@types/node": "6.0.88" - } - }, - "@types/jasmine": { - "version": "2.5.45", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-2.5.45.tgz", - "integrity": "sha1-WJKKYh0BTOarWcWpxBBx9zKLDKk=", - "dev": true - }, - "@types/lodash": { - "version": "4.14.74", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.74.tgz", - "integrity": "sha512-BZknw3E/z3JmCLqQVANcR17okqVTPZdlxvcIz0fJiJVLUCbSH1hK3zs9r634PVSmrzAxN+n/fxlVRiYoArdOIQ==", - "dev": true - }, - "@types/mime": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.0.tgz", - "integrity": "sha512-A2TAGbTFdBw9azHbpVd+/FkdW2T6msN1uct1O9bH3vTerEHKZhTXJUQXy+hNq1B0RagfU8U+KBdqiZpxjhOUQA==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.1.tgz", - "integrity": "sha512-rUO/jz10KRSyA9SHoCWQ8WX9BICyj5jZYu1/ucKEJKb4KzLZCKMURdYbadP157Q6Zl1x0vHsrU+Z/O0XlhYQDw==", - "dev": true - }, - "@types/minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=", - "dev": true - }, - "@types/mock-fs": { - "version": "3.6.30", - "resolved": "https://registry.npmjs.org/@types/mock-fs/-/mock-fs-3.6.30.tgz", - "integrity": "sha1-TYElQeh7I1dyYaWqlfcE3T0B5BA=", - "dev": true, - "requires": { - "@types/node": "6.0.88" - } - }, - "@types/node": { - "version": "6.0.88", - "resolved": "https://registry.npmjs.org/@types/node/-/node-6.0.88.tgz", - "integrity": "sha512-bYDPZTX0/s1aihdjLuAgogUAT5M+TpoWChEMea2p0yOcfn5bu3k6cJb9cp6nw268XeSNIGGr+4+/8V5K6BGzLQ==", - "dev": true - }, - "@types/request": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/request/-/request-2.0.3.tgz", - "integrity": "sha512-cIvnyFRARxwE4OHpCyYue7H+SxaKFPpeleRCHJicft8QhyTNbVYsMwjvEzEPqG06D2LGHZ+sN5lXc8+bTu6D8A==", - "dev": true, - "requires": { - "@types/form-data": "2.2.0", - "@types/node": "6.0.88" - } - }, - "@types/semver": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.4.0.tgz", - "integrity": "sha512-PBHCvO98hNec9A491vBbh0ZNDOVxccwKL1u2pm6fs9oDgm7SEnw0lEHqHfjsYryDxnE3zaf7LvERWEXjOp1hig==", - "dev": true - }, - "@types/serve-static": { - "version": "1.7.32", - "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.7.32.tgz", - "integrity": "sha512-WpI0g7M1FiOmJ/a97Qrjafq2I938tjAZ3hZr9O7sXyA6oUhH3bqUNZIt7r1KZg8TQAKxcvxt6JjQ5XuLfIBFvg==", - "dev": true, - "requires": { - "@types/express-serve-static-core": "4.0.53", - "@types/mime": "2.0.0" - } - }, - "@types/source-map": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@types/source-map/-/source-map-0.5.1.tgz", - "integrity": "sha512-/GVAjL1Y8puvZab63n8tsuBiYwZt1bApMdx58/msQ9ID5T05ov+wm/ZV1DvYC/DKKEygpTJViqQvkh5Rhrl4CA==", - "dev": true - }, - "@types/tapable": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-0.2.4.tgz", - "integrity": "sha512-pclMAvhPnXJcJu1ZZ8bQthuUcdDWzDuxDdbSf6l1U6s4fP6EBiZpPsOZYqFOrbqDV97sXGFSsb6AUpiLfv4xIA==", - "dev": true - }, - "@types/uglify-js": { - "version": "2.6.29", - "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-2.6.29.tgz", - "integrity": "sha512-BdFLCZW0GTl31AbqXSak8ss/MqEZ3DN2MH9rkAyGoTuzK7ifGUlX+u0nfbWeTsa7IPcZhtn8BlpYBXSV+vqGhQ==", - "dev": true, - "requires": { - "@types/source-map": "0.5.1" - } - }, - "@types/webpack": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/@types/webpack/-/webpack-3.0.11.tgz", - "integrity": "sha512-zd9NK+SLVONhuD2iGVfE8KcpTHIwIcIZqyisRyGurjC2iXzRu1rkJmAWq4agBOw7rU3GocH29JX/gwrDLSA+cw==", - "dev": true, - "requires": { - "@types/node": "6.0.88", - "@types/tapable": "0.2.4", - "@types/uglify-js": "2.6.29" - } - }, - "JSONStream": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz", - "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=", - "dev": true, - "requires": { - "jsonparse": "1.3.1", - "through": "2.3.8" - } - }, - "abbrev": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", - "integrity": "sha1-0FVMIlZjbi9W58LlrRg/hZQo2B8=" - }, - "accepts": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", - "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", - "requires": { - "mime-types": "2.1.17", - "negotiator": "0.6.1" - } - }, - "acorn": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.2.tgz", - "integrity": "sha512-o96FZLJBPY1lvTuJylGA9Bk3t/GKPPJG8H0ydQQl01crzwJgspa4AEIq/pVTXigmK0PHVQhiAtn8WMBLL9D2WA==" - }, - "acorn-dynamic-import": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz", - "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=", - "requires": { - "acorn": "4.0.13" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz", - "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=" - } - } - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "dev": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", - "dev": true - } - } - }, - "ajv": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.2.tgz", - "integrity": "sha1-R8aNaehvXZUxA7AHSpQw3GPaXjk=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.0.0", - "json-schema-traverse": "0.3.1", - "json-stable-stringify": "1.0.1" - } - }, - "ajv-keywords": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.0.tgz", - "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=" - }, - "align-text": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", - "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", - "requires": { - "kind-of": "3.2.2", - "longest": "1.0.1", - "repeat-string": "1.6.1" - } - }, - "alphanum-sort": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz", - "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=" - }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" - }, - "ansi-escapes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz", - "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=", - "dev": true - }, - "ansi-html": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/ansi-html/-/ansi-html-0.0.7.tgz", - "integrity": "sha1-gTWEAhliqenm/QOflA0S9WynhZ4=" - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "anymatch": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", - "requires": { - "micromatch": "2.3.11", - "normalize-path": "2.1.1" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==" - }, - "are-we-there-yet": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz", - "integrity": "sha1-u13KOCu5TwXhUZQ3PRb9O6HKEQ0=", - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.3.3" - } - }, - "argparse": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", - "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", - "requires": { - "sprintf-js": "1.0.3" - } - }, - "arr-diff": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", - "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", - "requires": { - "arr-flatten": "1.1.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==" - }, - "array-filter": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz", - "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=", - "dev": true - }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=" - }, - "array-flatten": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz", - "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY=" - }, - "array-ify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-ify/-/array-ify-1.0.0.tgz", - "integrity": "sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4=", - "dev": true - }, - "array-includes": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", - "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.8.2" - } - }, - "array-map": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz", - "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=", - "dev": true - }, - "array-reduce": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz", - "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=", - "dev": true - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, - "array-unique": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", - "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=" - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", - "dev": true - }, - "asap": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" - }, - "asn1": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", - "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=" - }, - "asn1.js": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz", - "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=", - "requires": { - "bn.js": "4.11.7", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz", - "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=", - "requires": { - "util": "0.10.3" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" - }, - "async": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz", - "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==", - "requires": { - "lodash": "4.17.4" - } - }, - "async-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", - "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=" - }, - "async-foreach": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" - }, - "autoprefixer": { - "version": "6.7.7", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", - "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=", - "requires": { - "browserslist": "1.7.7", - "caniuse-db": "1.0.30000733", - "normalize-range": "0.1.2", - "num2fraction": "1.2.2", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" - }, - "aws4": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", - "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "babel-generator": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.0.tgz", - "integrity": "sha1-rBriAHC3n248odMmlhMFN3TyDcU=", - "requires": { - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "detect-indent": "4.0.0", - "jsesc": "1.3.0", - "lodash": "4.17.4", - "source-map": "0.5.7", - "trim-right": "1.0.1" - }, - "dependencies": { - "jsesc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", - "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=" - } - } - }, - "babel-messages": { - "version": "6.23.0", - "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz", - "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=", - "requires": { - "babel-runtime": "6.26.0" - } - }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "2.5.1", - "regenerator-runtime": "0.11.0" - } - }, - "babel-template": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz", - "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=", - "requires": { - "babel-runtime": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "lodash": "4.17.4" - } - }, - "babel-traverse": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz", - "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=", - "requires": { - "babel-code-frame": "6.26.0", - "babel-messages": "6.23.0", - "babel-runtime": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "debug": "2.6.8", - "globals": "9.18.0", - "invariant": "2.2.2", - "lodash": "4.17.4" - } - }, - "babel-types": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz", - "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=", - "requires": { - "babel-runtime": "6.26.0", - "esutils": "2.0.2", - "lodash": "4.17.4", - "to-fast-properties": "1.0.3" - } - }, - "babylon": { - "version": "6.18.0", - "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz", - "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==" - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base64-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", - "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==" - }, - "batch": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", - "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=" - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", - "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "big.js": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz", - "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==" - }, - "binary-extensions": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.10.0.tgz", - "integrity": "sha1-muuabF6IY4qtFx4Wf1kAq+JINdA=" - }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "optional": true, - "requires": { - "inherits": "2.0.3" - } - }, - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, - "bn.js": { - "version": "4.11.7", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz", - "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==" - }, - "bonjour": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz", - "integrity": "sha1-jokKGD2O6aI5OzhExpGkK897yfU=", - "requires": { - "array-flatten": "2.1.1", - "deep-equal": "1.0.1", - "dns-equal": "1.0.0", - "dns-txt": "2.0.2", - "multicast-dns": "6.1.1", - "multicast-dns-service-types": "1.1.0" - } - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" - }, - "boom": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz", - "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=", - "requires": { - "hoek": "4.2.0" - } - }, - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "1.8.5", - "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", - "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", - "requires": { - "expand-range": "1.8.2", - "preserve": "0.2.0", - "repeat-element": "1.1.2" - } - }, - "brorand": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", - "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" - }, - "browserify-aes": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz", - "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=", - "requires": { - "buffer-xor": "1.0.3", - "cipher-base": "1.0.4", - "create-hash": "1.1.3", - "evp_bytestokey": "1.0.0", - "inherits": "2.0.3" - } - }, - "browserify-cipher": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz", - "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=", - "requires": { - "browserify-aes": "1.0.6", - "browserify-des": "1.0.0", - "evp_bytestokey": "1.0.0" - } - }, - "browserify-des": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz", - "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=", - "requires": { - "cipher-base": "1.0.4", - "des.js": "1.0.0", - "inherits": "2.0.3" - } - }, - "browserify-rsa": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", - "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", - "requires": { - "bn.js": "4.11.7", - "randombytes": "2.0.5" - } - }, - "browserify-sign": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", - "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", - "requires": { - "bn.js": "4.11.7", - "browserify-rsa": "4.0.1", - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "elliptic": "6.4.0", - "inherits": "2.0.3", - "parse-asn1": "5.1.0" - } - }, - "browserify-zlib": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz", - "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=", - "requires": { - "pako": "0.2.9" - } - }, - "browserslist": { - "version": "1.7.7", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", - "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=", - "requires": { - "caniuse-db": "1.0.30000733", - "electron-to-chromium": "1.3.21" - } - }, - "buffer": { - "version": "4.9.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", - "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", - "requires": { - "base64-js": "1.2.1", - "ieee754": "1.1.8", - "isarray": "1.0.0" - } - }, - "buffer-indexof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.0.tgz", - "integrity": "sha1-9U9kfE9OJSKLqmVqLlfkPV8nCYI=" - }, - "buffer-xor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", - "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "builtin-status-codes": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", - "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" - }, - "bytes": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz", - "integrity": "sha1-TJQj6i0lLCcMQbK97+/5u2tiwGo=" - }, - "cacache": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/cacache/-/cacache-10.0.0.tgz", - "integrity": "sha512-s9h6I9NY3KcBjfuS28K6XNmrv/HNFSzlpVD6eYMXugZg3Y8jjI1lUzTeUMa0oKByCDtHfsIy5Ec7KgWRnC5gtg==", - "requires": { - "bluebird": "3.5.1", - "chownr": "1.0.1", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "lru-cache": "4.1.1", - "mississippi": "1.3.0", - "mkdirp": "0.5.1", - "move-concurrently": "1.0.1", - "promise-inflight": "1.0.1", - "rimraf": "2.6.2", - "ssri": "5.0.0", - "unique-filename": "1.1.0", - "y18n": "3.2.1" - } - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "dev": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", - "dev": true - }, - "camel-case": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz", - "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=", - "requires": { - "no-case": "2.3.2", - "upper-case": "1.1.3" - } - }, - "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=" - }, - "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", - "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" - } - }, - "caniuse-api": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz", - "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=", - "requires": { - "browserslist": "1.7.7", - "caniuse-db": "1.0.30000733", - "lodash.memoize": "4.1.2", - "lodash.uniq": "4.5.0" - } - }, - "caniuse-db": { - "version": "1.0.30000733", - "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000733.tgz", - "integrity": "sha1-OmJbxBx6n5nVnWRVKFfdGvDt2dQ=" - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" - }, - "center-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", - "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", - "requires": { - "align-text": "0.1.4", - "lazy-cache": "1.0.4" - }, - "dependencies": { - "lazy-cache": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", - "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=" - } - } - }, - "chalk": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.2.0.tgz", - "integrity": "sha512-0BMM/2hG3ZaoPfR6F+h/oWpZtsh3b/s62TjSM6MGCJWEbJDN1acqCXvyhhZsDSVFklpebUoQ5O1kKC7lOzrn9g==", - "requires": { - "ansi-styles": "3.1.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.1.0.tgz", - "integrity": "sha1-CcIC1ckX7CMYjKpcnLkXnNlUd1A=", - "requires": { - "color-convert": "1.9.0" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "charenc": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" - }, - "chokidar": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", - "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", - "requires": { - "anymatch": "1.3.2", - "async-each": "1.0.1", - "fsevents": "1.1.2", - "glob-parent": "2.0.0", - "inherits": "2.0.3", - "is-binary-path": "1.0.1", - "is-glob": "2.0.1", - "path-is-absolute": "1.0.1", - "readdirp": "2.1.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "1.0.0" - } - } - } - }, - "chownr": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.0.1.tgz", - "integrity": "sha1-4qdQQqlVGQi+vSW4Uj1fl2nXkYE=" - }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "2.0.3", - "safe-buffer": "5.1.1" - } - }, - "circular-dependency-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/circular-dependency-plugin/-/circular-dependency-plugin-3.0.0.tgz", - "integrity": "sha1-m2hpLjWw41EJmNAWS2rlARvqV2A=" - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", - "dev": true - }, - "clap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", - "requires": { - "chalk": "1.1.3" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "clean-css": { - "version": "4.1.9", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.1.9.tgz", - "integrity": "sha1-Nc7ornaHpJuYA09w3gDE7dOCYwE=", - "requires": { - "source-map": "0.5.7" - } - }, - "cli-cursor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz", - "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=", - "dev": true, - "requires": { - "restore-cursor": "1.0.1" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - } - }, - "clone": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz", - "integrity": "sha1-Jgt6meux7f4kdTgXX3gyQ8sZ0Uk=" - }, - "clone-deep": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", - "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", - "requires": { - "for-own": "1.0.0", - "is-plain-object": "2.0.4", - "kind-of": "3.2.2", - "shallow-clone": "0.1.2" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "coa": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz", - "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=", - "requires": { - "q": "1.5.0" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" - }, - "color": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz", - "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=", - "requires": { - "clone": "1.0.2", - "color-convert": "1.9.0", - "color-string": "0.3.0" - } - }, - "color-convert": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.0.tgz", - "integrity": "sha1-Gsz5fdc5uYO/mU1W/sj5WFNkG3o=", - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" - }, - "color-string": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz", - "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=", - "requires": { - "color-name": "1.1.3" - } - }, - "colormin": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz", - "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=", - "requires": { - "color": "0.11.4", - "css-color-names": "0.0.4", - "has": "1.0.1" - } - }, - "colors": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=" - }, - "combined-stream": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", - "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", - "requires": { - "delayed-stream": "1.0.0" - } - }, - "commander": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz", - "integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==" - }, - "common-tags": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.4.0.tgz", - "integrity": "sha1-EYe+Tz1M8MBCfUP3Tu8fc1AWFMA=", - "requires": { - "babel-runtime": "6.26.0" - } - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=" - }, - "compare-func": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-1.3.2.tgz", - "integrity": "sha1-md0LpFfh+bxyKxLAjsM+6rMfpkg=", - "dev": true, - "requires": { - "array-ify": "1.0.0", - "dot-prop": "3.0.0" - } - }, - "compressible": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz", - "integrity": "sha1-FnGKdd4oPtjmBAQWJaIGRYZ5fYo=", - "requires": { - "mime-db": "1.30.0" - } - }, - "compression": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz", - "integrity": "sha1-AwyfGY8WQ6BX13anOOki2kNzAS0=", - "requires": { - "accepts": "1.3.4", - "bytes": "2.5.0", - "compressible": "2.0.11", - "debug": "2.6.8", - "on-headers": "1.0.1", - "safe-buffer": "5.1.1", - "vary": "1.1.1" - } - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", - "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "typedarray": "0.0.6" - } - }, - "connect-history-api-fallback": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz", - "integrity": "sha1-5R0X+PDvDbkKZP20feMFFVbp8Wk=" - }, - "console-browserify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", - "requires": { - "date-now": "0.1.4" - } - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=" - }, - "constants-browserify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", - "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" - }, - "content-disposition": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", - "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "conventional-changelog": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog/-/conventional-changelog-1.1.0.tgz", - "integrity": "sha1-iuP7Wf63S77golgz7h+D2tSgeHQ=", - "dev": true, - "requires": { - "conventional-changelog-angular": "1.5.0", - "conventional-changelog-atom": "0.1.1", - "conventional-changelog-codemirror": "0.1.0", - "conventional-changelog-core": "1.9.1", - "conventional-changelog-ember": "0.2.7", - "conventional-changelog-eslint": "0.1.0", - "conventional-changelog-express": "0.1.0", - "conventional-changelog-jquery": "0.1.0", - "conventional-changelog-jscs": "0.1.0", - "conventional-changelog-jshint": "0.1.0" - } - }, - "conventional-changelog-angular": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-angular/-/conventional-changelog-angular-1.5.0.tgz", - "integrity": "sha512-Gt0qSf5wdFmLabgdSlqjguDAmPyYTXtUl4WH5W3SlpElHhnU/UiCY3M7xcIkZxrNQfVA1UxUBgu65eBbaJnZVA==", - "dev": true, - "requires": { - "compare-func": "1.3.2", - "q": "1.5.0" - } - }, - "conventional-changelog-atom": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-atom/-/conventional-changelog-atom-0.1.1.tgz", - "integrity": "sha512-6Nlu/+MiD4gi7k3Z+N1vMJWpaPSdvFPWzPGnH4OXewHAxiAl0L/TT9CGgA01fosPxmYr4hMNtD7kyN0tkg8vIA==", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-codemirror": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-codemirror/-/conventional-changelog-codemirror-0.1.0.tgz", - "integrity": "sha1-dXelkdv5tTjnoVCn7mL2WihyszQ=", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-core/-/conventional-changelog-core-1.9.1.tgz", - "integrity": "sha512-Fo0bSeO+NsO6GtuQXts0xQeRpLrxaABTPU8NK4Zij9sJB3zFkU4BObSefJS4F4+EkKujaKCWtfS6Uih+9NpXrQ==", - "dev": true, - "requires": { - "conventional-changelog-writer": "2.0.1", - "conventional-commits-parser": "2.0.0", - "dateformat": "1.0.12", - "get-pkg-repo": "1.4.0", - "git-raw-commits": "1.2.0", - "git-remote-origin-url": "2.0.0", - "git-semver-tags": "1.2.1", - "lodash": "4.17.4", - "normalize-package-data": "2.4.0", - "q": "1.5.0", - "read-pkg": "1.1.0", - "read-pkg-up": "1.0.1", - "through2": "2.0.3" - } - }, - "conventional-changelog-ember": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/conventional-changelog-ember/-/conventional-changelog-ember-0.2.7.tgz", - "integrity": "sha512-Xj1v9uVcKM8N798hMr7e6yiw8IFyvI6Ik+TdjdmG54uGupqvEEWW37xAbPPbdKvgoitbyZkqUTancj055actEg==", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-eslint": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-eslint/-/conventional-changelog-eslint-0.1.0.tgz", - "integrity": "sha1-pSQR6ZngUBzlALhWsKZD0DMJB+I=", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-express": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-express/-/conventional-changelog-express-0.1.0.tgz", - "integrity": "sha1-VcbIQcgRliA2wDe9vZZKVK4xD84=", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-jquery": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-jquery/-/conventional-changelog-jquery-0.1.0.tgz", - "integrity": "sha1-Agg5cWLjhGmG5xJztsecW1+A9RA=", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-jscs": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-jscs/-/conventional-changelog-jscs-0.1.0.tgz", - "integrity": "sha1-BHnrRDzH1yxYvwvPDvHURKkvDlw=", - "dev": true, - "requires": { - "q": "1.5.0" - } - }, - "conventional-changelog-jshint": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/conventional-changelog-jshint/-/conventional-changelog-jshint-0.1.0.tgz", - "integrity": "sha1-AMq46aMxdIer2UxNhGcTQpGNKgc=", - "dev": true, - "requires": { - "compare-func": "1.3.2", - "q": "1.5.0" - } - }, - "conventional-changelog-writer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/conventional-changelog-writer/-/conventional-changelog-writer-2.0.1.tgz", - "integrity": "sha512-X4qC758celQOKw0iUPAsH5sJX6fH6N5dboFc3elXb1/SIKhsYMukhhaxWmxRdtVUSqGt9rZg8giwBQG5B2GeKg==", - "dev": true, - "requires": { - "compare-func": "1.3.2", - "conventional-commits-filter": "1.0.0", - "dateformat": "1.0.12", - "handlebars": "4.0.10", - "json-stringify-safe": "5.0.1", - "lodash": "4.17.4", - "meow": "3.7.0", - "semver": "5.4.1", - "split": "1.0.1", - "through2": "2.0.3" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", - "dev": true, - "optional": true - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "dev": true, - "optional": true, - "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", - "wordwrap": "0.0.2" - }, - "dependencies": { - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", - "dev": true, - "optional": true - } - } - }, - "handlebars": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", - "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", - "dev": true, - "requires": { - "async": "1.5.2", - "optimist": "0.6.1", - "source-map": "0.4.4", - "uglify-js": "2.8.29" - } - }, - "minimist": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", - "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=", - "dev": true - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "0.0.10", - "wordwrap": "0.0.3" - } - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": "1.0.1" - } - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "dev": true, - "optional": true, - "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, - "optional": true - } - } - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "dev": true, - "optional": true, - "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" - } - } - } - }, - "conventional-commits-filter": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-filter/-/conventional-commits-filter-1.0.0.tgz", - "integrity": "sha1-b8KmWTcrw/IznPn//34bA0S5MDk=", - "dev": true, - "requires": { - "is-subset": "0.1.1", - "modify-values": "1.0.0" - } - }, - "conventional-commits-parser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/conventional-commits-parser/-/conventional-commits-parser-2.0.0.tgz", - "integrity": "sha512-8od6g684Fhi5Vpp4ABRv/RBsW1AY6wSHbJHEK6FGTv+8jvAAnlABniZu/FVmX9TcirkHepaEsa1QGkRvbg0CKw==", - "dev": true, - "requires": { - "JSONStream": "1.3.1", - "is-text-path": "1.0.1", - "lodash": "4.17.4", - "meow": "3.7.0", - "split2": "2.1.1", - "through2": "2.0.3", - "trim-off-newlines": "1.0.1" - } - }, - "convert-source-map": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.0.tgz", - "integrity": "sha1-ms1whRxtXf3ZPZKC5e35SgP/RrU=" - }, - "cookie": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", - "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" - }, - "cookie-signature": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", - "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" - }, - "copy-concurrently": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", - "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", - "requires": { - "aproba": "1.2.0", - "fs-write-stream-atomic": "1.0.10", - "iferr": "0.1.5", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" - } - }, - "copy-webpack-plugin": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-4.1.1.tgz", - "integrity": "sha512-qcjV9uj5PFuKo9GDr0xYAZ3DwFA3ugwDcfbLHfiDrvnUx66Z7C4r00/ds856GaGb2cGHqLTwrGxwfvW+lgAQew==", - "requires": { - "bluebird": "3.5.1", - "fs-extra": "4.0.2", - "glob": "7.1.2", - "is-glob": "4.0.0", - "loader-utils": "0.2.17", - "lodash": "4.17.4", - "minimatch": "3.0.4", - "node-dir": "0.1.17" - }, - "dependencies": { - "bluebird": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", - "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" - }, - "is-glob": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", - "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", - "requires": { - "is-extglob": "2.1.1" - } - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" - } - } - } - }, - "core-js": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz", - "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs=" - }, - "core-object": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/core-object/-/core-object-3.1.5.tgz", - "integrity": "sha512-sA2/4+/PZ/KV6CKgjrVrrUVBKCkdDO02CUlQ0YKTQoYUwPYNOtOAcWlbYhd5v/1JqYaA6oZ4sDlOU4ppVw6Wbg==", - "requires": { - "chalk": "2.2.0" - } - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cosmiconfig": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", - "requires": { - "is-directory": "0.3.1", - "js-yaml": "3.7.0", - "minimist": "1.2.0", - "object-assign": "4.1.1", - "os-homedir": "1.0.2", - "parse-json": "2.2.0", - "require-from-string": "1.2.1" - } - }, - "create-ecdh": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz", - "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=", - "requires": { - "bn.js": "4.11.7", - "elliptic": "6.4.0" - } - }, - "create-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz", - "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=", - "requires": { - "cipher-base": "1.0.4", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "sha.js": "2.4.8" - } - }, - "create-hmac": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz", - "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=", - "requires": { - "cipher-base": "1.0.4", - "create-hash": "1.1.3", - "inherits": "2.0.3", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.8" - } - }, - "cross-spawn": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", - "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", - "optional": true, - "requires": { - "lru-cache": "4.1.1", - "which": "1.3.0" - } - }, - "crypt": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" - }, - "cryptiles": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz", - "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=", - "requires": { - "boom": "5.2.0" - }, - "dependencies": { - "boom": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz", - "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==", - "requires": { - "hoek": "4.2.0" - } - } - } - }, - "crypto-browserify": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz", - "integrity": "sha1-NlKgkGq5sqfgw85mpAjpV6JIVSI=", - "requires": { - "browserify-cipher": "1.0.0", - "browserify-sign": "4.0.4", - "create-ecdh": "4.0.0", - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "diffie-hellman": "5.0.2", - "inherits": "2.0.3", - "pbkdf2": "3.0.12", - "public-encrypt": "4.0.0", - "randombytes": "2.0.5" - } - }, - "css-color-names": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz", - "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=" - }, - "css-loader": { - "version": "0.28.7", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.28.7.tgz", - "integrity": "sha512-GxMpax8a/VgcfRrVy0gXD6yLd5ePYbXX/5zGgTVYp4wXtJklS8Z2VaUArJgc//f6/Dzil7BaJObdSv8eKKCPgg==", - "requires": { - "babel-code-frame": "6.26.0", - "css-selector-tokenizer": "0.7.0", - "cssnano": "3.10.0", - "icss-utils": "2.1.0", - "loader-utils": "1.1.0", - "lodash.camelcase": "4.3.0", - "object-assign": "4.1.1", - "postcss": "5.2.17", - "postcss-modules-extract-imports": "1.1.0", - "postcss-modules-local-by-default": "1.2.0", - "postcss-modules-scope": "1.1.0", - "postcss-modules-values": "1.3.0", - "postcss-value-parser": "3.3.0", - "source-list-map": "2.0.0" - } - }, - "css-parse": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz", - "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs=" - }, - "css-select": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", - "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=", - "requires": { - "boolbase": "1.0.0", - "css-what": "2.1.0", - "domutils": "1.5.1", - "nth-check": "1.0.1" - } - }, - "css-selector-tokenizer": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz", - "integrity": "sha1-5piEdK6MlTR3v15+/s/OzNnPTIY=", - "requires": { - "cssesc": "0.1.0", - "fastparse": "1.1.1", - "regexpu-core": "1.0.0" - } - }, - "css-what": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz", - "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0=" - }, - "cssesc": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz", - "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=" - }, - "cssnano": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz", - "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=", - "requires": { - "autoprefixer": "6.7.7", - "decamelize": "1.2.0", - "defined": "1.0.0", - "has": "1.0.1", - "object-assign": "4.1.1", - "postcss": "5.2.17", - "postcss-calc": "5.3.1", - "postcss-colormin": "2.2.2", - "postcss-convert-values": "2.6.1", - "postcss-discard-comments": "2.0.4", - "postcss-discard-duplicates": "2.1.0", - "postcss-discard-empty": "2.1.0", - "postcss-discard-overridden": "0.1.1", - "postcss-discard-unused": "2.2.3", - "postcss-filter-plugins": "2.0.2", - "postcss-merge-idents": "2.1.7", - "postcss-merge-longhand": "2.0.2", - "postcss-merge-rules": "2.1.2", - "postcss-minify-font-values": "1.0.5", - "postcss-minify-gradients": "1.0.5", - "postcss-minify-params": "1.2.2", - "postcss-minify-selectors": "2.1.1", - "postcss-normalize-charset": "1.1.1", - "postcss-normalize-url": "3.0.8", - "postcss-ordered-values": "2.2.3", - "postcss-reduce-idents": "2.4.0", - "postcss-reduce-initial": "1.0.1", - "postcss-reduce-transforms": "1.0.4", - "postcss-svgo": "2.1.6", - "postcss-unique-selectors": "2.0.2", - "postcss-value-parser": "3.3.0", - "postcss-zindex": "2.2.0" - } - }, - "csso": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz", - "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=", - "requires": { - "clap": "1.2.3", - "source-map": "0.5.7" - } - }, - "cuint": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cuint/-/cuint-0.2.2.tgz", - "integrity": "sha1-QICG1AlVDCYxFVYZ6fp7ytw7mRs=" - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", - "requires": { - "array-find-index": "1.0.2" - } - }, - "cyclist": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-0.2.2.tgz", - "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=" - }, - "d": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", - "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", - "requires": { - "es5-ext": "0.10.30" - } - }, - "dargs": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/dargs/-/dargs-4.1.0.tgz", - "integrity": "sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc=", - "dev": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "requires": { - "assert-plus": "1.0.0" - } - }, - "date-now": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=" - }, - "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" - } - }, - "debug": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", - "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", - "requires": { - "ms": "2.0.0" - } - }, - "debuglog": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", - "integrity": "sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=", - "dev": true - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" - }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", - "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", - "requires": { - "foreach": "2.0.5", - "object-keys": "1.0.11" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" - }, - "del": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-3.0.0.tgz", - "integrity": "sha1-U+z2mf/LyzljdpGrE7rxYIGXZuU=", - "requires": { - "globby": "6.1.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "p-map": "1.1.1", - "pify": "3.0.0", - "rimraf": "2.6.2" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "denodeify": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/denodeify/-/denodeify-1.2.1.tgz", - "integrity": "sha1-OjYof1A05pnnV3kBBSwubJQlFjE=" - }, - "depd": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", - "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" - }, - "des.js": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz", - "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=", - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detect-indent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz", - "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=", - "requires": { - "repeating": "2.0.1" - } - }, - "detect-node": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.3.tgz", - "integrity": "sha1-ogM8CcyOFY03dI+951B4Mr1s4Sc=" - }, - "dezalgo": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.3.tgz", - "integrity": "sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY=", - "dev": true, - "requires": { - "asap": "2.0.6", - "wrappy": "1.0.2" - } - }, - "diff": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/diff/-/diff-3.3.1.tgz", - "integrity": "sha512-MKPHZDMB0o6yHyDryUOScqZibp914ksXwAMYMTHj6KO8UeKsRYNJD3oNCKjTqZon+V488P7N/HzXF8t7ZR95ww==", - "dev": true - }, - "diffie-hellman": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz", - "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=", - "requires": { - "bn.js": "4.11.7", - "miller-rabin": "4.0.0", - "randombytes": "2.0.5" - } - }, - "dns-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz", - "integrity": "sha1-s55/HabrCnW6nBcySzR1PEfgZU0=" - }, - "dns-packet": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-1.1.1.tgz", - "integrity": "sha1-I2nUUDivBF84mOb6VoYq7T9AKWw=", - "requires": { - "ip": "1.1.5", - "safe-buffer": "5.1.1" - } - }, - "dns-txt": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz", - "integrity": "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=", - "requires": { - "buffer-indexof": "1.1.0" - } - }, - "doctrine": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.0.tgz", - "integrity": "sha1-xz2NKQnSIpHhoAejlYBNqLZl/mM=", - "dev": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - }, - "dom-converter": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.1.4.tgz", - "integrity": "sha1-pF71cnuJDJv/5tfIduexnLDhfzs=", - "requires": { - "utila": "0.3.3" - }, - "dependencies": { - "utila": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", - "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=" - } - } - }, - "dom-serializer": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz", - "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=", - "requires": { - "domelementtype": "1.1.3", - "entities": "1.1.1" - }, - "dependencies": { - "domelementtype": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz", - "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=" - } - } - }, - "domain-browser": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz", - "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=" - }, - "domelementtype": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz", - "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI=" - }, - "domhandler": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.1.0.tgz", - "integrity": "sha1-0mRvXlf2w7qxHPbLBdPArPdBJZQ=", - "requires": { - "domelementtype": "1.3.0" - } - }, - "domutils": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", - "requires": { - "dom-serializer": "0.1.0", - "domelementtype": "1.3.0" - } - }, - "dot-prop": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz", - "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=", - "dev": true, - "requires": { - "is-obj": "1.0.1" - } - }, - "dtsgenerator": { - "version": "0.9.5", - "resolved": "https://registry.npmjs.org/dtsgenerator/-/dtsgenerator-0.9.5.tgz", - "integrity": "sha512-sVvM4ugZBi+zWz2ctAWxKG3BlCrQkJL77DLPh96YXBpn3DIHk1NEqnToH6CtnSYvOL/Jfx08Fy/RMiz8yMGrLA==", - "dev": true, - "requires": { - "commander": "2.11.0", - "debug": "2.6.8", - "glob": "7.1.2", - "js-yaml": "3.10.0", - "mkdirp": "0.5.1", - "request": "2.82.0" - }, - "dependencies": { - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", - "dev": true - }, - "js-yaml": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", - "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", - "dev": true, - "requires": { - "argparse": "1.0.9", - "esprima": "4.0.0" - } - } - } - }, - "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", - "dev": true - }, - "duplexify": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.1.tgz", - "integrity": "sha512-j5goxHTwVED1Fpe5hh3q9R93Kip0Bg2KVAt4f8CEYM3UEwYcPSvWbXaUQOzdX/HtiNomipv+gU7ASQPDbV7pGQ==", - "requires": { - "end-of-stream": "1.4.0", - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "stream-shift": "1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", - "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "ejs": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz", - "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo=" - }, - "electron-to-chromium": { - "version": "1.3.21", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.21.tgz", - "integrity": "sha1-qWfr3P6O0Ag/wkTRiUAiqOgRPqI=" - }, - "elliptic": { - "version": "6.4.0", - "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz", - "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=", - "requires": { - "bn.js": "4.11.7", - "brorand": "1.1.0", - "hash.js": "1.1.3", - "hmac-drbg": "1.0.1", - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0", - "minimalistic-crypto-utils": "1.0.1" - } - }, - "ember-cli-string-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ember-cli-string-utils/-/ember-cli-string-utils-1.1.0.tgz", - "integrity": "sha1-ObZ3/CgF9VFzc1N2/O8njqpEUqE=" - }, - "emojis-list": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", - "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=" - }, - "encodeurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", - "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" - }, - "end-of-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.0.tgz", - "integrity": "sha1-epDYM+/abPpurA9JSduw+tOmMgY=", - "requires": { - "once": "1.4.0" - } - }, - "enhanced-resolve": { - "version": "3.4.1", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.4.1.tgz", - "integrity": "sha1-BCHjOf1xQZs9oT0Smzl5BAIwR24=", - "requires": { - "graceful-fs": "4.1.11", - "memory-fs": "0.4.1", - "object-assign": "4.1.1", - "tapable": "0.2.8" - } - }, - "ensure-posix-path": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/ensure-posix-path/-/ensure-posix-path-1.0.2.tgz", - "integrity": "sha1-pls+QtC3HPxYXrd0+ZQ8jZuRsMI=", - "dev": true - }, - "entities": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz", - "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA=" - }, - "errno": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz", - "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=", - "requires": { - "prr": "0.0.0" - } - }, - "error-ex": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", - "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", - "requires": { - "is-arrayish": "0.2.1" - } - }, - "es-abstract": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.8.2.tgz", - "integrity": "sha512-dvhwFL3yjQxNNsOWx6exMlaDrRHCRGMQlnx5lsXDCZ/J7G/frgIIl94zhZSp/galVAYp7VzPi1OrAHta89/yGQ==", - "requires": { - "es-to-primitive": "1.1.1", - "function-bind": "1.1.1", - "has": "1.0.1", - "is-callable": "1.1.3", - "is-regex": "1.0.4" - } - }, - "es-to-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", - "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", - "requires": { - "is-callable": "1.1.3", - "is-date-object": "1.0.1", - "is-symbol": "1.0.1" - } - }, - "es5-ext": { - "version": "0.10.30", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.30.tgz", - "integrity": "sha1-cUGhaDZpfbq/qq7uQUlc4p9SyTk=", - "requires": { - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" - } - }, - "es6-iterator": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz", - "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-symbol": "3.1.1" - } - }, - "es6-map": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", - "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", - "es6-set": "0.1.5", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } - }, - "es6-set": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", - "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1", - "event-emitter": "0.3.5" - } - }, - "es6-symbol": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", - "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30" - } - }, - "es6-weak-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", - "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30", - "es6-iterator": "2.0.1", - "es6-symbol": "3.1.1" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "escope": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", - "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=", - "requires": { - "es6-map": "0.1.5", - "es6-weak-map": "2.0.2", - "esrecurse": "4.2.0", - "estraverse": "4.2.0" - } - }, - "eslint": { - "version": "3.19.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz", - "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "chalk": "1.1.3", - "concat-stream": "1.6.0", - "debug": "2.6.8", - "doctrine": "2.0.0", - "escope": "3.6.0", - "espree": "3.5.1", - "esquery": "1.0.0", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "glob": "7.1.2", - "globals": "9.18.0", - "ignore": "3.3.5", - "imurmurhash": "0.1.4", - "inquirer": "0.12.0", - "is-my-json-valid": "2.16.1", - "is-resolvable": "1.0.0", - "js-yaml": "3.7.0", - "json-stable-stringify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "1.2.1", - "progress": "1.1.8", - "require-uncached": "1.0.3", - "shelljs": "0.7.8", - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1", - "table": "3.8.3", - "text-table": "0.2.0", - "user-home": "2.0.0" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "espree": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.1.tgz", - "integrity": "sha1-DJiLirRttTEAoZVK5LqZXd0n2H4=", - "dev": true, - "requires": { - "acorn": "5.1.2", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", - "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=" - }, - "esquery": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", - "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", - "dev": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", - "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", - "requires": { - "estraverse": "4.2.0", - "object-assign": "4.1.1" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "etag": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", - "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" - }, - "event-emitter": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", - "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", - "requires": { - "d": "1.0.0", - "es5-ext": "0.10.30" - } - }, - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "requires": { - "duplexer": "0.1.1", - "from": "0.1.7", - "map-stream": "0.1.0", - "pause-stream": "0.0.11", - "split": "0.3.3", - "stream-combiner": "0.0.4", - "through": "2.3.8" - }, - "dependencies": { - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "requires": { - "through": "2.3.8" - } - } - } - }, - "eventemitter3": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", - "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=" - }, - "events": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" - }, - "eventsource": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-0.1.6.tgz", - "integrity": "sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI=", - "requires": { - "original": "1.0.0" - } - }, - "evp_bytestokey": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz", - "integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=", - "requires": { - "create-hash": "1.1.3" - } - }, - "execa": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", - "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", - "requires": { - "cross-spawn": "5.1.0", - "get-stream": "3.0.0", - "is-stream": "1.1.0", - "npm-run-path": "2.0.2", - "p-finally": "1.0.0", - "signal-exit": "3.0.2", - "strip-eof": "1.0.0" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - } - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "exit-hook": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz", - "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=", - "dev": true - }, - "expand-brackets": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", - "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", - "requires": { - "is-posix-bracket": "0.1.1" - } - }, - "expand-range": { - "version": "1.8.2", - "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", - "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", - "requires": { - "fill-range": "2.2.3" - } - }, - "exports-loader": { - "version": "0.6.4", - "resolved": "https://registry.npmjs.org/exports-loader/-/exports-loader-0.6.4.tgz", - "integrity": "sha1-1w/GEhl1s1/BKDDPUnVL4nQPyIY=", - "requires": { - "loader-utils": "1.1.0", - "source-map": "0.5.7" - } - }, - "express": { - "version": "4.15.4", - "resolved": "https://registry.npmjs.org/express/-/express-4.15.4.tgz", - "integrity": "sha1-Ay4iU0ic+PzgJma+yj0R7XotrtE=", - "requires": { - "accepts": "1.3.4", - "array-flatten": "1.1.1", - "content-disposition": "0.5.2", - "content-type": "1.0.4", - "cookie": "0.3.1", - "cookie-signature": "1.0.6", - "debug": "2.6.8", - "depd": "1.1.1", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.8.1", - "finalhandler": "1.0.5", - "fresh": "0.5.0", - "merge-descriptors": "1.0.1", - "methods": "1.1.2", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "path-to-regexp": "0.1.7", - "proxy-addr": "1.1.5", - "qs": "6.5.0", - "range-parser": "1.2.0", - "send": "0.15.4", - "serve-static": "1.12.4", - "setprototypeof": "1.0.3", - "statuses": "1.3.1", - "type-is": "1.6.15", - "utils-merge": "1.0.0", - "vary": "1.1.1" - }, - "dependencies": { - "array-flatten": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", - "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" - }, - "qs": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.0.tgz", - "integrity": "sha512-fjVFjW9yhqMhVGwRExCXLhJKrLlkYSaxNWdyc9rmHlrVZbk35YHH312dFd7191uQeXkI3mKLZTIbSvIeFwFemg==" - } - } - }, - "extend": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", - "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=" - }, - "extglob": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", - "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", - "requires": { - "is-extglob": "1.0.0" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - } - } - }, - "extract-text-webpack-plugin": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/extract-text-webpack-plugin/-/extract-text-webpack-plugin-3.0.0.tgz", - "integrity": "sha1-kMqnkHvESfM1AF46x1MrQbAN5hI=", - "requires": { - "async": "2.5.0", - "loader-utils": "1.1.0", - "schema-utils": "0.3.0", - "webpack-sources": "1.0.1" - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" - }, - "fast-deep-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", - "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastparse": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.1.tgz", - "integrity": "sha1-0eJkOzipTXWDtHkGDmxK/8lAcfg=" - }, - "faye-websocket": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", - "requires": { - "websocket-driver": "0.6.5" - } - }, - "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", - "dev": true, - "requires": { - "escape-string-regexp": "1.0.5", - "object-assign": "4.1.1" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "dev": true, - "requires": { - "flat-cache": "1.2.2", - "object-assign": "4.1.1" - } - }, - "file-loader": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/file-loader/-/file-loader-1.1.5.tgz", - "integrity": "sha512-RzGHDatcVNpGISTvCpfUfOGpYuSR7HSsSg87ki+wF6rw1Hm0RALPTiAdsxAq1UwLf0RRhbe22/eHK6nhXspiOQ==", - "requires": { - "loader-utils": "1.1.0", - "schema-utils": "0.3.0" - } - }, - "filename-regex": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", - "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=" - }, - "fill-range": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz", - "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=", - "requires": { - "is-number": "2.1.0", - "isobject": "2.1.0", - "randomatic": "1.1.7", - "repeat-element": "1.1.2", - "repeat-string": "1.6.1" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "finalhandler": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.5.tgz", - "integrity": "sha1-pwEwPSV6G8gv6lR6M+WuiVMXI98=", - "requires": { - "debug": "2.6.8", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "on-finished": "2.3.0", - "parseurl": "1.3.2", - "statuses": "1.3.1", - "unpipe": "1.0.0" - } - }, - "find-cache-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-1.0.0.tgz", - "integrity": "sha1-kojj6ePMN0hxfTnq3hfPcfww7m8=", - "requires": { - "commondir": "1.0.1", - "make-dir": "1.0.0", - "pkg-dir": "2.0.0" - } - }, - "find-parent-dir": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz", - "integrity": "sha1-M8RLQpqysvBkYpnF+fcY83b/jVQ=", - "dev": true - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flat-cache": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.2.2.tgz", - "integrity": "sha1-+oZxTnLCHbiGAXYezy9VXRq8a5Y=", - "dev": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - }, - "dependencies": { - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "dev": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.0", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "dev": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - } - } - }, - "flatten": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz", - "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=" - }, - "flush-write-stream": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.2.tgz", - "integrity": "sha1-yBuQ2HRnZvGmCaRoCZRsRd2K5Bc=", - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=" - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "requires": { - "for-in": "1.0.2" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" - }, - "form-data": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz", - "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=", - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.17" - } - }, - "forwarded": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", - "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" - }, - "fresh": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", - "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=" - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, - "from2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", - "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "fs-extra": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.2.tgz", - "integrity": "sha1-+RcExT0bRh+JNFKwwwfZmXZHq2s=", - "requires": { - "graceful-fs": "4.1.11", - "jsonfile": "4.0.0", - "universalify": "0.1.1" - }, - "dependencies": { - "jsonfile": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", - "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", - "requires": { - "graceful-fs": "4.1.11" - } - } - } - }, - "fs-write-stream-atomic": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", - "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", - "requires": { - "graceful-fs": "4.1.11", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.3.3" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz", - "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==", - "optional": true, - "requires": { - "nan": "2.7.0", - "node-pre-gyp": "0.6.36" - }, - "dependencies": { - "abbrev": { - "version": "1.1.0", - "bundled": true, - "optional": true - }, - "ajv": { - "version": "4.11.8", - "bundled": true, - "optional": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "aproba": { - "version": "1.1.1", - "bundled": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.4", - "bundled": true, - "optional": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.2.9" - } - }, - "asn1": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "assert-plus": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "asynckit": { - "version": "0.4.0", - "bundled": true, - "optional": true - }, - "aws-sign2": { - "version": "0.6.0", - "bundled": true, - "optional": true - }, - "aws4": { - "version": "1.6.0", - "bundled": true, - "optional": true - }, - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "bcrypt-pbkdf": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "tweetnacl": "0.14.5" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "brace-expansion": { - "version": "1.1.7", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - } - }, - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "caseless": { - "version": "0.12.0", - "bundled": true, - "optional": true - }, - "co": { - "version": "4.6.0", - "bundled": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "optional": true, - "requires": { - "boom": "2.10.1" - } - }, - "dashdash": { - "version": "1.14.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "debug": { - "version": "2.6.8", - "bundled": true, - "optional": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-extend": { - "version": "0.4.2", - "bundled": true, - "optional": true - }, - "delayed-stream": { - "version": "1.0.0", - "bundled": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "extend": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "form-data": { - "version": "2.1.4", - "bundled": true, - "optional": true, - "requires": { - "asynckit": "0.4.0", - "combined-stream": "1.0.5", - "mime-types": "2.1.15" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "fstream": { - "version": "1.0.11", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.1" - } - }, - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "optional": true, - "requires": { - "fstream": "1.0.11", - "inherits": "2.0.3", - "minimatch": "3.0.4" - } - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "optional": true, - "requires": { - "aproba": "1.1.1", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "getpass": { - "version": "0.1.7", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "har-schema": { - "version": "1.0.5", - "bundled": true, - "optional": true - }, - "har-validator": { - "version": "4.2.1", - "bundled": true, - "optional": true, - "requires": { - "ajv": "4.11.8", - "har-schema": "1.0.5" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "optional": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.4.0", - "sshpk": "1.13.0" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true, - "optional": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true, - "optional": true - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.1" - } - }, - "jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true - }, - "json-schema": { - "version": "0.2.3", - "bundled": true, - "optional": true - }, - "json-stable-stringify": { - "version": "1.0.1", - "bundled": true, - "optional": true, - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true, - "optional": true - }, - "jsonify": { - "version": "0.0.0", - "bundled": true, - "optional": true - }, - "jsprim": { - "version": "1.4.0", - "bundled": true, - "optional": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.0.2", - "json-schema": "0.2.3", - "verror": "1.3.6" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "mime-db": { - "version": "1.27.0", - "bundled": true - }, - "mime-types": { - "version": "2.1.15", - "bundled": true, - "requires": { - "mime-db": "1.27.0" - } - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "node-pre-gyp": { - "version": "0.6.36", - "bundled": true, - "optional": true, - "requires": { - "mkdirp": "0.5.1", - "nopt": "4.0.1", - "npmlog": "4.1.0", - "rc": "1.2.1", - "request": "2.81.0", - "rimraf": "2.6.1", - "semver": "5.3.0", - "tar": "2.2.1", - "tar-pack": "3.4.0" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "optional": true, - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "npmlog": { - "version": "4.1.0", - "bundled": true, - "optional": true, - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "optional": true - }, - "osenv": { - "version": "0.1.4", - "bundled": true, - "optional": true, - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "performance-now": { - "version": "0.2.0", - "bundled": true, - "optional": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "punycode": { - "version": "1.4.1", - "bundled": true, - "optional": true - }, - "qs": { - "version": "6.4.0", - "bundled": true, - "optional": true - }, - "rc": { - "version": "1.2.1", - "bundled": true, - "optional": true, - "requires": { - "deep-extend": "0.4.2", - "ini": "1.3.4", - "minimist": "1.2.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.2.9", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "1.0.1", - "util-deprecate": "1.0.2" - } - }, - "request": { - "version": "2.81.0", - "bundled": true, - "optional": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.1.4", - "har-validator": "4.2.1", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.15", - "oauth-sign": "0.8.2", - "performance-now": "0.2.0", - "qs": "6.4.0", - "safe-buffer": "5.0.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.0.1" - } - }, - "rimraf": { - "version": "2.6.1", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "safe-buffer": { - "version": "5.0.1", - "bundled": true - }, - "semver": { - "version": "5.3.0", - "bundled": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "optional": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "optional": true, - "requires": { - "hoek": "2.16.3" - } - }, - "sshpk": { - "version": "1.13.0", - "bundled": true, - "optional": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jodid25519": "1.0.2", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - }, - "dependencies": { - "assert-plus": { - "version": "1.0.0", - "bundled": true, - "optional": true - } - } - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string_decoder": { - "version": "1.0.1", - "bundled": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "stringstream": { - "version": "0.0.5", - "bundled": true, - "optional": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "optional": true - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - }, - "tar-pack": { - "version": "3.4.0", - "bundled": true, - "optional": true, - "requires": { - "debug": "2.6.8", - "fstream": "1.0.11", - "fstream-ignore": "1.0.5", - "once": "1.4.0", - "readable-stream": "2.2.9", - "rimraf": "2.6.1", - "tar": "2.2.1", - "uid-number": "0.0.6" - } - }, - "tough-cookie": { - "version": "2.3.2", - "bundled": true, - "optional": true, - "requires": { - "punycode": "1.4.1" - } - }, - "tunnel-agent": { - "version": "0.6.0", - "bundled": true, - "optional": true, - "requires": { - "safe-buffer": "5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "bundled": true, - "optional": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true, - "optional": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.0.1", - "bundled": true, - "optional": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "optional": true, - "requires": { - "extsprintf": "1.0.2" - } - }, - "wide-align": { - "version": "1.1.2", - "bundled": true, - "optional": true, - "requires": { - "string-width": "1.0.2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - } - } - }, - "fstream": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.11.tgz", - "integrity": "sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE=", - "requires": { - "graceful-fs": "4.1.11", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.6.2" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "requires": { - "aproba": "1.2.0", - "console-control-strings": "1.1.0", - "has-unicode": "2.0.1", - "object-assign": "4.1.1", - "signal-exit": "3.0.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wide-align": "1.1.2" - } - }, - "gaze": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz", - "integrity": "sha1-hHIkZ3rbiHDWeSV+0ziP22HkAQU=", - "optional": true, - "requires": { - "globule": "1.2.0" - } - }, - "generate-function": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", - "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", - "dev": true - }, - "generate-object-property": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", - "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", - "dev": true, - "requires": { - "is-property": "1.0.2" - } - }, - "get-caller-file": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", - "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" - }, - "get-pkg-repo": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz", - "integrity": "sha1-xztInAbYDMVTbCyFP54FIyBWly0=", - "dev": true, - "requires": { - "hosted-git-info": "2.5.0", - "meow": "3.7.0", - "normalize-package-data": "2.4.0", - "parse-github-repo-url": "1.4.1", - "through2": "2.0.3" - } - }, - "get-stdin": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=" - }, - "get-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", - "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "requires": { - "assert-plus": "1.0.0" - } - }, - "git-raw-commits": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-1.2.0.tgz", - "integrity": "sha1-DzqL/ZmuDy2LkiTViJKXXppS0Dw=", - "dev": true, - "requires": { - "dargs": "4.1.0", - "lodash.template": "4.4.0", - "meow": "3.7.0", - "split2": "2.1.1", - "through2": "2.0.3" - } - }, - "git-remote-origin-url": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz", - "integrity": "sha1-UoJlna4hBxRaERJhEq0yFuxfpl8=", - "dev": true, - "requires": { - "gitconfiglocal": "1.0.0", - "pify": "2.3.0" - } - }, - "git-semver-tags": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/git-semver-tags/-/git-semver-tags-1.2.1.tgz", - "integrity": "sha512-fFyxtzTHCTQKwB4clA2AInVrlflBbVbbJD4NWwmxKXHUgsU/K9kmHNlkPLqFiuy9xu9q3lNopghR4VXeQwZbTQ==", - "dev": true, - "requires": { - "meow": "3.7.0", - "semver": "5.4.1" - } - }, - "gitconfiglocal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz", - "integrity": "sha1-QdBF84UaXqiPA/JMocYXgRRGS5s=", - "dev": true, - "requires": { - "ini": "1.3.4" - } - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "glob-base": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", - "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", - "requires": { - "glob-parent": "2.0.0", - "is-glob": "2.0.1" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "1.0.0" - } - } - } - }, - "glob-parent": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", - "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", - "requires": { - "is-glob": "2.0.1" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "1.0.0" - } - } - } - }, - "globals": { - "version": "9.18.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz", - "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==" - }, - "globby": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", - "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", - "requires": { - "array-union": "1.0.2", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "globule": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.0.tgz", - "integrity": "sha1-HcScaCLdnoovoAuiopUAboZkvQk=", - "optional": true, - "requires": { - "glob": "7.1.2", - "lodash": "4.17.4", - "minimatch": "3.0.4" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "handle-thing": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-1.2.5.tgz", - "integrity": "sha1-/Xqtcmvxpf0W38KbL3pmAdJxOcQ=" - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" - }, - "har-validator": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz", - "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=", - "requires": { - "ajv": "5.2.2", - "har-schema": "2.0.0" - } - }, - "has": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", - "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=" - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=" - }, - "hash-base": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz", - "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=", - "requires": { - "inherits": "2.0.3" - } - }, - "hash.js": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz", - "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==", - "requires": { - "inherits": "2.0.3", - "minimalistic-assert": "1.0.0" - } - }, - "hawk": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz", - "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==", - "requires": { - "boom": "4.3.1", - "cryptiles": "3.1.2", - "hoek": "4.2.0", - "sntp": "2.0.2" - } - }, - "he": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", - "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=" - }, - "hmac-drbg": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", - "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", - "requires": { - "hash.js": "1.1.3", - "minimalistic-assert": "1.0.0", - "minimalistic-crypto-utils": "1.0.1" - } - }, - "hoek": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz", - "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ==" - }, - "hosted-git-info": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", - "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==" - }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", - "requires": { - "inherits": "2.0.3", - "obuf": "1.1.1", - "readable-stream": "2.3.3", - "wbuf": "1.7.2" - } - }, - "html-comment-regex": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.1.tgz", - "integrity": "sha1-ZouTd26q5V696POtRkswekljYl4=" - }, - "html-entities": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz", - "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=" - }, - "html-minifier": { - "version": "3.5.5", - "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.5.tgz", - "integrity": "sha512-g+1+NBycQI0fGnggd52JM8TRUweG7+9W2wrtjGitMAqc4G7maweAHvVAAjz9veHseIH3tYKE2lk2USGSoewIrQ==", - "requires": { - "camel-case": "3.0.0", - "clean-css": "4.1.9", - "commander": "2.11.0", - "he": "1.1.1", - "ncname": "1.0.0", - "param-case": "2.1.1", - "relateurl": "0.2.7", - "uglify-js": "3.1.1" - } - }, - "html-webpack-plugin": { - "version": "2.30.1", - "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz", - "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=", - "requires": { - "bluebird": "3.5.0", - "html-minifier": "3.5.5", - "loader-utils": "0.2.17", - "lodash": "4.17.4", - "pretty-error": "2.1.1", - "toposort": "1.0.3" - }, - "dependencies": { - "bluebird": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", - "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" - } - } - } - }, - "htmlparser2": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.3.0.tgz", - "integrity": "sha1-zHDQWln2VC5D8OaFyYLhTJJKnv4=", - "requires": { - "domelementtype": "1.3.0", - "domhandler": "2.1.0", - "domutils": "1.1.6", - "readable-stream": "1.0.34" - }, - "dependencies": { - "domutils": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.1.6.tgz", - "integrity": "sha1-vdw94Jm5ou+sxRxiPyj0FuzFdIU=", - "requires": { - "domelementtype": "1.3.0" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" - }, - "http-errors": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", - "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", - "requires": { - "depd": "1.1.1", - "inherits": "2.0.3", - "setprototypeof": "1.0.3", - "statuses": "1.3.1" - } - }, - "http-proxy": { - "version": "1.16.2", - "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.16.2.tgz", - "integrity": "sha1-Bt/ykpUr9k2+hHH6nfcwZtTzd0I=", - "requires": { - "eventemitter3": "1.2.0", - "requires-port": "1.0.0" - } - }, - "http-proxy-middleware": { - "version": "0.17.4", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz", - "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=", - "requires": { - "http-proxy": "1.16.2", - "is-glob": "3.1.0", - "lodash": "4.17.4", - "micromatch": "2.3.11" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "requires": { - "assert-plus": "1.0.0", - "jsprim": "1.4.1", - "sshpk": "1.13.1" - } - }, - "https-browserify": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz", - "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=" - }, - "icss-replace-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz", - "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=" - }, - "icss-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-2.1.0.tgz", - "integrity": "sha1-g/Cg7DeL8yRheLbCrZE28TWxyWI=", - "requires": { - "postcss": "6.0.11" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.11.tgz", - "integrity": "sha512-DsnIzznNRQprsGTALpkC0xjDygo+QcOd+qVjP9+RjyzrPiyYOXBGOwoJ4rAiiE4lu6JggQ/jW4niY24WLxuncg==", - "requires": { - "chalk": "2.2.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "ieee754": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" - }, - "iferr": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", - "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=" - }, - "ignore": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.5.tgz", - "integrity": "sha512-JLH93mL8amZQhh/p6mfQgVBH3M6epNq3DfsXsTSuSrInVjwyYlFE1nv2AgfRCC8PoOhM0jwQ5v8s9LgbK7yGDw==", - "dev": true - }, - "image-size": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", - "integrity": "sha1-Cd/Uq50g4p6xw+gLiZA3jfnjy5w=", - "optional": true - }, - "import-local": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-0.1.1.tgz", - "integrity": "sha1-sReVcqrNwRxqkQCftDDbyrX2aKg=", - "requires": { - "pkg-dir": "2.0.0", - "resolve-cwd": "2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "in-publish": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", - "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", - "optional": true - }, - "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "requires": { - "repeating": "2.0.1" - } - }, - "indexes-of": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz", - "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=" - }, - "indexof": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", - "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "ini": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz", - "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4=", - "dev": true - }, - "inquirer": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz", - "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=", - "dev": true, - "requires": { - "ansi-escapes": "1.4.0", - "ansi-regex": "2.1.1", - "chalk": "1.1.3", - "cli-cursor": "1.0.2", - "cli-width": "2.2.0", - "figures": "1.7.0", - "lodash": "4.17.4", - "readline2": "1.0.1", - "run-async": "0.1.0", - "rx-lite": "3.1.2", - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "through": "2.3.8" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "internal-ip": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-1.2.0.tgz", - "integrity": "sha1-rp+/k7mEh4eF1QqN4bNWlWBYz1w=", - "requires": { - "meow": "3.7.0" - } - }, - "interpret": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.4.tgz", - "integrity": "sha1-ggzdWIuGj/sZGoCVBtbJyPISsbA=" - }, - "invariant": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", - "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", - "requires": { - "loose-envify": "1.3.1" - } - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" - }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" - }, - "ipaddr.js": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.4.0.tgz", - "integrity": "sha1-KWrKh4qCGBbluF0KKFqZvP9FgvA=" - }, - "is-absolute-url": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz", - "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=" - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "requires": { - "binary-extensions": "1.10.0" - } - }, - "is-buffer": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", - "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-callable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", - "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=" - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" - }, - "is-directory": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", - "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=" - }, - "is-dotfile": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", - "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=" - }, - "is-equal-shallow": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", - "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", - "requires": { - "is-primitive": "2.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "requires": { - "is-extglob": "2.1.1" - } - }, - "is-my-json-valid": { - "version": "2.16.1", - "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", - "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", - "dev": true, - "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "4.0.1", - "xtend": "4.0.1" - } - }, - "is-number": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", - "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", - "requires": { - "kind-of": "3.2.2" - } - }, - "is-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", - "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", - "dev": true - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" - }, - "is-path-in-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", - "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", - "requires": { - "is-path-inside": "1.0.0" - } - }, - "is-path-inside": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz", - "integrity": "sha1-/AbloWg/vaE95mev9xe7wQpI838=", - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=" - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "requires": { - "isobject": "3.0.1" - } - }, - "is-posix-bracket": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", - "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=" - }, - "is-primitive": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", - "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=" - }, - "is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", - "dev": true - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "requires": { - "has": "1.0.1" - } - }, - "is-resolvable": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.0.tgz", - "integrity": "sha1-jfV8YeouPFAUCNEA+wE8+NbgzGI=", - "dev": true, - "requires": { - "tryit": "1.0.3" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" - }, - "is-subset": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-subset/-/is-subset-0.1.1.tgz", - "integrity": "sha1-ilkRfZMt4d4A8kX83TnOQ/HpOaY=", - "dev": true - }, - "is-svg": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz", - "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=", - "requires": { - "html-comment-regex": "1.1.1" - } - }, - "is-symbol": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", - "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=" - }, - "is-text-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-text-path/-/is-text-path-1.0.1.tgz", - "integrity": "sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4=", - "dev": true, - "requires": { - "text-extensions": "1.6.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=" - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=" - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" - }, - "istanbul-instrumenter-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-2.0.0.tgz", - "integrity": "sha1-5UkpAKsLuoNe+oAkywC+mz7qJwA=", - "requires": { - "convert-source-map": "1.5.0", - "istanbul-lib-instrument": "1.8.0", - "loader-utils": "0.2.17", - "object-assign": "4.1.1" - }, - "dependencies": { - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" - } - } - } - }, - "istanbul-lib-coverage": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz", - "integrity": "sha512-0+1vDkmzxqJIn5rcoEqapSB4DmPxE31EtI2dF2aCkV5esN9EWHxZ0dwgDClivMXJqE7zaYQxq30hj5L0nlTN5Q==" - }, - "istanbul-lib-instrument": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-1.8.0.tgz", - "integrity": "sha1-ZvbJQhzJ7EcE928tsIS6kHiitTI=", - "requires": { - "babel-generator": "6.26.0", - "babel-template": "6.26.0", - "babel-traverse": "6.26.0", - "babel-types": "6.26.0", - "babylon": "6.18.0", - "istanbul-lib-coverage": "1.1.1", - "semver": "5.4.1" - } - }, - "jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha1-awicChFXax8W3xG4AUbZHU6Lij4=", - "dev": true, - "requires": { - "exit": "0.1.2", - "glob": "7.1.2", - "jasmine-core": "2.8.0" - } - }, - "jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha1-vMl5rh+f0FcB5F5S5l06XWPxok4=", - "dev": true - }, - "jasmine-spec-reporter": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-4.2.1.tgz", - "integrity": "sha512-FZBoZu7VE5nR7Nilzy+Np8KuVIOxF4oXDPDknehCYBDE080EnlPu0afdZNmpGDBRCUBv3mj5qgqCRmk6W/K8vg==", - "dev": true, - "requires": { - "colors": "1.1.2" - } - }, - "js-base64": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.3.2.tgz", - "integrity": "sha512-Y2/+DnfJJXT1/FCwUebUhLWb3QihxiSC42+ctHLGogmW2jPY6LCapMdFZXRvVP2z6qyKW7s6qncE/9gSqZiArw==" - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "js-yaml": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz", - "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=", - "requires": { - "argparse": "1.0.9", - "esprima": "2.7.3" - } - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "optional": true - }, - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=" - }, - "json-loader": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", - "integrity": "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w==" - }, - "json-parse-better-errors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.1.tgz", - "integrity": "sha512-xyQpxeWWMKyJps9CuGJYeng6ssI5bpqS9ltQpdVQ90t4ql6NdnxFKh95JcRt2cun/DjMVNrdjniLPuMA69xmCw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stable-stringify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", - "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", - "requires": { - "jsonify": "0.0.0" - } - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" - }, - "json3": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", - "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=" - }, - "json5": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz", - "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=" - }, - "jsonify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", - "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" - }, - "jsonparse": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", - "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", - "dev": true - }, - "jsonpointer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", - "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", - "dev": true - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "karma-source-map-support": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.2.0.tgz", - "integrity": "sha1-G/gee7SwiWJ6s1LsQXnhF8QGpUA=", - "requires": { - "source-map-support": "0.4.18" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "1.1.5" - } - }, - "lazy-cache": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", - "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=" - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "requires": { - "invert-kv": "1.0.0" - } - }, - "less": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/less/-/less-2.7.2.tgz", - "integrity": "sha1-No1sxz4fsDmBGDKAkYdDxdz5s98=", - "requires": { - "errno": "0.1.4", - "graceful-fs": "4.1.11", - "image-size": "0.5.5", - "mime": "1.4.0", - "mkdirp": "0.5.1", - "promise": "7.3.1", - "request": "2.82.0", - "source-map": "0.5.7" - } - }, - "less-loader": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-4.0.5.tgz", - "integrity": "sha1-rhVadAbKxqzSk9eFWH/P8PR4xN0=", - "requires": { - "clone": "2.1.1", - "loader-utils": "1.1.0", - "pify": "2.3.0" - }, - "dependencies": { - "clone": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.1.tgz", - "integrity": "sha1-0hfR6WERjjrJpLi7oyhVU79kfNs=" - } - } - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "license-checker": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/license-checker/-/license-checker-14.0.0.tgz", - "integrity": "sha512-NuPRmB/tICGaRuDwLoGp24oBW0e/dX9jnEYo5lR0hCTkIT1yx+Jm3x3hQ+qkgF+e2UJC59hDSJY1FPkjcxvQ0w==", - "dev": true, - "requires": { - "chalk": "0.5.1", - "debug": "2.6.8", - "mkdirp": "0.3.5", - "nopt": "2.2.1", - "read-installed": "4.0.3", - "semver": "5.4.1", - "spdx": "0.5.1", - "spdx-correct": "2.0.4", - "spdx-satisfies": "0.1.3", - "treeify": "1.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz", - "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk=", - "dev": true - }, - "ansi-styles": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz", - "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94=", - "dev": true - }, - "chalk": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz", - "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=", - "dev": true, - "requires": { - "ansi-styles": "1.1.0", - "escape-string-regexp": "1.0.5", - "has-ansi": "0.1.0", - "strip-ansi": "0.3.0", - "supports-color": "0.2.0" - } - }, - "has-ansi": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz", - "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=", - "dev": true, - "requires": { - "ansi-regex": "0.2.1" - } - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true - }, - "nopt": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.2.1.tgz", - "integrity": "sha1-KqCbfRdoSHs7ianFqlIzW/8Lrqc=", - "dev": true, - "requires": { - "abbrev": "1.1.0" - } - }, - "spdx-correct": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-2.0.4.tgz", - "integrity": "sha512-c+4gPpt9YDhz7cHlz5UrsHzxxRi4ksclxnEEKsuGT9JdwSC+ZNmsGbYRzzgxyZaBYpcWnlu+4lPcdLKx4DOCmA==", - "dev": true, - "requires": { - "spdx-expression-parse": "2.0.2", - "spdx-license-ids": "2.0.1" - } - }, - "spdx-exceptions": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.0.0.tgz", - "integrity": "sha1-aoDpnx8z5ArPSX9qQwz0mWnwE6g=", - "dev": true - }, - "spdx-expression-parse": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-2.0.2.tgz", - "integrity": "sha512-oFxOkWCfFS0ltNp0H66gXlU4NF6bxg7RkoTYR0413t+yTY9zyj+AIWsjtN8dcVp6703ijDYBWBIARlJ7DkyP9Q==", - "dev": true, - "requires": { - "spdx-exceptions": "2.0.0", - "spdx-license-ids": "2.0.1" - } - }, - "spdx-license-ids": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-2.0.1.tgz", - "integrity": "sha1-AgF7zDU07k/+9tWNIOfT6aHDyOw=", - "dev": true - }, - "strip-ansi": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz", - "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=", - "dev": true, - "requires": { - "ansi-regex": "0.2.1" - } - }, - "supports-color": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz", - "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo=", - "dev": true - } - } - }, - "license-webpack-plugin": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-1.0.1.tgz", - "integrity": "sha512-RQscYHQvaVFleUF3unLdQu6ORVVDqof2W0kM/3IFbLZheTMFXG/Y+dTU/RFaLxsBpaNN23MdPKST43D295j6JA==", - "requires": { - "ejs": "2.5.7" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - } - }, - "loader-runner": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz", - "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=" - }, - "loader-utils": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz", - "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=", - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - }, - "lodash": { - "version": "4.17.4", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", - "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=" - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash.assign": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", - "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", - "optional": true - }, - "lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=" - }, - "lodash.memoize": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", - "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" - }, - "lodash.mergewith": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz", - "integrity": "sha1-FQzwoWeR9ZA7iJHqsVRgknS96lU=", - "optional": true - }, - "lodash.tail": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.tail/-/lodash.tail-4.1.1.tgz", - "integrity": "sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=" - }, - "lodash.template": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz", - "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=", - "dev": true, - "requires": { - "lodash._reinterpolate": "3.0.0", - "lodash.templatesettings": "4.1.0" - } - }, - "lodash.templatesettings": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz", - "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=", - "dev": true, - "requires": { - "lodash._reinterpolate": "3.0.0" - } - }, - "lodash.uniq": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", - "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" - }, - "loglevel": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.4.1.tgz", - "integrity": "sha1-lbOD+Ro8J1b9SrCTZn5DCRYfK80=" - }, - "longest": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", - "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" - }, - "loose-envify": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", - "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", - "requires": { - "js-tokens": "3.0.2" - } - }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", - "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" - } - }, - "lower-case": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", - "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=" - }, - "lru-cache": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", - "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "macaddress": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/macaddress/-/macaddress-0.2.8.tgz", - "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=" - }, - "magic-string": { - "version": "0.22.4", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.22.4.tgz", - "integrity": "sha512-kxBL06p6iO2qPBHsqGK2b3cRwiRGpnmSuVWNhwHcMX7qJOUr1HvricYP1LZOCdkQBUp0jiWg2d6WJwR3vYgByw==", - "requires": { - "vlq": "0.2.2" - } - }, - "make-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.0.0.tgz", - "integrity": "sha1-l6ARdR6R3YfPre9Ygy67BJNt6Xg=", - "requires": { - "pify": "2.3.0" - } - }, - "make-error": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.0.tgz", - "integrity": "sha1-Uq06M5zPEM5itAQLcI/nByRLi5Y=", - "dev": true - }, - "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=" - }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - }, - "matcher-collection": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/matcher-collection/-/matcher-collection-1.0.5.tgz", - "integrity": "sha512-nUCmzKipcJEwYsBVAFh5P+d7JBuhJaW1xs85Hara9xuMLqtCVUrW6DSC0JVIkluxEH2W45nPBM/wjHtBXa/tYA==", - "dev": true, - "requires": { - "minimatch": "3.0.4" - } - }, - "math-expression-evaluator": { - "version": "1.2.17", - "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz", - "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=" - }, - "md5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", - "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "requires": { - "charenc": "0.0.2", - "crypt": "0.0.2", - "is-buffer": "1.1.5" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "mem": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", - "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", - "requires": { - "mimic-fn": "1.1.0" - } - }, - "memory-fs": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", - "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", - "requires": { - "errno": "0.1.4", - "readable-stream": "2.3.3" - } - }, - "memory-streams": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/memory-streams/-/memory-streams-0.1.2.tgz", - "integrity": "sha1-Jz/3d6tg/sWZsRY1UlUoLMosUMI=", - "dev": true, - "requires": { - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - } - } - }, - "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", - "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", - "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", - "requires": { - "arr-diff": "2.0.0", - "array-unique": "0.2.1", - "braces": "1.8.5", - "expand-brackets": "0.1.5", - "extglob": "0.3.2", - "filename-regex": "2.0.1", - "is-extglob": "1.0.0", - "is-glob": "2.0.1", - "kind-of": "3.2.2", - "normalize-path": "2.1.1", - "object.omit": "2.0.1", - "parse-glob": "3.0.4", - "regex-cache": "0.4.4" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "1.0.0" - } - } - } - }, - "miller-rabin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz", - "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=", - "requires": { - "bn.js": "4.11.7", - "brorand": "1.1.0" - } - }, - "mime": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz", - "integrity": "sha512-n9ChLv77+QQEapYz8lV+rIZAW3HhAPW2CXnzb1GN5uMkuczshwvkW7XPsbzU0ZQN3sP47Er2KVkp2p3KyqZKSQ==" - }, - "mime-db": { - "version": "1.30.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", - "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" - }, - "mime-types": { - "version": "2.1.17", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", - "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", - "requires": { - "mime-db": "1.30.0" - } - }, - "mimic-fn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", - "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=" - }, - "minimalistic-assert": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", - "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=" - }, - "minimalistic-crypto-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", - "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "1.1.8" - } - }, - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=" - }, - "minipass": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.2.1.tgz", - "integrity": "sha512-u1aUllxPJUI07cOqzR7reGmQxmCqlH88uIIsf6XZFEWgw7gXKpJdR+5R9Y3KEDmWYkdIz9wXZs3C0jOPxejk/Q==", - "dev": true, - "requires": { - "yallist": "3.0.2" - }, - "dependencies": { - "yallist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true - } - } - }, - "minizlib": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.0.3.tgz", - "integrity": "sha1-1cGr93vhVGGZUuJTM27Mq5sqMvU=", - "dev": true, - "requires": { - "minipass": "2.2.1" - } - }, - "mississippi": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-1.3.0.tgz", - "integrity": "sha1-0gFYPrEjJ+PFwWQqQEqcrPlONPU=", - "requires": { - "concat-stream": "1.6.0", - "duplexify": "3.5.1", - "end-of-stream": "1.4.0", - "flush-write-stream": "1.0.2", - "from2": "2.3.0", - "parallel-transform": "1.1.0", - "pump": "1.0.2", - "pumpify": "1.3.5", - "stream-each": "1.2.0", - "through2": "2.0.3" - } - }, - "mixin-object": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", - "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", - "requires": { - "for-in": "0.1.8", - "is-extendable": "0.1.1" - }, - "dependencies": { - "for-in": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", - "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=" - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } - } - }, - "mock-fs": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.4.1.tgz", - "integrity": "sha512-C8aapOvl77Bs18WCkejdLuX2kX8DaqaJ7ZmqUmX9U6HD2g31Pd0tZfNBAEVulmJWKyzUIyutrtxiIoNdXLAYsw==", - "dev": true - }, - "modify-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/modify-values/-/modify-values-1.0.0.tgz", - "integrity": "sha1-4rbN65zhn5kxelNyLz2/XfXqqrI=", - "dev": true - }, - "move-concurrently": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", - "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", - "requires": { - "aproba": "1.2.0", - "copy-concurrently": "1.0.5", - "fs-write-stream-atomic": "1.0.10", - "mkdirp": "0.5.1", - "rimraf": "2.6.2", - "run-queue": "1.0.3" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "multicast-dns": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.1.1.tgz", - "integrity": "sha1-bn3oalcIcqsXBYrepxYLvsqBTd4=", - "requires": { - "dns-packet": "1.1.1", - "thunky": "0.1.0" - } - }, - "multicast-dns-service-types": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz", - "integrity": "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=" - }, - "mute-stream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz", - "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=", - "dev": true - }, - "nan": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.7.0.tgz", - "integrity": "sha1-2Vv3IeyHfgjbJ27T/G63j5CDrUY=", - "optional": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "ncname": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz", - "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=", - "requires": { - "xml-char-classes": "1.0.0" - } - }, - "negotiator": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", - "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" - }, - "no-case": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz", - "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==", - "requires": { - "lower-case": "1.1.4" - } - }, - "node-dir": { - "version": "0.1.17", - "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", - "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", - "requires": { - "minimatch": "3.0.4" - } - }, - "node-forge": { - "version": "0.6.33", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.33.tgz", - "integrity": "sha1-RjgRh59XPUUVWtap9D3ClujoXrw=" - }, - "node-gyp": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.6.2.tgz", - "integrity": "sha1-m/vlRWIoYoSDjnUOrAUpWFP6HGA=", - "optional": true, - "requires": { - "fstream": "1.0.11", - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "4.1.2", - "osenv": "0.1.4", - "request": "2.82.0", - "rimraf": "2.6.2", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.3.0" - }, - "dependencies": { - "nopt": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", - "optional": true, - "requires": { - "abbrev": "1.1.0" - } - }, - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "optional": true - }, - "tar": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz", - "integrity": "sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE=", - "optional": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.11", - "inherits": "2.0.3" - } - } - } - }, - "node-libs-browser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz", - "integrity": "sha1-o6WeyXAkmFtG6Vg3lkb5bEthZkY=", - "requires": { - "assert": "1.4.1", - "browserify-zlib": "0.1.4", - "buffer": "4.9.1", - "console-browserify": "1.1.0", - "constants-browserify": "1.0.0", - "crypto-browserify": "3.11.0", - "domain-browser": "1.1.7", - "events": "1.1.1", - "https-browserify": "0.0.1", - "os-browserify": "0.2.1", - "path-browserify": "0.0.0", - "process": "0.11.10", - "punycode": "1.4.1", - "querystring-es3": "0.2.1", - "readable-stream": "2.3.3", - "stream-browserify": "2.0.1", - "stream-http": "2.7.2", - "string_decoder": "0.10.31", - "timers-browserify": "2.0.2", - "tty-browserify": "0.0.0", - "url": "0.11.0", - "util": "0.10.3", - "vm-browserify": "0.0.4" - }, - "dependencies": { - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" - } - } - }, - "node-modules-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/node-modules-path/-/node-modules-path-1.0.1.tgz", - "integrity": "sha1-QAlrCM560OoUaAhjr0ScfHWl0cg=" - }, - "node-sass": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.5.3.tgz", - "integrity": "sha1-0JydEXlkEjnRuX/8YjH9zsU+FWg=", - "optional": true, - "requires": { - "async-foreach": "0.1.3", - "chalk": "1.1.3", - "cross-spawn": "3.0.1", - "gaze": "1.1.2", - "get-stdin": "4.0.1", - "glob": "7.1.2", - "in-publish": "2.0.0", - "lodash.assign": "4.2.0", - "lodash.clonedeep": "4.5.0", - "lodash.mergewith": "4.6.0", - "meow": "3.7.0", - "mkdirp": "0.5.1", - "nan": "2.7.0", - "node-gyp": "3.6.2", - "npmlog": "4.1.2", - "request": "2.82.0", - "sass-graph": "2.2.4", - "stdout-stream": "1.4.0" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "optional": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "optional": true - } - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1.1.0", - "osenv": "0.1.4" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "requires": { - "hosted-git-info": "2.5.0", - "is-builtin-module": "1.0.0", - "semver": "5.4.1", - "validate-npm-package-license": "3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "requires": { - "remove-trailing-separator": "1.1.0" - } - }, - "normalize-range": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=" - }, - "normalize-url": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", - "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", - "requires": { - "object-assign": "4.1.1", - "prepend-http": "1.0.4", - "query-string": "4.3.4", - "sort-keys": "1.1.2" - } - }, - "npm-path": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/npm-path/-/npm-path-2.0.3.tgz", - "integrity": "sha1-Fc/04ciaONp39W9gVbJPl137K74=", - "dev": true, - "requires": { - "which": "1.3.0" - } - }, - "npm-run": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npm-run/-/npm-run-4.1.2.tgz", - "integrity": "sha1-EDDh7FaQjIn8w/o2bQOiwrqY65k=", - "dev": true, - "requires": { - "cross-spawn": "5.1.0", - "minimist": "1.2.0", - "npm-path": "2.0.3", - "npm-which": "3.0.1", - "serializerr": "1.0.3", - "sync-exec": "0.6.2" - }, - "dependencies": { - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - } - } - }, - "npm-run-all": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.1.tgz", - "integrity": "sha512-qrmqqaJa+REbzUTIL/mHfTdgwz+gL1xUezY/ueyLa7GISZ4T3h0CH8D2r6AaZdCYN2unu7PzspP0ofpXla1ftg==", - "dev": true, - "requires": { - "ansi-styles": "3.2.0", - "chalk": "2.2.0", - "cross-spawn": "5.1.0", - "memory-streams": "0.1.2", - "minimatch": "3.0.4", - "ps-tree": "1.1.0", - "read-pkg": "2.0.0", - "shell-quote": "1.6.1", - "string.prototype.padend": "3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "dev": true, - "requires": { - "color-convert": "1.9.0" - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "dev": true, - "requires": { - "lru-cache": "4.1.1", - "shebang-command": "1.2.0", - "which": "1.3.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "2.3.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "requires": { - "path-key": "2.0.1" - } - }, - "npm-which": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/npm-which/-/npm-which-3.0.1.tgz", - "integrity": "sha1-kiXybsOihcIJyuZ8OxGmtKtxQKo=", - "dev": true, - "requires": { - "commander": "2.11.0", - "npm-path": "2.0.3", - "which": "1.3.0" - } - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "requires": { - "are-we-there-yet": "1.1.4", - "console-control-strings": "1.1.0", - "gauge": "2.7.4", - "set-blocking": "2.0.0" - } - }, - "nth-check": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz", - "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=", - "requires": { - "boolbase": "1.0.0" - } - }, - "num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" - }, - "oauth-sign": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", - "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=" - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-keys": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", - "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" - }, - "object.omit": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", - "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", - "requires": { - "for-own": "0.1.5", - "is-extendable": "0.1.1" - }, - "dependencies": { - "for-own": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", - "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", - "requires": { - "for-in": "1.0.2" - } - } - } - }, - "obuf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.1.tgz", - "integrity": "sha1-EEEktsYCxnlogaBCVB0220OlJk4=" - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "on-headers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", - "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz", - "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=", - "dev": true - }, - "opn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.1.0.tgz", - "integrity": "sha512-iPNl7SyM8L30Rm1sjGdLLheyHVw5YXVfi3SKWJzBI7efxRwHojfRFjwE/OLM6qp9xJYMgab8WicTU1cPoY+Hpg==", - "requires": { - "is-wsl": "1.1.0" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "original": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/original/-/original-1.0.0.tgz", - "integrity": "sha1-kUf5P6FpbQS+YeAb1QuurKZWvTs=", - "requires": { - "url-parse": "1.0.5" - }, - "dependencies": { - "url-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.0.5.tgz", - "integrity": "sha1-CFSGBCKv3P7+tsllxmLUgAFpkns=", - "requires": { - "querystringify": "0.0.4", - "requires-port": "1.0.0" - } - } - } - }, - "os-browserify": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz", - "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=" - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "requires": { - "lcid": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz", - "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=", - "requires": { - "os-homedir": "1.0.2", - "os-tmpdir": "1.0.2" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" - }, - "p-limit": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", - "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=" - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "1.1.0" - } - }, - "p-map": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-1.1.1.tgz", - "integrity": "sha1-BfXkrpegaDcbwqXMhr+9vBnErno=" - }, - "pako": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz", - "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=" - }, - "parallel-transform": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.1.0.tgz", - "integrity": "sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=", - "requires": { - "cyclist": "0.2.2", - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "param-case": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz", - "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=", - "requires": { - "no-case": "2.3.2" - } - }, - "parse-asn1": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz", - "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=", - "requires": { - "asn1.js": "4.9.1", - "browserify-aes": "1.0.6", - "create-hash": "1.1.3", - "evp_bytestokey": "1.0.0", - "pbkdf2": "3.0.12" - } - }, - "parse-github-repo-url": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz", - "integrity": "sha1-nn2LslKmy2ukJZUGC3v23z28H1A=", - "dev": true - }, - "parse-glob": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", - "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", - "requires": { - "glob-base": "0.3.0", - "is-dotfile": "1.0.3", - "is-extglob": "1.0.0", - "is-glob": "2.0.1" - }, - "dependencies": { - "is-extglob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", - "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=" - }, - "is-glob": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", - "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", - "requires": { - "is-extglob": "1.0.0" - } - } - } - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "1.3.1" - } - }, - "parseurl": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", - "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" - }, - "path-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", - "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=" - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" - }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "requires": { - "through": "2.3.8" - } - }, - "pbkdf2": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.12.tgz", - "integrity": "sha1-vjZ4XFBn6kjYBv+SMojF91C2uKI=", - "requires": { - "create-hash": "1.1.3", - "create-hmac": "1.1.6", - "ripemd160": "2.0.1", - "safe-buffer": "5.1.1", - "sha.js": "2.4.8" - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", - "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", - "requires": { - "find-up": "2.1.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "2.0.0" - } - } - } - }, - "pluralize": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz", - "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=", - "dev": true - }, - "portfinder": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.13.tgz", - "integrity": "sha1-uzLs2HwnEErm7kS1o8y/Drsa7ek=", - "requires": { - "async": "1.5.2", - "debug": "2.6.8", - "mkdirp": "0.5.1" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" - } - } - }, - "postcss": { - "version": "5.2.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.17.tgz", - "integrity": "sha1-z09Ze4ZNZcikkrLqvp1wbIecOIs=", - "requires": { - "chalk": "1.1.3", - "js-base64": "2.3.2", - "source-map": "0.5.7", - "supports-color": "3.2.3" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - }, - "dependencies": { - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - } - } - }, - "postcss-calc": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz", - "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=", - "requires": { - "postcss": "5.2.17", - "postcss-message-helpers": "2.0.0", - "reduce-css-calc": "1.3.0" - } - }, - "postcss-colormin": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz", - "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=", - "requires": { - "colormin": "1.1.2", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-convert-values": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz", - "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=", - "requires": { - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-custom-properties": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/postcss-custom-properties/-/postcss-custom-properties-6.1.0.tgz", - "integrity": "sha1-nK8RUaxBsenmTTov+ezplsoYl30=", - "requires": { - "balanced-match": "1.0.0", - "postcss": "6.0.11" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.11.tgz", - "integrity": "sha512-DsnIzznNRQprsGTALpkC0xjDygo+QcOd+qVjP9+RjyzrPiyYOXBGOwoJ4rAiiE4lu6JggQ/jW4niY24WLxuncg==", - "requires": { - "chalk": "2.2.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-discard-comments": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz", - "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-discard-duplicates": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz", - "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-discard-empty": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz", - "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-discard-overridden": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz", - "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-discard-unused": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz", - "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=", - "requires": { - "postcss": "5.2.17", - "uniqs": "2.0.0" - } - }, - "postcss-filter-plugins": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz", - "integrity": "sha1-bYWGJTTXNaxCDkqFgG4fXUKG2Ew=", - "requires": { - "postcss": "5.2.17", - "uniqid": "4.1.1" - } - }, - "postcss-load-config": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-1.2.0.tgz", - "integrity": "sha1-U56a/J3chiASHr+djDZz4M5Q0oo=", - "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1", - "postcss-load-options": "1.2.0", - "postcss-load-plugins": "2.3.0" - } - }, - "postcss-load-options": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-load-options/-/postcss-load-options-1.2.0.tgz", - "integrity": "sha1-sJixVZ3awt8EvAuzdfmaXP4rbYw=", - "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1" - } - }, - "postcss-load-plugins": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz", - "integrity": "sha1-dFdoEWWZrKLwCfrUJrABdQSdjZI=", - "requires": { - "cosmiconfig": "2.2.2", - "object-assign": "4.1.1" - } - }, - "postcss-loader": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-2.0.8.tgz", - "integrity": "sha512-KtXBiQ/r/WYW8LxTSJK7h8wLqvCMSub/BqmRnud/Mu8RzwflW9cmXxwsMwbn15TNv287Hcufdb3ZSs7xHKnG8Q==", - "requires": { - "loader-utils": "1.1.0", - "postcss": "6.0.14", - "postcss-load-config": "1.2.0", - "schema-utils": "0.3.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "requires": { - "color-convert": "1.9.0" - } - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz", - "integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==", - "requires": { - "chalk": "2.3.0", - "source-map": "0.6.1", - "supports-color": "4.5.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-merge-idents": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz", - "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=", - "requires": { - "has": "1.0.1", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-merge-longhand": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz", - "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-merge-rules": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz", - "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=", - "requires": { - "browserslist": "1.7.7", - "caniuse-api": "1.6.1", - "postcss": "5.2.17", - "postcss-selector-parser": "2.2.3", - "vendors": "1.0.1" - } - }, - "postcss-message-helpers": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz", - "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=" - }, - "postcss-minify-font-values": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz", - "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=", - "requires": { - "object-assign": "4.1.1", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-minify-gradients": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz", - "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=", - "requires": { - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-minify-params": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz", - "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=", - "requires": { - "alphanum-sort": "1.0.2", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0", - "uniqs": "2.0.0" - } - }, - "postcss-minify-selectors": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz", - "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=", - "requires": { - "alphanum-sort": "1.0.2", - "has": "1.0.1", - "postcss": "5.2.17", - "postcss-selector-parser": "2.2.3" - } - }, - "postcss-modules-extract-imports": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.1.0.tgz", - "integrity": "sha1-thTJcgvmgW6u41+zpfqh26agXds=", - "requires": { - "postcss": "6.0.11" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.11.tgz", - "integrity": "sha512-DsnIzznNRQprsGTALpkC0xjDygo+QcOd+qVjP9+RjyzrPiyYOXBGOwoJ4rAiiE4lu6JggQ/jW4niY24WLxuncg==", - "requires": { - "chalk": "2.2.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-modules-local-by-default": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz", - "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=", - "requires": { - "css-selector-tokenizer": "0.7.0", - "postcss": "6.0.11" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.11.tgz", - "integrity": "sha512-DsnIzznNRQprsGTALpkC0xjDygo+QcOd+qVjP9+RjyzrPiyYOXBGOwoJ4rAiiE4lu6JggQ/jW4niY24WLxuncg==", - "requires": { - "chalk": "2.2.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-modules-scope": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz", - "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=", - "requires": { - "css-selector-tokenizer": "0.7.0", - "postcss": "6.0.11" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.11.tgz", - "integrity": "sha512-DsnIzznNRQprsGTALpkC0xjDygo+QcOd+qVjP9+RjyzrPiyYOXBGOwoJ4rAiiE4lu6JggQ/jW4niY24WLxuncg==", - "requires": { - "chalk": "2.2.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-modules-values": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz", - "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=", - "requires": { - "icss-replace-symbols": "1.1.0", - "postcss": "6.0.11" - }, - "dependencies": { - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.11", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.11.tgz", - "integrity": "sha512-DsnIzznNRQprsGTALpkC0xjDygo+QcOd+qVjP9+RjyzrPiyYOXBGOwoJ4rAiiE4lu6JggQ/jW4niY24WLxuncg==", - "requires": { - "chalk": "2.2.0", - "source-map": "0.5.7", - "supports-color": "4.4.0" - } - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-normalize-charset": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz", - "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-normalize-url": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz", - "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=", - "requires": { - "is-absolute-url": "2.1.0", - "normalize-url": "1.9.1", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-ordered-values": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz", - "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=", - "requires": { - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-reduce-idents": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz", - "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=", - "requires": { - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-reduce-initial": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz", - "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=", - "requires": { - "postcss": "5.2.17" - } - }, - "postcss-reduce-transforms": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz", - "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=", - "requires": { - "has": "1.0.1", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0" - } - }, - "postcss-selector-parser": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz", - "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=", - "requires": { - "flatten": "1.0.2", - "indexes-of": "1.0.1", - "uniq": "1.0.1" - } - }, - "postcss-svgo": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz", - "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=", - "requires": { - "is-svg": "2.1.0", - "postcss": "5.2.17", - "postcss-value-parser": "3.3.0", - "svgo": "0.7.2" - } - }, - "postcss-unique-selectors": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz", - "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=", - "requires": { - "alphanum-sort": "1.0.2", - "postcss": "5.2.17", - "uniqs": "2.0.0" - } - }, - "postcss-url": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/postcss-url/-/postcss-url-7.1.2.tgz", - "integrity": "sha1-4Erjhq9+pu9d9RxbRJ1rlQLNmbI=", - "requires": { - "mime": "1.4.0", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "postcss": "6.0.14", - "xxhashjs": "0.2.1" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", - "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", - "requires": { - "color-convert": "1.9.0" - } - }, - "chalk": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", - "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", - "requires": { - "ansi-styles": "3.2.0", - "escape-string-regexp": "1.0.5", - "supports-color": "4.5.0" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "postcss": { - "version": "6.0.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.14.tgz", - "integrity": "sha512-NJ1z0f+1offCgadPhz+DvGm5Mkci+mmV5BqD13S992o0Xk9eElxUfPPF+t2ksH5R/17gz4xVK8KWocUQ5o3Rog==", - "requires": { - "chalk": "2.3.0", - "source-map": "0.6.1", - "supports-color": "4.5.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - }, - "supports-color": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", - "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", - "requires": { - "has-flag": "2.0.0" - } - } - } - }, - "postcss-value-parser": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz", - "integrity": "sha1-h/OPnxj3dKSrTIojL1xc6IcqnRU=" - }, - "postcss-zindex": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz", - "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=", - "requires": { - "has": "1.0.1", - "postcss": "5.2.17", - "uniqs": "2.0.0" - } - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "prepend-http": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", - "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=" - }, - "preserve": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", - "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=" - }, - "pretty-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", - "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=", - "requires": { - "renderkid": "2.0.1", - "utila": "0.4.0" - } - }, - "process": { - "version": "0.11.10", - "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", - "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" - }, - "process-nextick-args": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", - "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" - }, - "progress": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", - "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=", - "dev": true - }, - "promise": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", - "optional": true, - "requires": { - "asap": "2.0.6" - } - }, - "promise-inflight": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=" - }, - "protochain": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/protochain/-/protochain-1.0.5.tgz", - "integrity": "sha1-mRxAfpneJkqt+PgVBLXn+ve/omA=", - "dev": true - }, - "proxy-addr": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", - "integrity": "sha1-ccDuOxAt4/IC87ZPYI0XP8uhqRg=", - "requires": { - "forwarded": "0.1.2", - "ipaddr.js": "1.4.0" - } - }, - "prr": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz", - "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=" - }, - "ps-tree": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.1.0.tgz", - "integrity": "sha1-tCGyQUDWID8e08dplrRCewjowBQ=", - "dev": true, - "requires": { - "event-stream": "3.3.4" - } - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "public-encrypt": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz", - "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=", - "requires": { - "bn.js": "4.11.7", - "browserify-rsa": "4.0.1", - "create-hash": "1.1.3", - "parse-asn1": "5.1.0", - "randombytes": "2.0.5" - } - }, - "pump": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.2.tgz", - "integrity": "sha1-Oz7mUS+U8OV1U4wXmV+fFpkKXVE=", - "requires": { - "end-of-stream": "1.4.0", - "once": "1.4.0" - } - }, - "pumpify": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.3.5.tgz", - "integrity": "sha1-G2ccYZlAq8rqwK0OOjwWS+dgmTs=", - "requires": { - "duplexify": "3.5.1", - "inherits": "2.0.3", - "pump": "1.0.2" - } - }, - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" - }, - "q": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/q/-/q-1.5.0.tgz", - "integrity": "sha1-3QG6ydBtMObyGa7LglPunr3DCPE=" - }, - "qs": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", - "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" - }, - "query-string": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", - "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", - "requires": { - "object-assign": "4.1.1", - "strict-uri-encode": "1.1.0" - } - }, - "querystring": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" - }, - "querystring-es3": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", - "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" - }, - "querystringify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-0.0.4.tgz", - "integrity": "sha1-DPf4T5Rj/wrlHExLFC2VvjdyTZw=" - }, - "randomatic": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz", - "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==", - "requires": { - "is-number": "3.0.0", - "kind-of": "4.0.0" - }, - "dependencies": { - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "requires": { - "kind-of": "3.2.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "requires": { - "is-buffer": "1.1.5" - } - } - } - }, - "randombytes": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz", - "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "range-parser": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", - "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" - }, - "raw-loader": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-0.5.1.tgz", - "integrity": "sha1-DD0L6u2KAclm2Xh793goElKpeao=" - }, - "read-installed": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/read-installed/-/read-installed-4.0.3.tgz", - "integrity": "sha1-/5uLZ/GH0eTCm5/rMfayI6zRkGc=", - "dev": true, - "requires": { - "debuglog": "1.0.1", - "graceful-fs": "4.1.11", - "read-package-json": "2.0.12", - "readdir-scoped-modules": "1.0.2", - "semver": "5.4.1", - "slide": "1.1.6", - "util-extend": "1.0.3" - } - }, - "read-package-json": { - "version": "2.0.12", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-2.0.12.tgz", - "integrity": "sha512-m7/I0+tP6D34EVvSlzCtuVA4D/dHL6OpLcn2e4XVP5X57pCKGUy1JjRSBVKHWpB+vUU91sL85h84qX0MdXzBSw==", - "dev": true, - "requires": { - "glob": "7.1.2", - "graceful-fs": "4.1.11", - "json-parse-better-errors": "1.0.1", - "normalize-package-data": "2.4.0", - "slash": "1.0.0" - } - }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - } - }, - "readable-stream": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", - "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "safe-buffer": "5.1.1", - "string_decoder": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "readdir-scoped-modules": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz", - "integrity": "sha1-n6+jfShr5dksuuve4DDcm19AZ0c=", - "dev": true, - "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "graceful-fs": "4.1.11", - "once": "1.4.0" - } - }, - "readdirp": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz", - "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=", - "requires": { - "graceful-fs": "4.1.11", - "minimatch": "3.0.4", - "readable-stream": "2.3.3", - "set-immediate-shim": "1.0.1" - } - }, - "readline2": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz", - "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=", - "dev": true, - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "mute-stream": "0.0.5" - } - }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "requires": { - "resolve": "1.4.0" - } - }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", - "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" - } - }, - "reduce-css-calc": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz", - "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=", - "requires": { - "balanced-match": "0.4.2", - "math-expression-evaluator": "1.2.17", - "reduce-function-call": "1.0.2" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" - } - } - }, - "reduce-function-call": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz", - "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=", - "requires": { - "balanced-match": "0.4.2" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", - "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=" - } - } - }, - "reflect-metadata": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.10.tgz", - "integrity": "sha1-tPg3BEFqytiZiMmxVjXUfgO5NEo=", - "dev": true - }, - "regenerate": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.3.tgz", - "integrity": "sha512-jVpo1GadrDAK59t/0jRx5VxYWQEDkkEKi6+HjE3joFVLfDOh9Xrdh0dF1eSq+BI/SwvTQ44gSscJ8N5zYL61sg==" - }, - "regenerator-runtime": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz", - "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A==" - }, - "regex-cache": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", - "requires": { - "is-equal-shallow": "0.1.3" - } - }, - "regexpu-core": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz", - "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=", - "requires": { - "regenerate": "1.3.3", - "regjsgen": "0.2.0", - "regjsparser": "0.1.5" - } - }, - "regjsgen": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz", - "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=" - }, - "regjsparser": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz", - "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=", - "requires": { - "jsesc": "0.5.0" - } - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=" - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=" - }, - "renderkid": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.1.tgz", - "integrity": "sha1-iYyr/Ivt5Le5ETWj/9Mj5YwNsxk=", - "requires": { - "css-select": "1.2.0", - "dom-converter": "0.1.4", - "htmlparser2": "3.3.0", - "strip-ansi": "3.0.1", - "utila": "0.3.3" - }, - "dependencies": { - "utila": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.3.3.tgz", - "integrity": "sha1-1+jn1+MJEHCSsF+NloiCTWM6QiY=" - } - } - }, - "repeat-element": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz", - "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=" - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" - }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", - "requires": { - "is-finite": "1.0.2" - } - }, - "request": { - "version": "2.82.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.82.0.tgz", - "integrity": "sha512-/QWqfmyTfQ4OYs6EhB1h2wQsX9ZxbuNePCvCm0Mdz/mxw73mjdg0D4QdIl0TQBFs35CZmMXLjk0iCGK395CUDg==", - "requires": { - "aws-sign2": "0.7.0", - "aws4": "1.6.0", - "caseless": "0.12.0", - "combined-stream": "1.0.5", - "extend": "3.0.1", - "forever-agent": "0.6.1", - "form-data": "2.3.1", - "har-validator": "5.0.3", - "hawk": "6.0.2", - "http-signature": "1.2.0", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.17", - "oauth-sign": "0.8.2", - "performance-now": "2.1.0", - "qs": "6.5.1", - "safe-buffer": "5.1.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.2", - "tunnel-agent": "0.6.0", - "uuid": "3.1.0" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" - }, - "require-from-string": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-1.2.1.tgz", - "integrity": "sha1-UpyczvJzgK3+yaL5ZbZJu+5jZBg=" - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "dev": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" - }, - "resolve": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.4.0.tgz", - "integrity": "sha512-aW7sVKPufyHqOmyyLzg/J+8606v5nevBgaliIlV7nUpVMsDnoBGV/cbSLNjZAg9q0Cfd/+easKVKQ8vOu8fn1Q==", - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-bin": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/resolve-bin/-/resolve-bin-0.4.0.tgz", - "integrity": "sha1-RxMiSYkRAa+xmZH+k3ywpfBy5dk=", - "dev": true, - "requires": { - "find-parent-dir": "0.3.0" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "requires": { - "resolve-from": "3.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=" - } - } - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", - "dev": true - }, - "restore-cursor": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz", - "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=", - "dev": true, - "requires": { - "exit-hook": "1.1.1", - "onetime": "1.1.0" - } - }, - "rewire": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/rewire/-/rewire-2.5.2.tgz", - "integrity": "sha1-ZCfee3/u+n02QBUH62SlOFvFjcc=", - "dev": true - }, - "right-align": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", - "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", - "requires": { - "align-text": "0.1.4" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "requires": { - "glob": "7.1.2" - } - }, - "ripemd160": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz", - "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=", - "requires": { - "hash-base": "2.0.2", - "inherits": "2.0.3" - } - }, - "run-async": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz", - "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=", - "dev": true, - "requires": { - "once": "1.4.0" - } - }, - "run-queue": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", - "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", - "requires": { - "aproba": "1.2.0" - } - }, - "rx-lite": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz", - "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=", - "dev": true - }, - "rxjs": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-5.5.2.tgz", - "integrity": "sha512-oRYoIKWBU3Ic37fLA5VJu31VqQO4bWubRntcHSJ+cwaDQBwdnZ9x4zmhJfm/nFQ2E82/I4loSioHnACamrKGgA==", - "requires": { - "symbol-observable": "1.0.4" - } - }, - "safe-buffer": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", - "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" - }, - "sass-graph": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", - "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", - "optional": true, - "requires": { - "glob": "7.1.2", - "lodash": "4.17.4", - "scss-tokenizer": "0.2.3", - "yargs": "7.1.0" - } - }, - "sass-loader": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-6.0.6.tgz", - "integrity": "sha512-c3/Zc+iW+qqDip6kXPYLEgsAu2lf4xz0EZDplB7EmSUMda12U1sGJPetH55B/j9eu0bTtKzKlNPWWyYC7wFNyQ==", - "requires": { - "async": "2.5.0", - "clone-deep": "0.3.0", - "loader-utils": "1.1.0", - "lodash.tail": "4.1.1", - "pify": "3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=" - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" - }, - "schema-utils": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-0.3.0.tgz", - "integrity": "sha1-9YdyIs4+kx7a4DnxfrNxbnE3+M8=", - "requires": { - "ajv": "5.2.2" - } - }, - "scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", - "optional": true, - "requires": { - "js-base64": "2.3.2", - "source-map": "0.4.4" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "optional": true, - "requires": { - "amdefine": "1.0.1" - } - } - } - }, - "select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" - }, - "selfsigned": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-1.9.1.tgz", - "integrity": "sha1-zdpEktcNSGVw+HxlVGAjVY4d+lo=", - "requires": { - "node-forge": "0.6.33" - } - }, - "semver": { - "version": "5.4.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", - "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==" - }, - "send": { - "version": "0.15.4", - "resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz", - "integrity": "sha1-mF+qPihLAnPHkzZKNcZze9k5Bbk=", - "requires": { - "debug": "2.6.8", - "depd": "1.1.1", - "destroy": "1.0.4", - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "etag": "1.8.1", - "fresh": "0.5.0", - "http-errors": "1.6.2", - "mime": "1.3.4", - "ms": "2.0.0", - "on-finished": "2.3.0", - "range-parser": "1.2.0", - "statuses": "1.3.1" - }, - "dependencies": { - "mime": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", - "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=" - } - } - }, - "serializerr": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/serializerr/-/serializerr-1.0.3.tgz", - "integrity": "sha1-EtTFqhw/+49tHcXzlaqUVVacP5E=", - "dev": true, - "requires": { - "protochain": "1.0.5" - } - }, - "serve-index": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.0.tgz", - "integrity": "sha1-0rKA/FYNYW7oG0i/D6gqvtJIXOc=", - "requires": { - "accepts": "1.3.4", - "batch": "0.6.1", - "debug": "2.6.8", - "escape-html": "1.0.3", - "http-errors": "1.6.2", - "mime-types": "2.1.17", - "parseurl": "1.3.2" - } - }, - "serve-static": { - "version": "1.12.4", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz", - "integrity": "sha1-m2qpjutyU8Tu3Ewfb9vKYJkBqWE=", - "requires": { - "encodeurl": "1.0.1", - "escape-html": "1.0.3", - "parseurl": "1.3.2", - "send": "0.15.4" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" - }, - "set-immediate-shim": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", - "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=" - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" - }, - "setprototypeof": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", - "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" - }, - "sha.js": { - "version": "2.4.8", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz", - "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=", - "requires": { - "inherits": "2.0.3" - } - }, - "shallow-clone": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", - "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", - "requires": { - "is-extendable": "0.1.1", - "kind-of": "2.0.1", - "lazy-cache": "0.2.7", - "mixin-object": "2.0.1" - }, - "dependencies": { - "kind-of": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", - "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", - "requires": { - "is-buffer": "1.1.5" - } - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "shell-quote": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz", - "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=", - "dev": true, - "requires": { - "array-filter": "0.0.1", - "array-map": "0.0.0", - "array-reduce": "0.0.0", - "jsonify": "0.0.0" - } - }, - "shelljs": { - "version": "0.7.8", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz", - "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=", - "dev": true, - "requires": { - "glob": "7.1.2", - "interpret": "1.0.4", - "rechoir": "0.6.2" - } - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "silent-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/silent-error/-/silent-error-1.1.0.tgz", - "integrity": "sha1-IglwbxyFCp8dENDYQJGLRvJuG8k=", - "requires": { - "debug": "2.6.8" - } - }, - "slash": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz", - "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=", - "dev": true - }, - "slice-ansi": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz", - "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=", - "dev": true - }, - "slide": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", - "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", - "dev": true - }, - "sntp": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.0.2.tgz", - "integrity": "sha1-UGQRDwr4X3z9t9a2ekACjOUrSys=", - "requires": { - "hoek": "4.2.0" - } - }, - "sockjs": { - "version": "0.3.18", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.18.tgz", - "integrity": "sha1-2bKJMWyn33dZXvKZ4HXw+TfrQgc=", - "requires": { - "faye-websocket": "0.10.0", - "uuid": "2.0.3" - }, - "dependencies": { - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - } - } - }, - "sockjs-client": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.1.4.tgz", - "integrity": "sha1-W6vjhrd15M8U51IJEUUmVAFsixI=", - "requires": { - "debug": "2.6.8", - "eventsource": "0.1.6", - "faye-websocket": "0.11.1", - "inherits": "2.0.3", - "json3": "3.3.2", - "url-parse": "1.1.9" - }, - "dependencies": { - "faye-websocket": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.1.tgz", - "integrity": "sha1-8O/hjE9W5PQK/H4Gxxn9XuYYjzg=", - "requires": { - "websocket-driver": "0.6.5" - } - } - } - }, - "sort-keys": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", - "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", - "requires": { - "is-plain-obj": "1.1.0" - } - }, - "source-list-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", - "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==" - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" - }, - "source-map-loader": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-0.2.1.tgz", - "integrity": "sha1-SBJr6SML1H+tBeRqjDwuPS2r5Qc=", - "requires": { - "async": "0.9.2", - "loader-utils": "0.2.17", - "source-map": "0.1.43" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", - "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=" - }, - "loader-utils": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz", - "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=", - "requires": { - "big.js": "3.2.0", - "emojis-list": "2.1.0", - "json5": "0.5.1", - "object-assign": "4.1.1" - } - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "requires": { - "amdefine": "1.0.1" - } - } - } - }, - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "requires": { - "source-map": "0.5.7" - } - }, - "spdx": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/spdx/-/spdx-0.5.1.tgz", - "integrity": "sha1-02wnUIi0jXWpBGzUSoOM5LUzmZg=", - "dev": true, - "requires": { - "spdx-exceptions": "1.0.5", - "spdx-license-ids": "1.2.2" - } - }, - "spdx-compare": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/spdx-compare/-/spdx-compare-0.1.2.tgz", - "integrity": "sha1-sGrz6jSvdDfZGp9Enq8tLpPDyPs=", - "dev": true, - "requires": { - "spdx-expression-parse": "1.0.4", - "spdx-ranges": "1.0.1" - } - }, - "spdx-correct": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", - "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-exceptions": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-1.0.5.tgz", - "integrity": "sha1-nSGsTaS9tx0GD7dOWmdTHQMsu6Y=", - "dev": true - }, - "spdx-expression-parse": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", - "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=" - }, - "spdx-license-ids": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", - "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=" - }, - "spdx-ranges": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/spdx-ranges/-/spdx-ranges-1.0.1.tgz", - "integrity": "sha1-D07se46kjtIC43S7iULo0Y3AET4=", - "dev": true - }, - "spdx-satisfies": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/spdx-satisfies/-/spdx-satisfies-0.1.3.tgz", - "integrity": "sha1-Z6HydOYRXUquKK/kdNt2FkvhC9w=", - "dev": true, - "requires": { - "spdx-compare": "0.1.2", - "spdx-expression-parse": "1.0.4" - } - }, - "spdy": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-3.4.7.tgz", - "integrity": "sha1-Qv9B7OXMD5mjpsKKq7c/XDsDrLw=", - "requires": { - "debug": "2.6.8", - "handle-thing": "1.2.5", - "http-deceiver": "1.2.7", - "safe-buffer": "5.1.1", - "select-hose": "2.0.0", - "spdy-transport": "2.0.20" - } - }, - "spdy-transport": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-2.0.20.tgz", - "integrity": "sha1-c15yBUxIayNU/onnAiVgBKOazk0=", - "requires": { - "debug": "2.6.8", - "detect-node": "2.0.3", - "hpack.js": "2.1.6", - "obuf": "1.1.1", - "readable-stream": "2.3.3", - "safe-buffer": "5.1.1", - "wbuf": "1.7.2" - } - }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "requires": { - "through": "2.3.8" - } - }, - "split2": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/split2/-/split2-2.1.1.tgz", - "integrity": "sha1-eh9VHhdqkOzTNF9yRqDP4XXvT9A=", - "dev": true, - "requires": { - "through2": "2.0.3" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "sshpk": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", - "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "bcrypt-pbkdf": "1.0.1", - "dashdash": "1.14.1", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.7", - "jsbn": "0.1.1", - "tweetnacl": "0.14.5" - } - }, - "ssri": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-5.0.0.tgz", - "integrity": "sha512-728D4yoQcQm1ooZvSbywLkV1RjfITZXh0oWrhM/lnsx3nAHx7LsRGJWB/YyvoceAYRq98xqbstiN4JBv1/wNHg==", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "statuses": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", - "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" - }, - "stdout-stream": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz", - "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=", - "optional": true, - "requires": { - "readable-stream": "2.3.3" - } - }, - "stream-browserify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz", - "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=", - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.3.3" - } - }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "0.1.1" - } - }, - "stream-each": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.0.tgz", - "integrity": "sha1-HpXUdXP1gNgU3A/4zQ9m8c5TyZE=", - "requires": { - "end-of-stream": "1.4.0", - "stream-shift": "1.0.0" - } - }, - "stream-http": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz", - "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==", - "requires": { - "builtin-status-codes": "3.0.0", - "inherits": "2.0.3", - "readable-stream": "2.3.3", - "to-arraybuffer": "1.0.1", - "xtend": "4.0.1" - } - }, - "stream-shift": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", - "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=" - }, - "strict-uri-encode": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", - "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - }, - "string.prototype.padend": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", - "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", - "dev": true, - "requires": { - "define-properties": "1.1.2", - "es-abstract": "1.8.2", - "function-bind": "1.1.1" - } - }, - "string_decoder": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", - "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "stringstream": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", - "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=" - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "requires": { - "is-utf8": "0.2.1" - } - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" - }, - "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", - "requires": { - "get-stdin": "4.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true - }, - "style-loader": { - "version": "0.13.2", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.2.tgz", - "integrity": "sha1-dFMzhM9pjHEEx5URULSXF63C87s=", - "requires": { - "loader-utils": "1.1.0" - } - }, - "stylus": { - "version": "0.54.5", - "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz", - "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=", - "requires": { - "css-parse": "1.7.0", - "debug": "2.6.8", - "glob": "7.0.6", - "mkdirp": "0.5.1", - "sax": "0.5.8", - "source-map": "0.1.43" - }, - "dependencies": { - "glob": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", - "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "sax": { - "version": "0.5.8", - "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", - "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE=" - }, - "source-map": { - "version": "0.1.43", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", - "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=", - "requires": { - "amdefine": "1.0.1" - } - } - } - }, - "stylus-loader": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/stylus-loader/-/stylus-loader-3.0.1.tgz", - "integrity": "sha1-d/SzT9Aw0lsmF7z1UT21sHMMQIk=", - "requires": { - "loader-utils": "1.1.0", - "lodash.clonedeep": "4.5.0", - "when": "3.6.4" - } - }, - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=", - "requires": { - "has-flag": "1.0.0" - } - }, - "svgo": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz", - "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=", - "requires": { - "coa": "1.0.4", - "colors": "1.1.2", - "csso": "2.3.2", - "js-yaml": "3.7.0", - "mkdirp": "0.5.1", - "sax": "1.2.4", - "whet.extend": "0.9.9" - } - }, - "symbol-observable": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.4.tgz", - "integrity": "sha1-Kb9hXUqnEhvdiYsi1LP5vE4qoD0=" - }, - "sync-exec": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/sync-exec/-/sync-exec-0.6.2.tgz", - "integrity": "sha1-cX0izFPwzh3vVZQ2LzqJouu5EQU=", - "dev": true - }, - "table": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz", - "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=", - "dev": true, - "requires": { - "ajv": "4.11.8", - "ajv-keywords": "1.5.1", - "chalk": "1.1.3", - "lodash": "4.17.4", - "slice-ansi": "0.0.4", - "string-width": "2.1.1" - }, - "dependencies": { - "ajv": { - "version": "4.11.8", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", - "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", - "dev": true, - "requires": { - "co": "4.6.0", - "json-stable-stringify": "1.0.1" - } - }, - "ajv-keywords": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz", - "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=", - "dev": true - }, - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "dev": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "3.0.0" - } - } - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, - "tapable": { - "version": "0.2.8", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.8.tgz", - "integrity": "sha1-mTcqXJmb8t8WCvwNdL7U9HlIzSI=" - }, - "tar": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-3.2.1.tgz", - "integrity": "sha512-ZSzds1E0IqutvMU8HxjMaU8eB7urw2fGwTq88ukDOVuUIh0656l7/P7LiVPxhO5kS4flcRJQk8USG+cghQbTUQ==", - "dev": true, - "requires": { - "chownr": "1.0.1", - "minipass": "2.2.1", - "minizlib": "1.0.3", - "mkdirp": "0.5.1", - "yallist": "3.0.2" - }, - "dependencies": { - "yallist": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz", - "integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=", - "dev": true - } - } - }, - "temp": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", - "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", - "dev": true, - "requires": { - "os-tmpdir": "1.0.2", - "rimraf": "2.2.8" - }, - "dependencies": { - "rimraf": { - "version": "2.2.8", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", - "dev": true - } - } - }, - "text-extensions": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-1.6.0.tgz", - "integrity": "sha512-U2M04F2rbuYYCNioiTD14cImLTae4ys1rC57tllzKg3dt5DPR2JXs5yFdC017yOBrW6wM6s5gtAlFJ7yye04rA==", - "dev": true - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz", - "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=", - "requires": { - "readable-stream": "2.3.3", - "xtend": "4.0.1" - } - }, - "thunky": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", - "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=" - }, - "time-stamp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.0.0.tgz", - "integrity": "sha1-lcakRTDhW6jW9KPsuMOj+sRto1c=" - }, - "timers-browserify": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.2.tgz", - "integrity": "sha1-q0iDz1l9zVCvIRNJoA+8pWrIa4Y=", - "requires": { - "setimmediate": "1.0.5" - } - }, - "to-arraybuffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", - "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=" - }, - "to-fast-properties": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz", - "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=" - }, - "toposort": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.3.tgz", - "integrity": "sha1-8CzYp0vYvi/A6YYRw7rLlaFxhpw=" - }, - "tough-cookie": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz", - "integrity": "sha1-8IH3bkyFcg5sN6X6ztc3FQ2EByo=", - "requires": { - "punycode": "1.4.1" - } - }, - "tree-kill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.0.tgz", - "integrity": "sha512-DlX6dR0lOIRDFxI0mjL9IYg6OTncLm/Zt+JiBhE5OlFcAR8yc9S7FFXU9so0oda47frdM/JFsk7UjNt9vscKcg==" - }, - "treeify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/treeify/-/treeify-1.0.1.tgz", - "integrity": "sha1-abPNAiAioWhCTnz6HO1EyTnT6y8=", - "dev": true - }, - "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=" - }, - "trim-off-newlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-off-newlines/-/trim-off-newlines-1.0.1.tgz", - "integrity": "sha1-n5up2e+odkw4dpi8v+sshI8RrbM=", - "dev": true - }, - "trim-right": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", - "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=" - }, - "tryit": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", - "integrity": "sha1-OTvnMKlEb9Hq1tpZoBQwjzbCics=", - "dev": true - }, - "ts-node": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", - "integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=", - "dev": true, - "requires": { - "arrify": "1.0.1", - "chalk": "2.2.0", - "diff": "3.3.1", - "make-error": "1.3.0", - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map-support": "0.4.18", - "tsconfig": "6.0.0", - "v8flags": "3.0.0", - "yn": "2.0.0" - } - }, - "tsconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", - "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", - "dev": true, - "requires": { - "strip-bom": "3.0.0", - "strip-json-comments": "2.0.1" - }, - "dependencies": { - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "tsickle": { - "version": "0.24.1", - "resolved": "https://registry.npmjs.org/tsickle/-/tsickle-0.24.1.tgz", - "integrity": "sha512-XloFQZhVhgjpQsi3u2ORNRJvuID5sflOg6HfP093IqAbhE1+fIUXznULpdDwHgG4p+v8w78KdHruQtkWUKx5AQ==", - "dev": true, - "requires": { - "minimist": "1.2.0", - "mkdirp": "0.5.1", - "source-map": "0.5.7", - "source-map-support": "0.4.18" - } - }, - "tslib": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.7.1.tgz", - "integrity": "sha1-vIAEFkaRkjp5/oN4u+s9ogF1OOw=", - "dev": true - }, - "tslint": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.7.0.tgz", - "integrity": "sha1-wl4NDJL6EgHCvDDoROCOaCtPNVI=", - "dev": true, - "requires": { - "babel-code-frame": "6.26.0", - "colors": "1.1.2", - "commander": "2.11.0", - "diff": "3.3.1", - "glob": "7.1.2", - "minimatch": "3.0.4", - "resolve": "1.4.0", - "semver": "5.4.1", - "tslib": "1.7.1", - "tsutils": "2.8.2" - } - }, - "tsutils": { - "version": "2.8.2", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.8.2.tgz", - "integrity": "sha1-LBSGukMSYIRbCsb5Aq/Z1wio6mo=", - "dev": true, - "requires": { - "tslib": "1.7.1" - } - }, - "tty-browserify": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", - "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "requires": { - "safe-buffer": "5.1.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "optional": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "type-is": { - "version": "1.6.15", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", - "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", - "requires": { - "media-typer": "0.3.0", - "mime-types": "2.1.17" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "typescript": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-2.4.2.tgz", - "integrity": "sha1-+DlfhdRZJ2BnyYiqQYN6j4KHCEQ=" - }, - "uglify-js": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.1.1.tgz", - "integrity": "sha512-f7DpmEgt/RYAKzQzcfahn3JYZHobDwTZCa8oixC7pweVGEIizTX2kTYdNWcdk00xsMJqUhI8RDAa9HXHXGhNxA==", - "requires": { - "commander": "2.11.0", - "source-map": "0.5.7" - } - }, - "uglify-to-browserify": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", - "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", - "optional": true - }, - "uglifyjs-webpack-plugin": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-1.0.0.tgz", - "integrity": "sha512-23qmtiLm1X7O0XVSZ54W7XGHykPss+2lo3RYC9zSzK3DDT5W27woZpDFDKguDCnG1RIX8cDnmy5j+dtXxJCA/Q==", - "requires": { - "cacache": "10.0.0", - "find-cache-dir": "1.0.0", - "schema-utils": "0.3.0", - "source-map": "0.5.7", - "uglify-es": "3.1.5", - "webpack-sources": "1.0.1", - "worker-farm": "1.4.1" - }, - "dependencies": { - "uglify-es": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/uglify-es/-/uglify-es-3.1.5.tgz", - "integrity": "sha512-l2PqhvUNmD5pOKiHMuE8TmlvvsghxvLcg+ffcg/obRn/qm0fXf+1Mi8N7tZZIi6zxQS+PbIvq39VCYxmK0QMYA==", - "requires": { - "commander": "2.11.0", - "source-map": "0.6.1" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" - } - } - } - } - }, - "uniq": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz", - "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=" - }, - "uniqid": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/uniqid/-/uniqid-4.1.1.tgz", - "integrity": "sha1-iSIN32t1GuUrX3JISGNShZa7hME=", - "requires": { - "macaddress": "0.2.8" - } - }, - "uniqs": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz", - "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=" - }, - "unique-filename": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.0.tgz", - "integrity": "sha1-0F8v5AMlYIcfMOk8vnNe6iAVFPM=", - "requires": { - "unique-slug": "2.0.0" - } - }, - "unique-slug": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.0.tgz", - "integrity": "sha1-22Z258fMBimHj/GWCXx4hVrp9Ks=", - "requires": { - "imurmurhash": "0.1.4" - } - }, - "universalify": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", - "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "upper-case": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", - "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" - }, - "url": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", - "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - }, - "dependencies": { - "punycode": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" - } - } - }, - "url-loader": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-0.6.2.tgz", - "integrity": "sha512-h3qf9TNn53BpuXTTcpC+UehiRrl0Cv45Yr/xWayApjw6G8Bg2dGke7rIwDQ39piciWCWrC+WiqLjOh3SUp9n0Q==", - "requires": { - "loader-utils": "1.1.0", - "mime": "1.4.1", - "schema-utils": "0.3.0" - }, - "dependencies": { - "mime": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", - "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" - } - } - }, - "url-parse": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.1.9.tgz", - "integrity": "sha1-xn8dd11R8KGJEd17P/rSe7nlvRk=", - "requires": { - "querystringify": "1.0.0", - "requires-port": "1.0.0" - }, - "dependencies": { - "querystringify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-1.0.0.tgz", - "integrity": "sha1-YoYkIRLFtxL6ZU5SZlK/ahP/Bcs=" - } - } - }, - "user-home": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz", - "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=", - "dev": true, - "requires": { - "os-homedir": "1.0.2" - } - }, - "util": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", - "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", - "requires": { - "inherits": "2.0.1" - }, - "dependencies": { - "inherits": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", - "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" - } - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "util-extend": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/util-extend/-/util-extend-1.0.3.tgz", - "integrity": "sha1-p8IW0mdUUWljeztu3GypEZ4v+T8=", - "dev": true - }, - "utila": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz", - "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=" - }, - "utils-merge": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", - "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=" - }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" - }, - "v8flags": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.0.tgz", - "integrity": "sha512-AGl+C+4qpeSu2g3JxCD/mGFFOs/vVZ3XREkD3ibQXEqr4Y4zgIrPWW124/IKJFHOIVFIoH8miWrLf0o84HYjwA==", - "dev": true, - "requires": { - "user-home": "1.1.1" - }, - "dependencies": { - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - } - } - }, - "validate-npm-package-license": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", - "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.4" - } - }, - "vary": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz", - "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc=" - }, - "vendors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.1.tgz", - "integrity": "sha1-N61zyO5Bf7PVgOeFMSMH0nSEfyI=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "requires": { - "assert-plus": "1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "1.3.0" - } - }, - "vlq": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/vlq/-/vlq-0.2.2.tgz", - "integrity": "sha1-4xbVJXtAuGu0PLjV/qXX9U1rDKE=" - }, - "vm-browserify": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz", - "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=", - "requires": { - "indexof": "0.0.1" - } - }, - "walk-sync": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/walk-sync/-/walk-sync-0.3.2.tgz", - "integrity": "sha512-FMB5VqpLqOCcqrzA9okZFc0wq0Qbmdm396qJxvQZhDpyu0W95G9JCmp74tx7iyYnyOcBtUuKJsgIKAqjozvmmQ==", - "dev": true, - "requires": { - "ensure-posix-path": "1.0.2", - "matcher-collection": "1.0.5" - } - }, - "watchpack": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.4.0.tgz", - "integrity": "sha1-ShRyvLuVK9Cpu0A2gB+VTfs5+qw=", - "requires": { - "async": "2.5.0", - "chokidar": "1.7.0", - "graceful-fs": "4.1.11" - } - }, - "wbuf": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.2.tgz", - "integrity": "sha1-1pe5nx9ZUS3ydRvkJ2nBWAtYAf4=", - "requires": { - "minimalistic-assert": "1.0.0" - } - }, - "webpack": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.8.1.tgz", - "integrity": "sha512-5ZXLWWsMqHKFr5y0N3Eo5IIisxeEeRAajNq4mELb/WELOR7srdbQk2N5XiyNy2A/AgvlR3AmeBCZJW8lHrolbw==", - "requires": { - "acorn": "5.1.2", - "acorn-dynamic-import": "2.0.2", - "ajv": "5.2.2", - "ajv-keywords": "2.1.0", - "async": "2.5.0", - "enhanced-resolve": "3.4.1", - "escope": "3.6.0", - "interpret": "1.0.4", - "json-loader": "0.5.7", - "json5": "0.5.1", - "loader-runner": "2.3.0", - "loader-utils": "1.1.0", - "memory-fs": "0.4.1", - "mkdirp": "0.5.1", - "node-libs-browser": "2.0.0", - "source-map": "0.5.7", - "supports-color": "4.4.0", - "tapable": "0.2.8", - "uglifyjs-webpack-plugin": "0.4.6", - "watchpack": "1.4.0", - "webpack-sources": "1.0.1", - "yargs": "8.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - }, - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", - "wordwrap": "0.0.2" - } - }, - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "2.0.0" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "os-locale": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", - "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", - "requires": { - "execa": "0.7.0", - "lcid": "1.0.0", - "mem": "1.1.0" - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "requires": { - "pify": "2.3.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "3.0.0" - } - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" - }, - "dependencies": { - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" - } - } - } - }, - "uglifyjs-webpack-plugin": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz", - "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=", - "requires": { - "source-map": "0.5.7", - "uglify-js": "2.8.29", - "webpack-sources": "1.0.1" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" - }, - "yargs": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", - "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", - "requires": { - "camelcase": "4.1.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "2.1.0", - "read-pkg-up": "2.0.0", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "2.1.1", - "which-module": "2.0.0", - "y18n": "3.2.1", - "yargs-parser": "7.0.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1", - "wrap-ansi": "2.1.0" - }, - "dependencies": { - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "requires": { - "code-point-at": "1.1.0", - "is-fullwidth-code-point": "1.0.0", - "strip-ansi": "3.0.1" - } - } - } - } - } - }, - "yargs-parser": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", - "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", - "requires": { - "camelcase": "4.1.0" - }, - "dependencies": { - "camelcase": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", - "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" - } - } - } - } - }, - "webpack-concat-plugin": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/webpack-concat-plugin/-/webpack-concat-plugin-1.4.0.tgz", - "integrity": "sha512-Ym9Qm5Sw9oXJYChNJk09I/yaXDaV3UDxsa07wcCvILzIeSJTnSUZjhS4y2YkULzgE8VHOv9X04KtlJPZGwXqMg==", - "requires": { - "md5": "2.2.1", - "uglify-js": "2.8.29" - }, - "dependencies": { - "camelcase": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", - "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=" - }, - "cliui": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", - "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", - "requires": { - "center-align": "0.1.3", - "right-align": "0.1.3", - "wordwrap": "0.0.2" - } - }, - "uglify-js": { - "version": "2.8.29", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", - "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", - "requires": { - "source-map": "0.5.7", - "uglify-to-browserify": "1.0.2", - "yargs": "3.10.0" - } - }, - "wordwrap": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", - "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=" - }, - "yargs": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", - "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", - "requires": { - "camelcase": "1.2.1", - "cliui": "2.1.0", - "decamelize": "1.2.0", - "window-size": "0.1.0" - } - } - } - }, - "webpack-core": { - "version": "0.6.9", - "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz", - "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=", - "requires": { - "source-list-map": "0.1.8", - "source-map": "0.4.4" - }, - "dependencies": { - "source-list-map": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz", - "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=" - }, - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "requires": { - "amdefine": "1.0.1" - } - } - } - }, - "webpack-dev-middleware": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.0.tgz", - "integrity": "sha1-007++y7dp+HTtdvgcolRMhllFwk=", - "requires": { - "memory-fs": "0.4.1", - "mime": "1.4.0", - "path-is-absolute": "1.0.1", - "range-parser": "1.2.0", - "time-stamp": "2.0.0" - } - }, - "webpack-dev-server": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-2.9.3.tgz", - "integrity": "sha512-bwq7sj452FRH+oVfgOA8xXKkLYPTNsYB4dQ0Jhz3ydjNJ9MvhpGJtehFW8Z0cEcwNkRRiF4aYbReiSGQ4pbS1w==", - "requires": { - "ansi-html": "0.0.7", - "array-includes": "3.0.3", - "bonjour": "3.5.0", - "chokidar": "1.7.0", - "compression": "1.7.0", - "connect-history-api-fallback": "1.3.0", - "debug": "3.1.0", - "del": "3.0.0", - "express": "4.15.4", - "html-entities": "1.2.1", - "http-proxy-middleware": "0.17.4", - "import-local": "0.1.1", - "internal-ip": "1.2.0", - "ip": "1.1.5", - "loglevel": "1.4.1", - "opn": "5.1.0", - "portfinder": "1.0.13", - "selfsigned": "1.9.1", - "serve-index": "1.9.0", - "sockjs": "0.3.18", - "sockjs-client": "1.1.4", - "spdy": "3.4.7", - "strip-ansi": "3.0.1", - "supports-color": "4.4.0", - "webpack-dev-middleware": "1.12.0", - "yargs": "6.6.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=" - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "has-flag": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", - "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=" - }, - "supports-color": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz", - "integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==", - "requires": { - "has-flag": "2.0.0" - } - }, - "yargs": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz", - "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=", - "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "4.2.1" - } - }, - "yargs-parser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", - "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", - "requires": { - "camelcase": "3.0.0" - } - } - } - }, - "webpack-merge": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-4.1.0.tgz", - "integrity": "sha1-atciI7PguDflMeRZfBmfkJNhUR4=", - "requires": { - "lodash": "4.17.4" - } - }, - "webpack-sources": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.1.tgz", - "integrity": "sha512-05tMxipUCwHqYaVS8xc7sYPTly8PzXayRCB4dTxLhWTqlKUiwH6ezmEe0OSreL1c30LAuA3Zqmc+uEBUGFJDjw==", - "requires": { - "source-list-map": "2.0.0", - "source-map": "0.5.7" - } - }, - "webpack-subresource-integrity": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-1.0.1.tgz", - "integrity": "sha1-H8CdRkl9pm5GdDoqUdLMOFucsO0=", - "requires": { - "webpack-core": "0.6.9" - } - }, - "websocket-driver": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.6.5.tgz", - "integrity": "sha1-XLJVbOuF9Dc8bYI4qmkchFThOjY=", - "requires": { - "websocket-extensions": "0.1.1" - } - }, - "websocket-extensions": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.1.tgz", - "integrity": "sha1-domUmcGEtu91Q3fC27DNbLVdKec=" - }, - "when": { - "version": "3.6.4", - "resolved": "https://registry.npmjs.org/when/-/when-3.6.4.tgz", - "integrity": "sha1-RztRfsFZ4rhQBUl6E5g/CVQS404=" - }, - "whet.extend": { - "version": "0.9.9", - "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz", - "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=" - }, - "which": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", - "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", - "requires": { - "isexe": "2.0.0" - } - }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=" - }, - "wide-align": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.2.tgz", - "integrity": "sha512-ijDLlyQ7s6x1JgCLur53osjm/UXUYD9+0PbYKrBsYisYXzCxN+HC3mYDNy/dWdmf3AwqwU3CXwDCvsNgGK1S0w==", - "requires": { - "string-width": "1.0.2" - } - }, - "window-size": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", - "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=" - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "worker-farm": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.4.1.tgz", - "integrity": "sha512-tgFAtgOYLPutkAyzgpS6VJFL5HY+0ui1Tvua+fITgz8ByaJTMFGtazR6xxQfwfiAcbwE+2fLG/K49wc2TfwCNw==", - "requires": { - "errno": "0.1.4", - "xtend": "4.0.1" - } - }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "requires": { - "string-width": "1.0.2", - "strip-ansi": "3.0.1" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "dev": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "xml-char-classes": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz", - "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" - }, - "xxhashjs": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/xxhashjs/-/xxhashjs-0.2.1.tgz", - "integrity": "sha1-m76b6JYUKXbfo0wGGy0GjEPTDeA=", - "requires": { - "cuint": "0.2.2" - } - }, - "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", - "optional": true, - "requires": { - "camelcase": "3.0.0", - "cliui": "3.2.0", - "decamelize": "1.2.0", - "get-caller-file": "1.0.2", - "os-locale": "1.4.0", - "read-pkg-up": "1.0.1", - "require-directory": "2.1.1", - "require-main-filename": "1.0.1", - "set-blocking": "2.0.0", - "string-width": "1.0.2", - "which-module": "1.0.0", - "y18n": "3.2.1", - "yargs-parser": "5.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "optional": true - } - } - }, - "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "optional": true, - "requires": { - "camelcase": "3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "optional": true - } - } - }, - "yn": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", - "integrity": "sha1-5a2ryKz0CPY4X8dklWhMiOavaJo=", - "dev": true - }, - "zone.js": { - "version": "0.8.17", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.8.17.tgz", - "integrity": "sha1-TF5RhahX2o2nk9rzkZNxxaNrKgs=" - } - } -} diff --git a/package.json b/package.json index adab4c28470f..06ff5def71b7 100644 --- a/package.json +++ b/package.json @@ -1,38 +1,50 @@ { - "name": "@angular/cli", - "version": "1.6.0-beta.2", - "description": "CLI tool for Angular", - "main": "packages/@angular/cli/lib/cli/index.js", - "trackingCode": "UA-8594346-19", + "name": "@angular/devkit-repo", + "version": "0.0.0", + "private": true, + "description": "Software Development Kit for Angular", "bin": { - "ng": "./bin/ng" + "architect": "./bin/architect", + "benchmark": "./bin/benchmark", + "build-optimizer": "./bin/build-optimizer", + "devkit-admin": "./bin/devkit-admin", + "ng": "./bin/ng", + "schematics": "./bin/schematics" }, - "keywords": [], + "keywords": [ + "angular", + "Angular CLI", + "devkit", + "sdk", + "Angular DevKit" + ], "scripts": { - "crazy2e": "echo This is crazy! Youre INSANE; npm run test:e2e -- --noproject ''; npm run test:e2e -- --nb-shards=4 --shard=0 --nobuild --nolink & npm run test:e2e -- --nb-shards=4 --shard=1 --nobuild --nolink & npm run test:e2e -- --nb-shards=4 --shard=2 --nobuild --nolink & npm run test:e2e -- --nb-shards=4 --shard=3 --nobuild --nolink & wait", - "build": "node scripts/run-tool.js publish build", - "test": "npm-run-all -c test:packages test:cli test:deps test:licenses test:messages", - "e2e": "npm run test:e2e", - "e2e:nightly": "node tests/run_e2e.js --nightly", - "test:e2e": "node tests/run_e2e.js", - "test:cli": "node tests/runner", - "test:deps": "node scripts/publish/validate_dependencies.js", - "test:inspect": "node --inspect --debug-brk tests/runner", - "test:licenses": "node scripts/test-licenses.js", - "test:messages": "node scripts/test-commit-messages.js", - "test:packages": "node scripts/run-packages-spec.js", - "eslint": "eslint .", - "tslint": "tslint \"**/*.ts\" -c tslint.json -e \"**/config/schema.d.ts\" -e \"**/tests/**\" -e \"node_modules/**\" -e \"tmp/**\" -e \"dist/**\"", - "lint": "npm-run-all -c eslint tslint", - "tool": "node scripts/run-tool.js" + "admin": "node ./bin/devkit-admin", + "build": "npm run admin -- build", + "build-tsc": "tsc -p tsconfig.json", + "fix": "npm run admin -- lint --fix", + "lint": "npm run admin -- lint", + "prebuildifier": "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", + "templates": "node ./bin/devkit-admin templates", + "test": "node ./bin/devkit-admin test", + "test-large": "node ./bin/devkit-admin test --large --spec-reporter", + "test-cli-e2e": "node ./tests/legacy-cli/run_e2e", + "test:watch": "nodemon --watch packages -e ts ./bin/devkit-admin test", + "validate": "node ./bin/devkit-admin validate", + "validate-commits": "./bin/devkit-admin validate-commits", + "prepush": "node ./bin/devkit-admin hooks/pre-push", + "preinstall": "node ./tools/yarn/check-yarn.js", + "webdriver-update-appveyor": "webdriver-manager update --standalone false --gecko false --versions.chrome 2.37", + "webdriver-update-circleci": "webdriver-manager update --standalone false --gecko false --versions.chrome $CHROMEDRIVER_VERSION_ARG " }, "repository": { "type": "git", "url": "https://github.com/angular/angular-cli.git" }, "engines": { - "node": ">= 6.9.0", - "npm": ">= 3.0.0" + "node": ">=10.9.0 <11.0.0", + "yarn": ">=1.9.0 <2.0.0" }, "author": "Angular Authors", "license": "MIT", @@ -40,112 +52,66 @@ "url": "https://github.com/angular/angular-cli/issues" }, "homepage": "https://github.com/angular/angular-cli", + "workspaces": { + "packages": [ + "packages/angular/*", + "packages/angular_devkit/*", + "packages/ngtools/*", + "packages/schematics/*" + ], + "nohoist": [ + "@angular/compiler-cli" + ] + }, "dependencies": { - "@angular-devkit/build-optimizer": "~0.0.28", - "@angular-devkit/schematics": "~0.0.35", - "@schematics/angular": "~0.1.0", - "autoprefixer": "^6.5.3", - "chalk": "~2.2.0", - "circular-dependency-plugin": "^3.0.0", - "common-tags": "^1.3.1", - "copy-webpack-plugin": "^4.1.1", - "core-object": "^3.1.0", - "css-loader": "^0.28.1", - "cssnano": "^3.10.0", - "denodeify": "^1.2.1", - "ember-cli-string-utils": "^1.0.0", - "enhanced-resolve": "^3.4.1", - "exports-loader": "^0.6.3", - "extract-text-webpack-plugin": "3.0.0", - "file-loader": "^1.1.5", - "fs-extra": "^4.0.0", "glob": "^7.0.3", - "html-webpack-plugin": "^2.29.0", - "istanbul-instrumenter-loader": "^2.0.0", - "karma-source-map-support": "^1.2.0", - "less": "^2.7.2", - "less-loader": "^4.0.5", - "license-webpack-plugin": "^1.0.0", - "loader-utils": "^1.0.2", - "lodash": "^4.11.1", - "magic-string": "^0.22.3", - "memory-fs": "^0.4.1", - "minimatch": "^3.0.4", - "node-modules-path": "^1.0.0", - "nopt": "^4.0.1", - "opn": "~5.1.0", - "portfinder": "~1.0.12", - "postcss-custom-properties": "^6.1.0", - "postcss-loader": "^2.0.8", - "postcss-url": "^7.1.2", - "raw-loader": "^0.5.1", - "resolve": "^1.1.7", - "rxjs": "^5.5.2", - "sass-loader": "^6.0.3", - "semver": "^5.3.0", - "silent-error": "^1.0.0", - "source-map": "^0.5.6", - "source-map-loader": "^0.2.0", - "source-map-support": "^0.4.1", - "style-loader": "^0.13.1", - "stylus": "^0.54.5", - "stylus-loader": "^3.0.1", - "tree-kill": "^1.0.0", - "typescript": "~2.4.2", - "uglifyjs-webpack-plugin": "1.0.0", - "url-loader": "^0.6.2", - "webpack": "~3.8.1", - "webpack-concat-plugin": "1.4.0", - "webpack-dev-middleware": "~1.12.0", - "webpack-dev-server": "~2.9.3", - "webpack-merge": "^4.1.0", - "webpack-sources": "^1.0.0", - "webpack-subresource-integrity": "^1.0.1", - "zone.js": "^0.8.14" + "node-fetch": "^2.2.0", + "quicktype-core": "^5.0.41", + "temp": "^0.8.3", + "tslint": "^5.11.0", + "typescript": "~3.1.1" }, "devDependencies": { - "@angular/compiler": "^5.0.0", - "@angular/compiler-cli": "^5.0.0", - "@angular/core": "^5.0.0", - "@angular/service-worker": "^5.0.0", - "@types/common-tags": "^1.2.4", - "@types/copy-webpack-plugin": "^4.0.0", - "@types/denodeify": "^1.2.30", - "@types/express": "^4.0.32", - "@types/fs-extra": "^4.0.0", - "@types/glob": "^5.0.29", - "@types/jasmine": "2.5.45", - "@types/lodash": "~4.14.50", + "@angular/compiler": "^7.0.0-rc.0", + "@angular/compiler-cli": "^7.0.0-rc.0", + "@bazel/typescript": "0.16.1", + "@ngtools/json-schema": "^1.1.0", + "@types/copy-webpack-plugin": "^4.4.1", + "@types/express": "^4.16.0", + "@types/glob": "^5.0.35", + "@types/inquirer": "^0.0.42", + "@types/istanbul": "^0.4.30", + "@types/jasmine": "^2.8.8", + "@types/loader-utils": "^1.1.3", "@types/minimist": "^1.2.0", - "@types/mock-fs": "^3.6.30", - "@types/node": "^6.0.84", - "@types/request": "~2.0.0", - "@types/semver": "^5.3.30", - "@types/source-map": "^0.5.0", - "@types/webpack": "^3.0.5", - "conventional-changelog": "1.1.0", - "dtsgenerator": "^0.9.1", - "eslint": "^3.11.0", - "express": "^4.14.0", + "@types/node": "8.10.10", + "@types/request": "^2.47.1", + "@types/semver": "^5.5.0", + "@types/source-map": "0.5.2", + "@types/webpack": "^4.4.11", + "@types/webpack-dev-server": "^3.1.0", + "@types/webpack-sources": "^0.1.5", + "common-tags": "^1.8.0", + "conventional-changelog": "^1.1.0", + "conventional-commits-parser": "^3.0.0", + "gh-got": "^7.0.0", + "git-raw-commits": "^2.0.0", + "husky": "^0.14.3", + "istanbul": "^0.4.5", "jasmine": "^2.6.0", - "jasmine-spec-reporter": "^4.1.0", - "license-checker": "^14.0.0", + "jasmine-spec-reporter": "^3.2.0", + "license-checker": "^20.1.0", + "minimatch": "^3.0.4", "minimist": "^1.2.0", - "mock-fs": "^4.0.0", - "npm-run": "^4.1.0", - "npm-run-all": "^4.0.0", - "request": "^2.74.0", - "resolve-bin": "^0.4.0", - "rewire": "^2.5.1", - "spdx-satisfies": "^0.1.3", - "tar": "^3.1.5", - "temp": "0.8.3", - "through": "^2.3.6", - "ts-node": "^3.2.0", - "tslint": "^5.1.0", - "walk-sync": "^0.3.1" - }, - "optionalDependencies": { - "node-sass": "^4.3.0" + "rxjs": "~6.3.0", + "semver": "^5.3.0", + "source-map": "^0.5.6", + "source-map-support": "^0.5.0", + "spdx-satisfies": "^4.0.0", + "tar": "^4.4.4", + "through2": "^2.0.3", + "ts-node": "^5.0.0", + "tslint-no-circular-imports": "^0.5.0", + "tslint-sonarts": "^1.7.0" } } diff --git a/packages/@angular/cli/bin/ng b/packages/@angular/cli/bin/ng deleted file mode 100755 index 2c265c957d4d..000000000000 --- a/packages/@angular/cli/bin/ng +++ /dev/null @@ -1,201 +0,0 @@ -#!/usr/bin/env node -'use strict'; - -// Provide a title to the process in `ps`. -// Due to an obscure Mac bug, do not start this title with any symbol. -process.title = 'ng'; - -const CliConfig = require('../models/config').CliConfig; -const Version = require('../upgrade/version').Version; - -const fs = require('fs'); -const findUp = require('../utilities/find-up').findUp; -const packageJson = require('../package.json'); -const path = require('path'); -const resolve = require('resolve'); -const stripIndents = require('common-tags').stripIndents; -const yellow = require('chalk').yellow; -const SemVer = require('semver').SemVer; -const events = require('events'); - - -function _fromPackageJson(cwd) { - cwd = cwd || process.cwd(); - - do { - const packageJsonPath = path.join(cwd, 'node_modules/@angular/cli/package.json'); - if (fs.existsSync(packageJsonPath)) { - const content = fs.readFileSync(packageJsonPath, 'utf-8'); - if (content) { - const json = JSON.parse(content); - if (json['version']) { - return new SemVer(json['version']); - } - } - } - - // Check the parent. - cwd = path.dirname(cwd); - } while (cwd != path.dirname(cwd)); - - return null; -} - - -// Check if we need to profile this CLI run. -let profiler = null; -if (process.env['NG_CLI_PROFILING']) { - profiler = require('v8-profiler'); - profiler.startProfiling(); - function exitHandler(options, err) { - if (options.cleanup) { - const cpuProfile = profiler.stopProfiling(); - fs.writeFileSync(path.resolve(process.cwd(), process.env.NG_CLI_PROFILING) + '.cpuprofile', - JSON.stringify(cpuProfile)); - } - - if (options.exit) { - process.exit(); - } - } - - process.on('exit', exitHandler.bind(null, { cleanup: true })); - process.on('SIGINT', exitHandler.bind(null, { exit: true })); - process.on('uncaughtException', exitHandler.bind(null, { exit: true })); -} - - -// Show the warnings due to package and version deprecation. -const version = new SemVer(process.version); -if (version.compare(new SemVer('6.9.0')) < 0 - && CliConfig.fromGlobal().get('warnings.nodeDeprecation')) { - process.stderr.write(yellow(stripIndents` - You are running version ${version.version} of Node, which will not be supported in future - versions of the CLI. The official Node version that will be supported is 6.9 and greater. - - To disable this warning use "ng set --global warnings.nodeDeprecation=false". - `)); -} - - -if (require('../package.json')['name'] == 'angular-cli' - && CliConfig.fromGlobal().get('warnings.packageDeprecation')) { - process.stderr.write(yellow(stripIndents` - As a forewarning, we are moving the CLI npm package to "@angular/cli" with the next release, - which will only support Node 6.9 and greater. This package will be officially deprecated - shortly after. - - To disable this warning use "ng set --global warnings.packageDeprecation=false". - `)); -} - -const packageJsonProjectPath = findUp('package.json', process.cwd(), true); -if (packageJsonProjectPath && fs.existsSync(packageJsonProjectPath)) { - const packageJsonProject = require(packageJsonProjectPath); - const deps = packageJsonProject['dependencies'] || {}; - const devDeps = packageJsonProject['devDependencies'] || {}; - const hasOldDep = !!deps['angular-cli']; - const hasDep = !!deps['@angular/cli']; - const hasOldDevDep = !!devDeps['angular-cli']; - const hasDevDep = !!devDeps['@angular/cli']; - - if (hasOldDep || hasOldDevDep || !(hasDevDep || hasDep)) { - const warnings = [ - 'Unable to find "@angular/cli" in devDependencies.', - '' - ]; - - if (hasOldDep || hasOldDevDep) { - warnings.push( - 'The package "angular-cli" has been deprecated and renamed to "@angular/cli".', - ''); - } - - warnings.push('Please take the following steps to avoid issues:'); - - if (hasOldDep) { - warnings.push('"npm uninstall --save angular-cli"'); - } - if (hasOldDevDep) { - warnings.push('"npm uninstall --save-dev angular-cli"'); - } - if (hasDep) { - warnings.push('"npm uninstall --save @angular/cli"') - } - if (!hasDevDep) { - warnings.push('"npm install --save-dev @angular/cli@latest"'); - } - process.stderr.write(yellow(warnings.join('\n'), '\n\n')); - } -} - -resolve('@angular/cli', { basedir: process.cwd() }, - function (error, projectLocalCli) { - var cli; - if (error) { - // If there is an error, resolve could not find the ng-cli - // library from a package.json. Instead, include it from a relative - // path to this script file (which is likely a globally installed - // npm package). Most common cause for hitting this is `ng new` - cli = require('../lib/cli'); - } else { - // Verify that package's version. - Version.assertPostWebpackVersion(); - - // This was run from a global, check local version. - const globalVersion = new SemVer(packageJson['version']); - let localVersion; - let shouldWarn = false; - - try { - localVersion = _fromPackageJson(); - shouldWarn = localVersion && globalVersion.compare(localVersion) > 0; - } catch (e) { - console.error(e); - shouldWarn = true; - } - - if (shouldWarn && CliConfig.fromGlobal().get('warnings.versionMismatch')) { - let warning = yellow(stripIndents` - Your global Angular CLI version (${globalVersion}) is greater than your local - version (${localVersion}). The local Angular CLI version is used. - - To disable this warning use "ng set --global warnings.versionMismatch=false". - `); - // Don't show warning colorised on `ng completion` - if (process.argv[2] !== 'completion') { - // eslint-disable no-console - console.log(warning); - } else { - // eslint-disable no-console - console.error(warning); - process.exit(1); - } - } - - // No error implies a projectLocalCli, which will load whatever - // version of ng-cli you have installed in a local package.json - cli = require(projectLocalCli); - } - - if ('default' in cli) { - cli = cli['default']; - } - - let standardInput; - try { - standardInput = process.stdin; - } catch (e) { - delete process.stdin; - process.stdin = new events.EventEmitter(); - standardInput = process.stdin; - } - - cli({ - cliArgs: process.argv.slice(2), - inputStream: standardInput, - outputStream: process.stdout - }).then(function (result) { - process.exit(typeof result === 'object' ? result.exitCode : result); - }); - }); diff --git a/packages/@angular/cli/commands/build.ts b/packages/@angular/cli/commands/build.ts deleted file mode 100644 index 09180561f791..000000000000 --- a/packages/@angular/cli/commands/build.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { CliConfig } from '../models/config'; -import { BuildOptions } from '../models/build-options'; -import { Version } from '../upgrade/version'; -import { oneLine } from 'common-tags'; - -const Command = require('../ember-cli/lib/models/command'); - - -const config = CliConfig.fromProject() || CliConfig.fromGlobal(); -const buildConfigDefaults = config.getPaths('defaults.build', [ - 'sourcemaps', 'baseHref', 'progress', 'poll', 'deleteOutputPath', 'preserveSymlinks', - 'showCircularDependencies', 'commonChunk', 'namedChunks' -]); - -// defaults for BuildOptions -export const baseBuildCommandOptions: any = [ - { - name: 'target', - type: String, - default: 'development', - aliases: ['t', { 'dev': 'development' }, { 'prod': 'production' }], - description: 'Defines the build target.' - }, - { - name: 'environment', - type: String, - aliases: ['e'], - description: 'Defines the build environment.' - }, - { - name: 'output-path', - type: 'Path', - aliases: ['op'], - description: 'Path where output will be placed.' - }, - { - name: 'aot', - type: Boolean, - description: 'Build using Ahead of Time compilation.' - }, - { - name: 'sourcemaps', - type: Boolean, - aliases: ['sm', 'sourcemap'], - description: 'Output sourcemaps.', - default: buildConfigDefaults['sourcemaps'] - }, - { - name: 'vendor-chunk', - type: Boolean, - aliases: ['vc'], - description: 'Use a separate bundle containing only vendor libraries.' - }, - { - name: 'common-chunk', - type: Boolean, - default: buildConfigDefaults['commonChunk'], - aliases: ['cc'], - description: 'Use a separate bundle containing code used across multiple bundles.' - }, - { - name: 'base-href', - type: String, - aliases: ['bh'], - description: 'Base url for the application being built.', - default: buildConfigDefaults['baseHref'] - }, - { - name: 'deploy-url', - type: String, - aliases: ['d'], - description: 'URL where files will be deployed.' - }, - { - name: 'verbose', - type: Boolean, - default: false, - aliases: ['v'], - description: 'Adds more details to output logging.' - }, - { - name: 'progress', - type: Boolean, - aliases: ['pr'], - description: 'Log progress to the console while building.', - default: buildConfigDefaults['progress'] - }, - { - name: 'i18n-file', - type: String, - description: 'Localization file to use for i18n.' - }, - { - name: 'i18n-format', - type: String, - description: 'Format of the localization file specified with --i18n-file.' - }, - { - name: 'locale', - type: String, - description: 'Locale to use for i18n.' - }, - { - name: 'missing-translation', - type: String, - description: 'How to handle missing translations for i18n.' - }, - { - name: 'extract-css', - type: Boolean, - aliases: ['ec'], - description: 'Extract css from global styles onto css files instead of js ones.' - }, - { - name: 'watch', - type: Boolean, - default: false, - aliases: ['w'], - description: 'Run build when files change.' - }, - { - name: 'output-hashing', - type: String, - values: ['none', 'all', 'media', 'bundles'], - description: 'Define the output filename cache-busting hashing mode.', - aliases: ['oh'] - }, - { - name: 'poll', - type: Number, - description: 'Enable and define the file watching poll time period (milliseconds).', - default: buildConfigDefaults['poll'] - }, - { - name: 'app', - type: String, - aliases: ['a'], - description: 'Specifies app name or index to use.' - }, - { - name: 'delete-output-path', - type: Boolean, - aliases: ['dop'], - description: 'Delete output path before build.', - default: buildConfigDefaults['deleteOutputPath'], - }, - { - name: 'preserve-symlinks', - type: Boolean, - description: 'Do not use the real path when resolving modules.', - default: buildConfigDefaults['preserveSymlinks'] - }, - { - name: 'extract-licenses', - type: Boolean, - default: true, - description: 'Extract all licenses in a separate file, in the case of production builds only.' - }, - { - name: 'show-circular-dependencies', - type: Boolean, - aliases: ['scd'], - description: 'Show circular dependency warnings on builds.', - default: buildConfigDefaults['showCircularDependencies'] - }, - { - name: 'build-optimizer', - type: Boolean, - description: 'Enables @angular-devkit/build-optimizer optimizations when using `--aot`.' - }, - { - name: 'named-chunks', - type: Boolean, - aliases: ['nc'], - description: 'Use file name for lazy loaded chunks.', - default: buildConfigDefaults['namedChunks'] - }, - { - name: 'subresource-integrity', - type: Boolean, - default: false, - aliases: ['sri'], - description: 'Enables the use of subresource integrity validation.' - }, - { - name: 'bundle-dependencies', - type: ['none', 'all'], - default: 'none', - description: 'Available on server platform only. Which external dependencies to bundle into ' - + 'the module. By default, all of node_modules will be kept as requires.' - }, - { - name: 'service-worker', - type: Boolean, - default: true, - aliases: ['sw'], - description: 'Generates a service worker config for production builds, if the app has ' - + 'service worker enabled.' - } -]; - -export interface BuildTaskOptions extends BuildOptions { - statsJson?: boolean; -} - -const BuildCommand = Command.extend({ - name: 'build', - description: 'Builds your app and places it into the output path (dist/ by default).', - aliases: ['b'], - - availableOptions: baseBuildCommandOptions.concat([ - { - name: 'stats-json', - type: Boolean, - default: false, - description: oneLine`Generates a \`stats.json\` file which can be analyzed using tools - such as: \`webpack-bundle-analyzer\` or https://webpack.github.io/analyse.` - } - ]), - - run: function (commandOptions: BuildTaskOptions) { - // Check Angular and TypeScript versions. - Version.assertAngularVersionIs2_3_1OrHigher(this.project.root); - Version.assertTypescriptVersion(this.project.root); - - // Force commonjs module format for TS on dev watch builds. - if (commandOptions.target === 'development' && commandOptions.watch === true) { - commandOptions.forceTsCommonjs = true; - } - - const BuildTask = require('../tasks/build').default; - - const buildTask = new BuildTask({ - project: this.project, - ui: this.ui, - }); - - return buildTask.run(commandOptions); - } -}); - - -BuildCommand.overrideCore = true; -export default BuildCommand; diff --git a/packages/@angular/cli/commands/completion.ts b/packages/@angular/cli/commands/completion.ts deleted file mode 100644 index 369128c5b7af..000000000000 --- a/packages/@angular/cli/commands/completion.ts +++ /dev/null @@ -1,212 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; - -import { stripIndent } from 'common-tags'; - -const stringUtils = require('ember-cli-string-utils'); -const Command = require('../ember-cli/lib/models/command'); -const lookupCommand = require('../ember-cli/lib/cli/lookup-command'); - -function extractOptions(opts: any): string[] { - const output: string[] = []; - - for (let index = 0; index < opts.length; index++) { - const element = opts[index]; - output.push('--' + element.name); - if (element.aliases) { - output.push('-' + element.aliases[0]); - } - } - - return output; -} - -function extractBlueprints(opts: any): string[] { - const output: string[] = []; - - for (let index = 0; index < opts.length; index++) { - const element = opts[index]; - output.push(element.name); - } - - return output; -} - -export interface CompletionCommandOptions { - all?: boolean; - bash?: boolean; - zsh?: boolean; -} - -const optsNg: string[] = []; - -const CompletionCommand = Command.extend({ - name: 'completion', - description: 'Adds autocomplete functionality to `ng` commands and subcommands.', - works: 'everywhere', - availableOptions: [ - { - name: 'all', - type: Boolean, - default: true, - aliases: ['a'], - description: 'Generate a completion script compatible with both bash and zsh.' - }, - { - name: 'bash', - type: Boolean, - default: false, - aliases: ['b'], - description: 'Generate a completion script for bash.' - }, - { - name: 'zsh', - type: Boolean, - default: false, - aliases: ['z'], - description: 'Generate a completion script for zsh.' - } - ], - - run: function (commandOptions: CompletionCommandOptions) { - commandOptions.all = !commandOptions.bash && !commandOptions.zsh; - - const commandFiles = fs.readdirSync(__dirname) - .filter(file => file.match(/\.(j|t)s$/) && !file.match(/\.d.ts$/)) - .map(file => path.parse(file).name) - .map(file => file.toLowerCase()); - - const commandMap = commandFiles.reduce((acc: any, curr: string) => { - let classifiedName = stringUtils.classify(curr); - let defaultImport = require(`./${curr}`).default; - - acc[classifiedName] = defaultImport; - - return acc; - }, {}); - - let caseBlock = ''; - - commandFiles.forEach(cmd => { - const Command = lookupCommand(commandMap, cmd); - const com: string[] = []; - - const command = new Command({ - ui: this.ui, - project: this.project, - commands: this.commands, - tasks: this.tasks - }); - - if (command.hidden || command.unknown) { - return; - } - - optsNg.push(command.name); - com.push(command.name); - - if (command.aliases) { - command.aliases.forEach((element: string) => { - optsNg.push(element); - com.push(element); - }); - } - - let opts: string[] = []; - if (command.blueprints && command.blueprints[0]) { - opts = opts.concat(extractBlueprints(command.blueprints)); - } - - if (command.availableOptions && command.availableOptions[0]) { - opts = opts.concat(extractOptions(command.availableOptions)); - const optsStr = opts.sort().join(' '); - caseBlock = `${caseBlock} - ${com.sort().join('|')}) opts="${optsStr}" ;;`; - } - }); - - caseBlock = `ng|help) opts="${optsNg.sort().join(' ')}" ;;${caseBlock} - *) opts="" ;;`; - - console.log(stripIndent` - ###-begin-ng-completion### - # - - # ng command completion script - # This command supports 3 cases. - # 1. (Default case) It prints a common completion initialisation for both Bash and Zsh. - # It is the result of either calling "ng completion" or "ng completion -a". - # 2. Produce Bash-only completion: "ng completion -b" or "ng completion --bash". - # 3. Produce Zsh-only completion: "ng completion -z" or "ng completion --zsh". - # - # Usage: . <(ng completion --bash) # place it appropriately in .bashrc or - # . <(ng completion --zsh) # find a spot for it in .zshrc - #`); - - if (commandOptions.all && !commandOptions.bash) { - console.log('if test ".$(type -t complete 2>/dev/null || true)" = ".builtin"; then'); - } - - if (commandOptions.all || commandOptions.bash) { - console.log(stripIndent` - _ng_completion() { - local cword pword opts - - COMPREPLY=() - cword=\${COMP_WORDS[COMP_CWORD]} - pword=\${COMP_WORDS[COMP_CWORD - 1]} - - case \${pword} in - ${caseBlock} - esac - - COMPREPLY=( $(compgen -W '\${opts}' -- $cword) ) - - return 0 - } - - complete -o default -F _ng_completion ng - `); - } - - if (commandOptions.all) { - console.log(stripIndent` - elif test ".$(type -w compctl 2>/dev/null || true)" = ".compctl: builtin" ; then - `); - } - - if (commandOptions.all || commandOptions.zsh) { - console.log(stripIndent` - _ng_completion () { - local words cword opts - read -Ac words - read -cn cword - let cword-=1 - - case $words[cword] in - ${caseBlock} - esac - - setopt shwordsplit - reply=($opts) - unset shwordsplit - } - - compctl -K _ng_completion ng - `); - } - - if (commandOptions.all) { - console.log(stripIndent` - else - echo "Builtin command 'complete' or 'compctl' is redefined; cannot produce completion." - return 1 - fi`); - } - - console.log('###-end-ng-completion###'); - - } -}); - -export default CompletionCommand; diff --git a/packages/@angular/cli/commands/destroy.ts b/packages/@angular/cli/commands/destroy.ts deleted file mode 100644 index ac8ae4f53bd7..000000000000 --- a/packages/@angular/cli/commands/destroy.ts +++ /dev/null @@ -1,21 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); -const SilentError = require('silent-error'); - - -const DestroyCommand = Command.extend({ - name: 'destroy', - aliases: ['d'], - works: 'insideProject', - hidden: true, - - anonymousOptions: [ - '' - ], - - run: function() { - return Promise.reject(new SilentError('The destroy command is not supported by Angular CLI.')); - } -}); - -export default DestroyCommand; -DestroyCommand.overrideCore = true; diff --git a/packages/@angular/cli/commands/doc.ts b/packages/@angular/cli/commands/doc.ts deleted file mode 100644 index b1fa6161ab3b..000000000000 --- a/packages/@angular/cli/commands/doc.ts +++ /dev/null @@ -1,38 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); -import { DocTask } from '../tasks/doc'; - -export interface DocOptions { - search?: boolean; -} - -const DocCommand = Command.extend({ - name: 'doc', - description: 'Opens the official Angular API documentation for a given keyword.', - works: 'everywhere', - availableOptions: [ - { - name: 'search', - aliases: ['s'], - type: Boolean, - default: false, - description: 'Search whole angular.io instead of just api.' - } - ], - - anonymousOptions: [ - '' - ], - - run: function(commandOptions: DocOptions, rawArgs: Array) { - const keyword = rawArgs[0]; - - const docTask = new DocTask({ - ui: this.ui, - project: this.project - }); - - return docTask.run(keyword, commandOptions.search); - } -}); - -export default DocCommand; diff --git a/packages/@angular/cli/commands/e2e.ts b/packages/@angular/cli/commands/e2e.ts deleted file mode 100644 index fc6d084816a8..000000000000 --- a/packages/@angular/cli/commands/e2e.ts +++ /dev/null @@ -1,133 +0,0 @@ -const SilentError = require('silent-error'); - -import { overrideOptions } from '../utilities/override-options'; -import { CliConfig } from '../models/config'; -import { ServeTaskOptions, baseServeCommandOptions } from './serve'; -import { checkPort } from '../utilities/check-port'; -import { oneLine } from 'common-tags'; -const Command = require('../ember-cli/lib/models/command'); - - -export interface E2eTaskOptions extends ServeTaskOptions { - config: string; - serve: boolean; - webdriverUpdate: boolean; - specs: string[]; - elementExplorer: boolean; -} - -const E2eCommand = Command.extend({ - name: 'e2e', - aliases: ['e'], - description: 'Run e2e tests in existing project.', - works: 'insideProject', - availableOptions: overrideOptions([ - ...baseServeCommandOptions, - { - name: 'config', - type: String, - aliases: ['c'], - description: oneLine` - Use a specific config file. - Defaults to the protractor config file in angular-cli.json. - ` - }, - { - name: 'specs', - type: Array, - default: [], - aliases: ['sp'], - description: oneLine` - Override specs in the protractor config. - Can send in multiple specs by repeating flag (ng e2e --specs=spec1.ts --specs=spec2.ts). - ` - }, - { - name: 'element-explorer', - type: Boolean, - default: false, - aliases: ['ee'], - description: 'Start Protractor\'s Element Explorer for debugging.' - }, - { - name: 'webdriver-update', - type: Boolean, - default: true, - aliases: ['wu'], - description: 'Try to update webdriver.' - }, - { - name: 'serve', - type: Boolean, - default: true, - aliases: ['s'], - description: oneLine` - Compile and Serve the app. - All non-reload related serve options are also available (e.g. --port=4400). - ` - } - ], [ - { - name: 'port', - default: 0, - description: 'The port to use to serve the application.' - }, - { - name: 'watch', - default: false, - description: 'Run build when files change.' - }, - ]), - run: function (commandOptions: E2eTaskOptions) { - const E2eTask = require('../tasks/e2e').E2eTask; - - const e2eTask = new E2eTask({ - ui: this.ui, - project: this.project - }); - - if (!commandOptions.config) { - const e2eConfig = CliConfig.fromProject().config.e2e; - - if (!e2eConfig.protractor.config) { - throw new SilentError('No protractor config found in .angular-cli.json.'); - } - - commandOptions.config = e2eConfig.protractor.config; - } - - if (commandOptions.serve) { - const ServeTask = require('../tasks/serve').default; - - const serve = new ServeTask({ - ui: this.ui, - project: this.project, - }); - - // Protractor will end the proccess, so we don't need to kill the dev server - return new Promise((resolve, reject) => { - let firstRebuild = true; - function rebuildCb(stats: any) { - // don't run re-run tests on subsequent rebuilds - const cleanBuild = !!!stats.compilation.errors.length; - if (firstRebuild && cleanBuild) { - firstRebuild = false; - return resolve(e2eTask.run(commandOptions)); - } else { - return reject('Build did not succeed. Please fix errors before running e2e task'); - } - } - - checkPort(commandOptions.port, commandOptions.host) - .then((port: number) => commandOptions.port = port) - .then(() => serve.run(commandOptions, rebuildCb)) - .catch(reject); - }); - } else { - return e2eTask.run(commandOptions); - } - } -}); - - -export default E2eCommand; diff --git a/packages/@angular/cli/commands/easter-egg.ts b/packages/@angular/cli/commands/easter-egg.ts deleted file mode 100644 index 227b2612facf..000000000000 --- a/packages/@angular/cli/commands/easter-egg.ts +++ /dev/null @@ -1,35 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); -const stringUtils = require('ember-cli-string-utils'); -import chalk from 'chalk'; - - -function pickOne(of: string[]): string { - return of[Math.floor(Math.random() * of.length)]; -} - - -const MakeThisAwesomeCommand = Command.extend({ - name: 'make-this-awesome', - works: 'insideProject', - hidden: true, - - run: function (commandOptions: any, rawArgs: string[]): Promise { - (this as any)[stringUtils.camelize(this.name)](commandOptions, rawArgs); - - return Promise.resolve(); - }, - - makeThisAwesome: function() { - const phrase = pickOne([ - `You're on it, there's nothing for me to do!`, - `Let's take a look... nope, it's all good!`, - `You're doing fine.`, - `You're already doing great.`, - `Nothing to do; already awesome. Exiting.`, - `Error 418: As Awesome As Can Get.` - ]); - console.log(chalk.green(phrase)); - } -}); - -export default MakeThisAwesomeCommand; diff --git a/packages/@angular/cli/commands/eject.ts b/packages/@angular/cli/commands/eject.ts deleted file mode 100644 index fa69b6ea8e32..000000000000 --- a/packages/@angular/cli/commands/eject.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { BuildOptions } from '../models/build-options'; -import {baseBuildCommandOptions} from './build'; - -const Command = require('../ember-cli/lib/models/command'); - -// defaults for BuildOptions -export const baseEjectCommandOptions: any = [ - ...baseBuildCommandOptions, - { - name: 'force', - type: Boolean, - description: 'Overwrite any webpack.config.js and npm scripts already existing.' - }, - { - name: 'app', - type: String, - aliases: ['a'], - description: 'Specifies app name to use.' - } -]; - -export interface EjectTaskOptions extends BuildOptions { - force?: boolean; - app?: string; -} - - -const EjectCommand = Command.extend({ - name: 'eject', - description: 'Ejects your app and output the proper webpack configuration and scripts.', - - availableOptions: baseEjectCommandOptions, - - run: function (commandOptions: EjectTaskOptions) { - - const EjectTask = require('../tasks/eject').default; - const ejectTask = new EjectTask({ - project: this.project, - ui: this.ui, - }); - - return ejectTask.run(commandOptions); - } -}); - - -export default EjectCommand; diff --git a/packages/@angular/cli/commands/generate.ts b/packages/@angular/cli/commands/generate.ts deleted file mode 100644 index e9a4d79b3585..000000000000 --- a/packages/@angular/cli/commands/generate.ts +++ /dev/null @@ -1,221 +0,0 @@ -import chalk from 'chalk'; -const stringUtils = require('ember-cli-string-utils'); -import { oneLine } from 'common-tags'; -import { CliConfig } from '../models/config'; - -import 'rxjs/add/observable/of'; -import 'rxjs/add/operator/ignoreElements'; -import { - getCollection, - getEngineHost -} from '../utilities/schematics'; -import { DynamicPathOptions, dynamicPathParser } from '../utilities/dynamic-path-parser'; -import { getAppFromConfig } from '../utilities/app-utils'; -import * as path from 'path'; -import { SchematicAvailableOptions } from '../tasks/schematic-get-options'; - -const Command = require('../ember-cli/lib/models/command'); -const SilentError = require('silent-error'); - -const { cyan, yellow } = chalk; -const separatorRegEx = /[\/\\]/g; - - -export default Command.extend({ - name: 'generate', - description: 'Generates and/or modifies files based on a schematic.', - aliases: ['g'], - - availableOptions: [ - { - name: 'dry-run', - type: Boolean, - default: false, - aliases: ['d'], - description: 'Run through without making any changes.' - }, - { - name: 'force', - type: Boolean, - default: false, - aliases: ['f'], - description: 'Forces overwriting of files.' - }, - { - name: 'app', - type: String, - aliases: ['a'], - description: 'Specifies app name to use.' - }, - { - name: 'collection', - type: String, - aliases: ['c'], - description: 'Schematics collection to use.' - }, - { - name: 'lint-fix', - type: Boolean, - aliases: ['lf'], - description: 'Use lint to fix files after generation.' - } - ], - - anonymousOptions: [ - '' - ], - - getCollectionName(rawArgs: string[]) { - let collectionName = CliConfig.getValue('defaults.schematics.collection'); - if (rawArgs) { - const parsedArgs = this.parseArgs(rawArgs, false); - if (parsedArgs.options.collection) { - collectionName = parsedArgs.options.collection; - } - } - return collectionName; - }, - - beforeRun: function(rawArgs: string[]) { - - const isHelp = ['--help', '-h'].includes(rawArgs[0]); - if (isHelp) { - return; - } - - const schematicName = rawArgs[0]; - if (!schematicName) { - return Promise.reject(new SilentError(oneLine` - The "ng generate" command requires a - schematic name to be specified. - For more details, use "ng help". - `)); - } - - if (/^\d/.test(rawArgs[1])) { - SilentError.debugOrThrow('@angular/cli/commands/generate', - `The \`ng generate ${schematicName} ${rawArgs[1]}\` file name cannot begin with a digit.`); - } - - const SchematicGetOptionsTask = require('../tasks/schematic-get-options').default; - - const getOptionsTask = new SchematicGetOptionsTask({ - ui: this.ui, - project: this.project - }); - const collectionName = this.getCollectionName(rawArgs); - - return getOptionsTask.run({ - schematicName, - collectionName - }) - .then((availableOptions: SchematicAvailableOptions) => { - let anonymousOptions: string[] = []; - if (collectionName === '@schematics/angular' && schematicName === 'interface') { - anonymousOptions = ['']; - } - - this.registerOptions({ - anonymousOptions: anonymousOptions, - availableOptions: availableOptions - }); - }); - }, - - run: function (commandOptions: any, rawArgs: string[]) { - if (rawArgs[0] === 'module' && !rawArgs[1]) { - throw 'The `ng generate module` command requires a name to be specified.'; - } - - const entityName = rawArgs[1]; - commandOptions.name = stringUtils.dasherize(entityName.split(separatorRegEx).pop()); - - const appConfig = getAppFromConfig(commandOptions.app); - const dynamicPathOptions: DynamicPathOptions = { - project: this.project, - entityName: entityName, - appConfig: appConfig, - dryRun: commandOptions.dryRun - }; - const parsedPath = dynamicPathParser(dynamicPathOptions); - commandOptions.sourceDir = parsedPath.sourceDir; - const root = parsedPath.sourceDir + path.sep; - commandOptions.appRoot = parsedPath.appRoot === parsedPath.sourceDir ? '' : - parsedPath.appRoot.startsWith(root) - ? parsedPath.appRoot.substr(root.length) - : parsedPath.appRoot; - - commandOptions.path = parsedPath.dir.replace(separatorRegEx, '/'); - commandOptions.path = parsedPath.dir === parsedPath.sourceDir ? '' : - parsedPath.dir.startsWith(root) - ? commandOptions.path.substr(root.length) - : commandOptions.path; - - const cwd = this.project.root; - const schematicName = rawArgs[0]; - - if (['component', 'c', 'directive', 'd'].indexOf(schematicName) !== -1) { - if (commandOptions.prefix === undefined) { - commandOptions.prefix = appConfig.prefix; - } - - if (schematicName === 'component' || schematicName === 'c') { - if (commandOptions.styleext === undefined) { - commandOptions.styleext = CliConfig.getValue('defaults.styleExt'); - } - } - } - - const SchematicRunTask = require('../tasks/schematic-run').default; - const schematicRunTask = new SchematicRunTask({ - ui: this.ui, - project: this.project - }); - const collectionName = commandOptions.collection || - CliConfig.getValue('defaults.schematics.collection'); - - if (collectionName === '@schematics/angular' && schematicName === 'interface' && rawArgs[2]) { - commandOptions.type = rawArgs[2]; - } - - return schematicRunTask.run({ - taskOptions: commandOptions, - workingDir: cwd, - collectionName, - schematicName - }); - }, - - printDetailedHelp: function (_options: any, rawArgs: any): string | Promise { - const engineHost = getEngineHost(); - const collectionName = this.getCollectionName(); - const collection = getCollection(collectionName); - const schematicName = rawArgs[1]; - if (schematicName) { - const SchematicGetHelpOutputTask = require('../tasks/schematic-get-help-output').default; - const getHelpOutputTask = new SchematicGetHelpOutputTask({ - ui: this.ui, - project: this.project - }); - return getHelpOutputTask.run({ - schematicName, - collectionName, - nonSchematicOptions: this.availableOptions.filter((o: any) => !o.hidden) - }) - .then((output: string[]) => { - return [ - cyan(`ng generate ${schematicName} ${cyan('[name]')} ${cyan('')}`), - ...output - ].join('\n'); - }); - } else { - const schematicNames: string[] = engineHost.listSchematics(collection); - const output: string[] = []; - output.push(cyan('Available schematics:')); - schematicNames.forEach(schematicName => { - output.push(yellow(` ${schematicName}`)); - }); - return Promise.resolve(output.join('\n')); - } - } -}); diff --git a/packages/@angular/cli/commands/get.ts b/packages/@angular/cli/commands/get.ts deleted file mode 100644 index a0092f45f78f..000000000000 --- a/packages/@angular/cli/commands/get.ts +++ /dev/null @@ -1,49 +0,0 @@ -import {CliConfig} from '../models/config'; - -const SilentError = require('silent-error'); -const Command = require('../ember-cli/lib/models/command'); - - -export interface GetOptions { - global?: boolean; -} - - -const GetCommand = Command.extend({ - name: 'get', - description: 'Get a value from the configuration. Example: ng get [key]', - works: 'everywhere', - - availableOptions: [ - { - name: 'global', - type: Boolean, - 'default': false, - description: 'Get the value in the global configuration (in your home directory).' - } - ], - - run: function (commandOptions: GetOptions, rawArgs: string[]): Promise { - return new Promise(resolve => { - const config = commandOptions.global ? CliConfig.fromGlobal() : CliConfig.fromProject(); - - if (config === null) { - throw new SilentError('No config found. If you want to use global configuration, ' - + 'you need the --global argument.'); - } - - const value = config.get(rawArgs[0]); - - if (value === null || value === undefined) { - throw new SilentError('Value cannot be found.'); - } else if (typeof value == 'object') { - console.log(JSON.stringify(value, null, 2)); - } else { - console.log(value); - } - resolve(); - }); - } -}); - -export default GetCommand; diff --git a/packages/@angular/cli/commands/help.ts b/packages/@angular/cli/commands/help.ts deleted file mode 100644 index b5f4946ebbfb..000000000000 --- a/packages/@angular/cli/commands/help.ts +++ /dev/null @@ -1,93 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; - -const Command = require('../ember-cli/lib/models/command'); -const stringUtils = require('ember-cli-string-utils'); -const lookupCommand = require('../ember-cli/lib/cli/lookup-command'); - -const HelpCommand = Command.extend({ - name: 'help', - description: 'Shows help for the CLI.', - works: 'everywhere', - - availableOptions: [ - { - name: 'short', - type: Boolean, - default: false, - aliases: ['s'], - description: 'Display command name and description only.' - }, - ], - - anonymousOptions: ['command-name (Default: all)'], - - run: function (commandOptions: any, rawArgs: any) { - let commandFiles = fs.readdirSync(__dirname) - // Remove files that are not JavaScript or Typescript - .filter(file => file.match(/\.(j|t)s$/) && !file.match(/\.d.ts$/)) - .map(file => path.parse(file).name) - .map(file => file.toLowerCase()); - - let commandMap = commandFiles.reduce((acc: any, curr: string) => { - let classifiedName = stringUtils.classify(curr); - let defaultImport = require(`./${curr}`).default; - - acc[classifiedName] = defaultImport; - - return acc; - }, {}); - - if (rawArgs.indexOf('all') !== -1) { - rawArgs = []; // just act as if command not specified - } - - commandFiles.forEach(cmd => { - const Command = lookupCommand(commandMap, cmd); - - const command = new Command({ - ui: this.ui, - project: this.project, - commands: this.commands, - tasks: this.tasks - }); - - if (command.hidden || command.unknown) { - return; - } - - if (rawArgs.length > 0) { - let commandInput = rawArgs[0]; - const aliases = Command.prototype.aliases; - if (aliases && aliases.indexOf(commandInput) > -1) { - commandInput = Command.prototype.name; - } - - if (cmd === commandInput) { - if (commandOptions.short) { - this.ui.writeLine(command.printShortHelp(commandOptions)); - } else if (command.printDetailedHelp(commandOptions, rawArgs)) { - const result = command.printDetailedHelp(commandOptions, rawArgs); - if (result instanceof Promise) { - result.then(r => this.ui.writeLine(r)); - } else { - this.ui.writeLine(result); - } - } else { - this.ui.writeLine(command.printBasicHelp(commandOptions)); - } - } - } else { - if (commandOptions.short) { - this.ui.writeLine(command.printShortHelp(commandOptions)); - } else { - this.ui.writeLine(command.printBasicHelp(commandOptions)); - } - } - - }); - } -}); - -HelpCommand.overrideCore = true; -export default HelpCommand; diff --git a/packages/@angular/cli/commands/lint.ts b/packages/@angular/cli/commands/lint.ts deleted file mode 100644 index 7d75543e81a9..000000000000 --- a/packages/@angular/cli/commands/lint.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { oneLine } from 'common-tags'; -import { CliConfig } from '../models/config'; - -const Command = require('../ember-cli/lib/models/command'); - - -export interface LintCommandOptions { - fix?: boolean; - typeCheck?: boolean; - format?: string; - force?: boolean; -} - -export default Command.extend({ - name: 'lint', - aliases: ['l'], - description: 'Lints code in existing project.', - works: 'insideProject', - availableOptions: [ - { - name: 'fix', - type: Boolean, - default: false, - description: 'Fixes linting errors (may overwrite linted files).' - }, - { - name: 'type-check', - type: Boolean, - default: false, - description: 'Controls the type check for linting.' - }, - { - name: 'force', - type: Boolean, - default: false, - description: 'Succeeds even if there was linting errors.' - }, - { - name: 'format', - aliases: ['t'], - type: String, - default: 'prose', - description: oneLine` - Output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist). - ` - } - ], - run: function (commandOptions: LintCommandOptions) { - const LintTask = require('../tasks/lint').default; - - const lintTask = new LintTask({ - ui: this.ui, - project: this.project - }); - - return lintTask.run({ - ...commandOptions, - configs: CliConfig.fromProject().config.lint - }); - } -}); diff --git a/packages/@angular/cli/commands/new.ts b/packages/@angular/cli/commands/new.ts deleted file mode 100644 index aea3b7e82ab9..000000000000 --- a/packages/@angular/cli/commands/new.ts +++ /dev/null @@ -1,185 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import chalk from 'chalk'; - -import { CliConfig } from '../models/config'; -import { validateProjectName } from '../utilities/validate-project-name'; -import { oneLine } from 'common-tags'; -import { SchematicAvailableOptions } from '../tasks/schematic-get-options'; - -const { cyan } = chalk; - -const Command = require('../ember-cli/lib/models/command'); -const SilentError = require('silent-error'); - -const NewCommand = Command.extend({ - name: 'new', - aliases: ['n'], - description: `Creates a new directory and a new Angular app eg. "ng new [name]".`, - works: 'outsideProject', - - availableOptions: [ - { - name: 'dry-run', - type: Boolean, - default: false, - aliases: ['d'], - description: oneLine` - Run through without making any changes. - Will list all files that would have been created when running "ng new". - ` - }, - { - name: 'verbose', - type: Boolean, - default: false, - aliases: ['v'], - description: 'Adds more details to output logging.' - }, - { - name: 'link-cli', - type: Boolean, - default: false, - aliases: ['lc'], - description: 'Automatically link the `@angular/cli` package.', - hidden: true - }, - { - name: 'skip-install', - type: Boolean, - default: false, - aliases: ['si'], - description: 'Skip installing packages.' - }, - { - name: 'skip-commit', - type: Boolean, - default: false, - aliases: ['sc'], - description: 'Skip committing the first commit to git.' - }, - { - name: 'collection', - type: String, - aliases: ['c'], - description: 'Schematics collection to use.' - } - ], - - isProject: function (projectPath: string) { - return CliConfig.fromProject(projectPath) !== null; - }, - - getCollectionName(rawArgs: string[]) { - let collectionName = CliConfig.fromGlobal().get('defaults.schematics.collection'); - if (rawArgs) { - const parsedArgs = this.parseArgs(rawArgs, false); - if (parsedArgs.options.collection) { - collectionName = parsedArgs.options.collection; - } - } - return collectionName; - }, - - beforeRun: function (rawArgs: string[]) { - const isHelp = ['--help', '-h'].includes(rawArgs[0]); - if (isHelp) { - return; - } - - const schematicName = CliConfig.getValue('defaults.schematics.newApp'); - - if (/^\d/.test(rawArgs[1])) { - SilentError.debugOrThrow('@angular/cli/commands/generate', - `The \`ng new ${rawArgs[0]}\` file name cannot begin with a digit.`); - } - - const SchematicGetOptionsTask = require('../tasks/schematic-get-options').default; - - const getOptionsTask = new SchematicGetOptionsTask({ - ui: this.ui, - project: this.project - }); - - return getOptionsTask.run({ - schematicName, - collectionName: this.getCollectionName(rawArgs) - }) - .then((availableOptions: SchematicAvailableOptions) => { - this.registerOptions({ - availableOptions: availableOptions - }); - }); - }, - - run: function (commandOptions: any, rawArgs: string[]) { - const packageName = rawArgs.shift(); - - if (!packageName) { - return Promise.reject(new SilentError( - `The "ng ${this.name}" command requires a name argument to be specified eg. ` + - chalk.yellow('ng new [name] ') + - `For more details, use "ng help".`)); - } - - validateProjectName(packageName); - commandOptions.name = packageName; - if (commandOptions.dryRun) { - commandOptions.skipGit = true; - } - - commandOptions.directory = commandOptions.directory || packageName; - const directoryName = path.join(process.cwd(), commandOptions.directory); - - if (fs.existsSync(directoryName) && this.isProject(directoryName)) { - throw new SilentError(oneLine` - Directory ${directoryName} exists and is already an Angular CLI project. - `); - } - - if (commandOptions.collection) { - commandOptions.collectionName = commandOptions.collection; - } else { - commandOptions.collectionName = this.getCollectionName(rawArgs); - } - - const InitTask = require('../tasks/init').default; - - const initTask = new InitTask({ - project: this.project, - tasks: this.tasks, - ui: this.ui, - }); - - // Ensure skipGit has a boolean value. - commandOptions.skipGit = commandOptions.skipGit === undefined ? false : commandOptions.skipGit; - - return initTask.run(commandOptions, rawArgs); - }, - - printDetailedHelp: function (): string | Promise { - const collectionName = this.getCollectionName(); - const schematicName = CliConfig.getValue('defaults.schematics.newApp'); - const SchematicGetHelpOutputTask = require('../tasks/schematic-get-help-output').default; - const getHelpOutputTask = new SchematicGetHelpOutputTask({ - ui: this.ui, - project: this.project - }); - return getHelpOutputTask.run({ - schematicName, - collectionName, - nonSchematicOptions: this.availableOptions.filter((o: any) => !o.hidden) - }) - .then((output: string[]) => { - const outputLines = [ - cyan(`ng new ${cyan('[name]')} ${cyan('')}`), - ...output - ]; - return outputLines.join('\n'); - }); - } -}); - - -NewCommand.overrideCore = true; -export default NewCommand; diff --git a/packages/@angular/cli/commands/serve.ts b/packages/@angular/cli/commands/serve.ts deleted file mode 100644 index d059571e5644..000000000000 --- a/packages/@angular/cli/commands/serve.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { BuildOptions } from '../models/build-options'; -import { baseBuildCommandOptions } from './build'; -import { CliConfig } from '../models/config'; -import { Version } from '../upgrade/version'; -import { ServeTaskOptions } from './serve'; -import { checkPort } from '../utilities/check-port'; -import { overrideOptions } from '../utilities/override-options'; - -const Command = require('../ember-cli/lib/models/command'); - -const config = CliConfig.fromProject() || CliConfig.fromGlobal(); -const serveConfigDefaults = config.getPaths('defaults.serve', [ - 'port', 'host', 'ssl', 'sslKey', 'sslCert', 'proxyConfig' -]); -const defaultPort = process.env.PORT || serveConfigDefaults['port']; - -export interface ServeTaskOptions extends BuildOptions { - port?: number; - host?: string; - proxyConfig?: string; - liveReload?: boolean; - publicHost?: string; - disableHostCheck?: boolean; - ssl?: boolean; - sslKey?: string; - sslCert?: string; - open?: boolean; - hmr?: boolean; - servePath?: string; -} - -// Expose options unrelated to live-reload to other commands that need to run serve -export const baseServeCommandOptions: any = overrideOptions([ - ...baseBuildCommandOptions, - { - name: 'port', - type: Number, - default: defaultPort, - aliases: ['p'], - description: 'Port to listen to for serving.' - }, - { - name: 'host', - type: String, - default: serveConfigDefaults['host'], - aliases: ['H'], - description: `Listens only on ${serveConfigDefaults['host']} by default.` - }, - { - name: 'proxy-config', - type: 'Path', - default: serveConfigDefaults['proxyConfig'], - aliases: ['pc'], - description: 'Proxy configuration file.' - }, - { - name: 'ssl', - type: Boolean, - default: serveConfigDefaults['ssl'], - description: 'Serve using HTTPS.' - }, - { - name: 'ssl-key', - type: String, - default: serveConfigDefaults['sslKey'], - description: 'SSL key to use for serving HTTPS.' - }, - { - name: 'ssl-cert', - type: String, - default: serveConfigDefaults['sslCert'], - description: 'SSL certificate to use for serving HTTPS.' - }, - { - name: 'open', - type: Boolean, - default: false, - aliases: ['o'], - description: 'Opens the url in default browser.', - }, - { - name: 'live-reload', - type: Boolean, - default: true, - aliases: ['lr'], - description: 'Whether to reload the page on change, using live-reload.' - }, - { - name: 'public-host', - type: String, - aliases: ['live-reload-client'], - description: 'Specify the URL that the browser client will use.' - }, - { - name: 'disable-host-check', - type: Boolean, - default: false, - description: 'Don\'t verify connected clients are part of allowed hosts.', - }, - { - name: 'serve-path', - type: String, - description: 'The pathname where the app will be served.' - }, - { - name: 'hmr', - type: Boolean, - default: false, - description: 'Enable hot module replacement.', - } -], [ - { - name: 'watch', - default: true, - description: 'Rebuild on change.' - } -]); - -const ServeCommand = Command.extend({ - name: 'serve', - description: 'Builds and serves your app, rebuilding on file changes.', - aliases: ['server', 's'], - - availableOptions: baseServeCommandOptions, - - run: function (commandOptions: ServeTaskOptions) { - const ServeTask = require('../tasks/serve').default; - - // Check Angular and TypeScript versions. - Version.assertAngularVersionIs2_3_1OrHigher(this.project.root); - Version.assertTypescriptVersion(this.project.root); - - // Force commonjs module format for TS on dev builds. - if (commandOptions.target === 'development') { - commandOptions.forceTsCommonjs = true; - } - - // Default evalSourcemaps to true for serve. This makes rebuilds faster. - commandOptions.evalSourcemaps = true; - - return checkPort(commandOptions.port, commandOptions.host, defaultPort) - .then(port => { - commandOptions.port = port; - - const serve = new ServeTask({ - ui: this.ui, - project: this.project, - }); - - return serve.run(commandOptions); - }); - } -}); - -export default ServeCommand; diff --git a/packages/@angular/cli/commands/set.ts b/packages/@angular/cli/commands/set.ts deleted file mode 100644 index 8f8e8bd8ba85..000000000000 --- a/packages/@angular/cli/commands/set.ts +++ /dev/null @@ -1,116 +0,0 @@ -import * as fs from 'fs'; -import chalk from 'chalk'; -import { CliConfig } from '../models/config'; -import { oneLine } from 'common-tags'; - -const SilentError = require('silent-error'); -const Command = require('../ember-cli/lib/models/command'); - -export interface SetOptions { - global?: boolean; -} - - -const SetCommand = Command.extend({ - name: 'set', - description: 'Set a value in the configuration.', - works: 'everywhere', - - availableOptions: [ - { - name: 'global', - type: Boolean, - 'default': false, - aliases: ['g'], - description: 'Set the value in the global configuration rather than in your project\'s.' - }, - ], - - asBoolean: function (raw: string): boolean { - if (raw == 'true' || raw == '1') { - return true; - } else if (raw == 'false' || raw == '' || raw == '0') { - return false; - } else { - throw new SilentError(`Invalid boolean value: "${raw}"`); - } - }, - asNumber: function (raw: string): number { - if (Number.isNaN(+raw)) { - throw new SilentError(`Invalid number value: "${raw}"`); - } - return +raw; - }, - - run: function (commandOptions: SetOptions, rawArgs: string[]): Promise { - return new Promise(resolve => { - const config = commandOptions.global ? CliConfig.fromGlobal() : CliConfig.fromProject(); - if (config === null) { - throw new SilentError('No config found. If you want to use global configuration, ' - + 'you need the --global argument.'); - } - - let [jsonPath, rawValue] = rawArgs; - - if (rawValue === undefined) { - [jsonPath, rawValue] = jsonPath.split('=', 2); - if (rawValue === undefined) { - throw new SilentError('Must specify a value.'); - } - } - - const type = config.typeOf(jsonPath); - let value: any = rawValue; - switch (type) { - case 'boolean': value = this.asBoolean(rawValue); break; - case 'number': value = this.asNumber(rawValue); break; - case 'string': value = rawValue; break; - - default: value = parseValue(rawValue, jsonPath); - } - - if (jsonPath.indexOf('prefix') > 0) { - // update tslint if prefix is updated - updateLintForPrefix(this.project.root + '/tslint.json', value); - } - - try { - config.set(jsonPath, value); - config.save(); - } catch (error) { - throw new SilentError(error.message); - } - resolve(); - }); - } -}); - -function updateLintForPrefix(filePath: string, prefix: string): void { - const tsLint = JSON.parse(fs.readFileSync(filePath, 'utf8')); - const componentLint = tsLint.rules['component-selector'][2]; - if (componentLint instanceof Array) { - tsLint.rules['component-selector'][2].push(prefix); - } else { - tsLint.rules['component-selector'][2] = prefix; - } - - const directiveLint = tsLint.rules['directive-selector'][2]; - if (directiveLint instanceof Array) { - tsLint.rules['directive-selector'][2].push(prefix); - } else { - tsLint.rules['directive-selector'][2] = prefix; - } - fs.writeFileSync(filePath, JSON.stringify(tsLint, null, 2)); - console.log(chalk.yellow(oneLine`we have updated tslint to match prefix, - you may want to fix linting errors.`)); -} - -function parseValue(rawValue: string, path: string) { - try { - return JSON.parse(rawValue); - } catch (error) { - throw new SilentError(`No node found at path ${path}`); - } -} - -export default SetCommand; diff --git a/packages/@angular/cli/commands/test.ts b/packages/@angular/cli/commands/test.ts deleted file mode 100644 index 40fa3ebaa69c..000000000000 --- a/packages/@angular/cli/commands/test.ts +++ /dev/null @@ -1,150 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); -import TestTask from '../tasks/test'; -import { CliConfig } from '../models/config'; -import { oneLine } from 'common-tags'; - -const config = CliConfig.fromProject() || CliConfig.fromGlobal(); -const testConfigDefaults = config.getPaths('defaults.build', [ - 'progress', 'poll', 'preserveSymlinks' -]); - -export interface TestOptions { - watch?: boolean; - codeCoverage?: boolean; - singleRun?: boolean; - browsers?: string; - colors?: boolean; - log?: string; - port?: number; - reporters?: string; - sourcemaps?: boolean; - progress?: boolean; - config: string; - poll?: number; - environment?: string; - app?: string; - preserveSymlinks?: boolean; - forceTsCommonjs?: boolean; -} - - -const TestCommand = Command.extend({ - name: 'test', - aliases: ['t'], - description: 'Run unit tests in existing project.', - works: 'insideProject', - - availableOptions: [ - { - name: 'watch', - type: Boolean, - aliases: ['w'], - description: 'Run build when files change.' - }, - { - name: 'code-coverage', - type: Boolean, - default: false, - aliases: ['cc'], - description: 'Coverage report will be in the coverage/ directory.' - }, - { - name: 'config', - type: String, - aliases: ['c'], - description: oneLine`Use a specific config file. - Defaults to the karma config file in .angular-cli.json.` - }, - { - name: 'single-run', - type: Boolean, - aliases: ['sr'], - description: 'Run tests a single time.' - }, - { - name: 'progress', - type: Boolean, - default: testConfigDefaults['progress'], - description: 'Log progress to the console while in progress.' - }, - { - name: 'browsers', - type: String, - description: 'Override which browsers tests are run against.' - }, - { - name: 'colors', - type: Boolean, - description: 'Enable or disable colors in the output (reporters and logs).' - }, - { - name: 'log-level', - type: String, - description: 'Level of logging.' - }, - { - name: 'port', - type: Number, - description: 'Port where the web server will be listening.' - }, - { - name: 'reporters', - type: String, - description: 'List of reporters to use.' - }, - { - name: 'sourcemaps', - type: Boolean, - default: true, - aliases: ['sm', 'sourcemap'], - description: 'Output sourcemaps.' - }, - { - name: 'poll', - type: Number, - default: testConfigDefaults['poll'], - description: 'Enable and define the file watching poll time period (milliseconds).' - }, - { - name: 'environment', - type: String, - aliases: ['e'] , - description: 'Defines the build environment.' - }, - { - name: 'preserve-symlinks', - type: Boolean, - description: 'Do not use the real path when resolving modules.', - default: testConfigDefaults['preserveSymlinks'] - }, - { - name: 'app', - type: String, - aliases: ['a'], - description: 'Specifies app name to use.' - } - ], - - run: function (commandOptions: TestOptions) { - const testTask = new TestTask({ - ui: this.ui, - project: this.project - }); - - if (commandOptions.watch !== undefined && !commandOptions.watch) { - // if not watching ensure karma is doing a single run - commandOptions.singleRun = true; - } - - // Don't force commonjs for code coverage builds, some setups need es2015 for it. - // https://github.com/angular/angular-cli/issues/5526 - if (!commandOptions.codeCoverage) { - commandOptions.forceTsCommonjs = true; - } - - return testTask.run(commandOptions); - } -}); - -TestCommand.overrideCore = true; -export default TestCommand; diff --git a/packages/@angular/cli/commands/version.ts b/packages/@angular/cli/commands/version.ts deleted file mode 100644 index abab2e803c1a..000000000000 --- a/packages/@angular/cli/commands/version.ts +++ /dev/null @@ -1,139 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); -import { stripIndents } from 'common-tags'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as child_process from 'child_process'; -import chalk from 'chalk'; -import { CliConfig } from '../models/config'; - - -const VersionCommand = Command.extend({ - name: 'version', - description: 'Outputs Angular CLI version.', - aliases: ['v', '--version', '-v'], - works: 'everywhere', - - availableOptions: [], - - run: function (_options: any) { - let versions: { [name: string]: string } = {}; - let angular: { [name: string]: string } = {}; - let angularCoreVersion = ''; - let angularSameAsCore: string[] = []; - const pkg = require(path.resolve(__dirname, '..', 'package.json')); - let projPkg: any; - try { - projPkg = require(path.resolve(this.project.root, 'package.json')); - } catch (exception) { - projPkg = undefined; - } - - const roots = ['@angular-devkit/', '@ngtools/', '@schematics/', 'typescript', 'webpack']; - - let ngCliVersion = pkg.version; - if (!__dirname.match(/node_modules/)) { - let gitBranch = '??'; - try { - const gitRefName = '' + child_process.execSync('git symbolic-ref HEAD', {cwd: __dirname}); - gitBranch = path.basename(gitRefName.replace('\n', '')); - } catch (e) { - } - - ngCliVersion = `local (v${pkg.version}, branch: ${gitBranch})`; - } - const config = CliConfig.fromProject(); - if (config && config.config && config.config.project) { - if (config.config.project.ejected) { - ngCliVersion += ' (e)'; - } - } - - if (projPkg) { - roots.forEach(root => { - versions = Object.assign(versions, this.getDependencyVersions(projPkg, root)); - }); - angular = this.getDependencyVersions(projPkg, '@angular/'); - - // Filter all angular versions that are the same as core. - angularCoreVersion = angular['@angular/core']; - if (angularCoreVersion) { - for (const angularPackage of Object.keys(angular)) { - if (angular[angularPackage] == angularCoreVersion) { - angularSameAsCore.push(angularPackage.replace(/^@angular\//, '')); - delete angular[angularPackage]; - } - } - } - } - const asciiArt = ` - _ _ ____ _ ___ - / \\ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| - / â–³ \\ | '_ \\ / _\` | | | | |/ _\` | '__| | | | | | | - / ___ \\| | | | (_| | |_| | | (_| | | | |___| |___ | | -/_/ \\_\\_| |_|\\__, |\\__,_|_|\\__,_|_| \\____|_____|___| - |___/ - `; - - this.ui.writeLine(stripIndents` - ${chalk.red(asciiArt)} - Angular CLI: ${ngCliVersion} - Node: ${process.versions.node} - OS: ${process.platform} ${process.arch} - Angular: ${angularCoreVersion} - ... ${angularSameAsCore.sort().reduce((acc, name) => { - // Perform a simple word wrap around 60. - if (acc.length == 0) { - return [name]; - } - const line = (acc[acc.length - 1] + ', ' + name); - if (line.length > 60) { - acc.push(name); - } else { - acc[acc.length - 1] = line; - } - return acc; - }, []).join('\n... ')} - - ${Object.keys(angular).map(module => module + ': ' + angular[module]).sort().join('\n')} - ${Object.keys(versions).map(module => module + ': ' + versions[module]).sort().join('\n')} - `); - }, - - getDependencyVersions: function(pkg: any, prefix: string): { [name: string]: string } { - const modules: any = {}; - const deps = Object.keys(pkg['dependencies'] || {}) - .concat(Object.keys(pkg['devDependencies'] || {})) - .filter(depName => depName && depName.startsWith(prefix)); - - if (prefix[0] == '@') { - try { - fs.readdirSync(path.resolve(this.project.root, 'node_modules', prefix)) - .map(name => prefix + name) - .forEach(name => deps.push(name)); - } catch (_) {} - } else { - modules[prefix] = this.getVersion(prefix); - } - - deps.forEach(name => modules[name] = this.getVersion(name)); - - return modules; - }, - - getVersion: function(moduleName: string): string { - try { - const modulePkg = require(path.resolve( - this.project.root, - 'node_modules', - moduleName, - 'package.json')); - return modulePkg.version; - } catch (e) { - return 'error'; - } - } -}); - - -VersionCommand.overrideCore = true; -export default VersionCommand; diff --git a/packages/@angular/cli/commands/xi18n.ts b/packages/@angular/cli/commands/xi18n.ts deleted file mode 100644 index afaea034de80..000000000000 --- a/packages/@angular/cli/commands/xi18n.ts +++ /dev/null @@ -1,75 +0,0 @@ -const Command = require('../ember-cli/lib/models/command'); - -export interface Xi18nOptions { - outputPath?: string; - verbose?: boolean; - i18nFormat?: string; - locale?: string; - outFile?: string; -} - -const Xi18nCommand = Command.extend({ - name: 'xi18n', - description: 'Extracts i18n messages from source code.', - works: 'insideProject', - availableOptions: [ - { - name: 'i18n-format', - type: String, - default: 'xlf', - aliases: ['f', {'xmb': 'xmb'}, {'xlf': 'xlf'}, {'xliff': 'xlf'}], - description: 'Output format for the generated file.' - }, - { - name: 'output-path', - type: 'Path', - default: null, - aliases: ['op'], - description: 'Path where output will be placed.' - }, - { - name: 'verbose', - type: Boolean, - default: false, - description: 'Adds more details to output logging.' - }, - { - name: 'progress', - type: Boolean, - default: true, - description: 'Log progress to the console while running.' - }, - { - name: 'app', - type: String, - aliases: ['a'], - description: 'Specifies app name to use.' - }, - { - name: 'locale', - type: String, - aliases: ['l'], - description: 'Specifies the source language of the application.' - }, - { - name: 'out-file', - type: String, - aliases: ['of'], - description: 'Name of the file to output.' - }, - ], - run: function (commandOptions: any) { - const {Extracti18nTask} = require('../tasks/extract-i18n'); - - const xi18nTask = new Extracti18nTask({ - ui: this.ui, - project: this.project - }); - - return xi18nTask.run(commandOptions); - } -}); - - -export default Xi18nCommand; - diff --git a/packages/@angular/cli/custom-typings.d.ts b/packages/@angular/cli/custom-typings.d.ts deleted file mode 100644 index ccd697a97ffa..000000000000 --- a/packages/@angular/cli/custom-typings.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -interface IWebpackDevServerConfigurationOptions { - contentBase?: boolean | string | string[]; - hot?: boolean; - historyApiFallback?: {[key: string]: any} | boolean; - compress?: boolean; - proxy?: {[key: string]: string}; - staticOptions?: any; - quiet?: boolean; - noInfo?: boolean; - lazy?: boolean; - filename?: string; - watchOptions?: { - aggregateTimeout?: number; - poll?: number; - }; - publicPath?: string; - headers?: { [key: string]: string }; - stats?: { [key: string]: boolean } | string; - inline: boolean; - https?: boolean; - key?: string; - cert?: string; - overlay?: boolean | { errors: boolean, warnings: boolean }; - public?: string; - disableHostCheck?: boolean; -} diff --git a/packages/@angular/cli/ember-cli/LICENSE.md b/packages/@angular/cli/ember-cli/LICENSE.md deleted file mode 100644 index 3a86b810c14a..000000000000 --- a/packages/@angular/cli/ember-cli/LICENSE.md +++ /dev/null @@ -1,21 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2013-2016 Stefan Penner, Robert Jackson and ember-cli contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/packages/@angular/cli/ember-cli/lib/cli/cli.js b/packages/@angular/cli/ember-cli/lib/cli/cli.js deleted file mode 100644 index b5fc4ebebaaa..000000000000 --- a/packages/@angular/cli/ember-cli/lib/cli/cli.js +++ /dev/null @@ -1,245 +0,0 @@ -'use strict'; - -const lookupCommand = require('./lookup-command'); -const getOptionArgs = require('../utilities/get-option-args'); - -// Disabled until e2e and serve command can be evaluated/corrected -- require('../utilities/will-interrupt-process'); -const onProcessInterrupt = { addHandler: (_handler) => { }, removeHandler: (_handler) => { } }; - -class CLI { - /** - * @private - * @class CLI - * @constructor - * @param options - */ - constructor(options) { - /** - * @private - * @property name - */ - this.name = options.name; - - /** - * @private - * @property ui - * @type UI - */ - this.ui = options.ui; - - /** - * @private - * @property analytics - */ - this.analytics = options.analytics; - - /** - * @private - * @property testing - * @type Boolean - */ - this.testing = options.testing; - - /** - * @private - * @property disableDependencyChecker - * @type Boolean - */ - this.disableDependencyChecker = options.disableDependencyChecker; - - /** - * @private - * @property root - */ - this.root = options.root; - - /** - * @private - * @property npmPackage - */ - this.npmPackage = options.npmPackage; - - /** - * @private - * @property instrumentation - */ - this.instrumentation = { - stopAndReport: (...args) => { }, - start: (...args) => { }, - }; - } - - /** - * @private - * @method run - * @param environment - * @return {Promise} - */ - run(environment) { - let shutdownOnExit = null; - - return Promise.resolve().then(() => { - let args = environment.cliArgs.slice(); - - if (args.length === 0) { - args[0] = 'help'; - } - - if (args[0] === '--help') { - if (args.length === 1) { - args[0] = 'help'; - } else { - args.shift(); - args.push('--help'); - } - } - - let commandName = args.shift(); - let commandArgs = args; - let helpOptions; - - let CurrentCommand = lookupCommand(environment.commands, commandName, commandArgs, { - project: environment.project, - ui: this.ui, - }); - - let command = new CurrentCommand({ - ui: this.ui, - analytics: this.analytics, - commands: environment.commands, - tasks: environment.tasks, - project: environment.project, - settings: environment.settings, - testing: this.testing, - cli: this, - }); - - getOptionArgs('--verbose', commandArgs).forEach(arg => { - process.env[`EMBER_VERBOSE_${arg.toUpperCase()}`] = 'true'; - }); - - if (!this.testing) { - let skipInstallationCheck = commandArgs.indexOf('--skip-installation-check') !== -1; - if (environment.project.isEmberCLIProject() && !skipInstallationCheck) { - const InstallationChecker = require('../models/installation-checker'); - new InstallationChecker({ project: environment.project }).checkInstallations(); - } - } - - let instrumentation = this.instrumentation; - let onCommandInterrupt; - - let runPromise = Promise.resolve().then(() => { - instrumentation.stopAndReport('init'); - instrumentation.start('command'); - - onProcessInterrupt.addHandler(onCommandInterrupt); - - return command.beforeRun(commandArgs); - }).then(() => { - return command.validateAndRun(commandArgs); - }).then(result => { - instrumentation.stopAndReport('command', commandName, commandArgs); - - onProcessInterrupt.removeHandler(onCommandInterrupt); - - return result; - }).then(result => { - // if the help option was passed, call the help command - if (result === 'callHelp') { - helpOptions = { - environment, - commandName, - commandArgs, - }; - - return this.callHelp(helpOptions); - } - - return result; - }).then(exitCode => { - // TODO: fix this - // Possibly this issue: https://github.com/joyent/node/issues/8329 - // Wait to resolve promise when running on windows. - // This ensures that stdout is flushed so acceptance tests get full output - - return new Promise(resolve => { - if (process.platform === 'win32') { - setTimeout(resolve, 250, exitCode); - } else { - resolve(exitCode); - } - }); - }); - - onCommandInterrupt = () => - Promise.resolve(command.onInterrupt()) - .then(() => runPromise); - - return runPromise; - }) - .catch(this.logError.bind(this)); - } - - /** - * @private - * @method callHelp - * @param options - * @return {Promise} - */ - callHelp(options) { - let environment = options.environment; - let commandName = options.commandName; - let commandArgs = options.commandArgs; - let helpIndex = commandArgs.indexOf('--help'); - let hIndex = commandArgs.indexOf('-h'); - - let HelpCommand = lookupCommand(environment.commands, 'help', commandArgs, { - project: environment.project, - ui: this.ui, - }); - - let help = new HelpCommand({ - ui: this.ui, - analytics: this.analytics, - commands: environment.commands, - tasks: environment.tasks, - project: environment.project, - settings: environment.settings, - testing: this.testing, - }); - - if (helpIndex > -1) { - commandArgs.splice(helpIndex, 1); - } - - if (hIndex > -1) { - commandArgs.splice(hIndex, 1); - } - - commandArgs.unshift(commandName); - - return help.validateAndRun(commandArgs); - } - - /** - * @private - * @method logError - * @param error - * @return {number} - */ - logError(error) { - if (this.testing && error) { - console.error(error.message); - if (error.stack) { - console.error(error.stack); - } - throw error; - } - this.ui.errorLog.push(error); - this.ui.writeError(error); - return 1; - } -} - -module.exports = CLI; diff --git a/packages/@angular/cli/ember-cli/lib/cli/index.js b/packages/@angular/cli/ember-cli/lib/cli/index.js deleted file mode 100644 index 57afbe466843..000000000000 --- a/packages/@angular/cli/ember-cli/lib/cli/index.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; - -// Main entry point -const path = require('path'); - -// ember-cli and user apps have many dependencies, many of which require -// process.addListener('exit', ....) for cleanup, by default this limit for -// such listeners is 10, recently users have been increasing this and not to -// their fault, rather they are including large and more diverse sets of -// node_modules. -// -// https://github.com/babel/ember-cli-babel/issues/76 -process.setMaxListeners(1000); - -// Options: Array cliArgs, Stream inputStream, Stream outputStream -module.exports = function(options) { - let UI = options.UI || require('../ui'); - const CLI = require('./cli'); - const Project = require('../models/project'); - - // TODO: one UI (lib/models/project.js also has one for now...) - let ui = new UI({ - inputStream: options.inputStream, - outputStream: options.outputStream, - errorStream: options.errorStream || process.stderr, - errorLog: options.errorLog || [], - ci: process.env.CI || (/^(dumb|emacs)$/).test(process.env.TERM), - writeLevel: (process.argv.indexOf('--silent') !== -1) ? 'ERROR' : undefined, - }); - - - let defaultUpdateCheckerOptions = { - checkForUpdates: false, - }; - - let cli = new CLI({ - ui, - testing: options.testing, - name: options.cli ? options.cli.name : 'ember', - disableDependencyChecker: options.disableDependencyChecker, - root: options.cli ? options.cli.root : path.resolve(__dirname, '..', '..'), - npmPackage: options.cli ? options.cli.npmPackage : 'ember-cli', - }); - - let project = Project.projectOrnullProject(ui, cli); - - let environment = { - tasks: options.tasks || {}, - cliArgs: options.cliArgs, - commands: options.commands || {}, - project, - settings: defaultUpdateCheckerOptions, - }; - - return cli.run(environment); -}; diff --git a/packages/@angular/cli/ember-cli/lib/cli/lookup-command.js b/packages/@angular/cli/ember-cli/lib/cli/lookup-command.js deleted file mode 100644 index fe30b66c8105..000000000000 --- a/packages/@angular/cli/ember-cli/lib/cli/lookup-command.js +++ /dev/null @@ -1,38 +0,0 @@ -'use strict'; - -const UnknownCommand = require('../commands/unknown'); - -module.exports = function(commands, commandName, commandArgs, optionHash) { - - function aliasMatches(alias) { - return alias === commandName; - } - - function findCommand(commands, commandName) { - for (let key in commands) { - let command = commands[key]; - - let name = command.prototype.name; - let aliases = command.prototype.aliases || []; - - if (name === commandName || aliases.some(aliasMatches)) { - return command; - } - } - } - - // Attempt to find command in ember-cli core commands - let command = findCommand(commands, commandName); - - if (command) { - return command; - } - - // if we didn't find anything, return an "UnknownCommand" - return class extends UnknownCommand { - constructor(options) { - super(options); - this.name = commandName; - } - }; -}; diff --git a/packages/@angular/cli/ember-cli/lib/commands/unknown.js b/packages/@angular/cli/ember-cli/lib/commands/unknown.js deleted file mode 100644 index 2bf091989953..000000000000 --- a/packages/@angular/cli/ember-cli/lib/commands/unknown.js +++ /dev/null @@ -1,18 +0,0 @@ -'use strict'; - -const Command = require('../models/command'); -const SilentError = require('silent-error'); -const chalk = require('chalk'); - -module.exports = Command.extend({ - skipHelp: true, - unknown: true, - - printBasicHelp() { - return chalk.red(`No help entry for '${this.name}'`); - }, - - validateAndRun() { - throw new SilentError(`The specified command ${this.name} is invalid. For available options, see \`ng help\`.`); - }, -}); diff --git a/packages/@angular/cli/ember-cli/lib/models/command.js b/packages/@angular/cli/ember-cli/lib/models/command.js deleted file mode 100644 index 5e5bcb8c4bf7..000000000000 --- a/packages/@angular/cli/ember-cli/lib/models/command.js +++ /dev/null @@ -1,662 +0,0 @@ -'use strict'; - -const nopt = require('nopt'); -const chalk = require('chalk'); -const path = require('path'); -const camelize = require('ember-cli-string-utils').camelize; -const printCommand = require('../utilities/print-command'); -const _ = require('lodash'); -const EOL = require('os').EOL; -const CoreObject = require('core-object'); -const SilentError = require('silent-error'); -const fs = require('fs'); - -let cache = {}; - -let allowedWorkOptions = { - insideProject: true, - outsideProject: true, - everywhere: true, -}; - -path.name = 'Path'; - -/** - * The base class for all CLI commands. - * - * @module ember-cli - * @class Command - * @constructor - * @extends CoreObject - */ -let Command = CoreObject.extend({ - /** - * The description of what this command does. - * - * @final - * @property description - * @type String - */ - description: null, - - /** - * Does this command work everywhere or just inside or outside of projects. - * - * Possible values: - * - * - `insideProject` - * - `outsideProject` - * - `everywhere` - * - * @final - * @property works - * @type String - * @default `insideProject` - */ - works: 'insideProject', - - _printableProperties: [ - 'name', - 'description', - 'aliases', - 'works', - 'availableOptions', - 'anonymousOptions', - ], - - init() { - this._super.apply(this, arguments); - - /** - * @final - * @property isWithinProject - * @type Boolean - */ - this.isWithinProject = this.project.isEmberCLIProject(); - - /** - * The name of the command. - * - * @final - * @property name - * @type String - * @example `new` or `generate` - */ - this.name = this.name || ''; - - /** - * An array of aliases for the command - * - * @final - * @property aliases - * @type Array - * @example `['g']` for the `generate` command - */ - this.aliases = this.aliases || []; - - // Works Property - if (!allowedWorkOptions[this.works]) { - throw new Error(`The "${this.name}" command's works field has to be either "everywhere", "insideProject" or "outsideProject".`); - } - - /** - * An array of available options for the command - * - * @final - * @property availableOptions - * @type Array - * @example - * ```js - * availableOptions: [ - * { name: 'dry-run', type: Boolean, default: false, aliases: ['d'] }, - * { name: 'verbose', type: Boolean, default: false, aliases: ['v'] }, - * { name: 'blueprint', type: String, default: 'app', aliases: ['b'] }, - * { name: 'skip-npm', type: Boolean, default: false, aliases: ['sn'] }, - * { name: 'skip-bower', type: Boolean, default: false, aliases: ['sb'] }, - * { name: 'skip-git', type: Boolean, default: false, aliases: ['sg'] }, - * { name: 'directory', type: String , aliases: ['dir'] } - * ], - * ``` - */ - this.availableOptions = this.availableOptions || []; - - /** - * An array of anonymous options for the command - * - * @final - * @property anonymousOptions - * @type Array - * @example - * ```js - * anonymousOptions: [ - * '' - * ], - * ``` - */ - this.anonymousOptions = this.anonymousOptions || []; - - this.registerOptions(); - }, - - /** - Registers options with command. This method provides the ability to extend or override command options. - Expects an object containing anonymousOptions or availableOptions, which it will then merge with - existing availableOptions before building the optionsAliases which are used to define shorthands. - @method registerOptions - @param {Object} options - */ - registerOptions(options) { - let extendedAvailableOptions = (options && options.availableOptions) || []; - let extendedAnonymousOptions = (options && options.anonymousOptions) || []; - - this.anonymousOptions = _.union(this.anonymousOptions.slice(0), extendedAnonymousOptions); - - // merge any availableOptions - this.availableOptions = _.union(this.availableOptions.slice(0), extendedAvailableOptions); - - let optionKeys = _.uniq(_.map(this.availableOptions, 'name')); - - optionKeys.map(this.mergeDuplicateOption.bind(this)); - - this.optionsAliases = this.optionsAliases || {}; - - this.availableOptions.map(this.validateOption.bind(this)); - }, - - /** - * Called when command is interrupted from outside, e.g. ctrl+C or process kill - * Can be used to cleanup artifacts produced by command and control process exit code - * - * @method onInterrupt - * @return {Promise|undefined} if rejected promise then result of promise will be used as an exit code - */ - onInterrupt() { - if (this._currentTask) { - return this._currentTask.onInterrupt(); - } else { - // interrupt all external commands which don't use `runTask()` with an error - process.exit(1); - } - }, - - _env(/* name */) { - return { - ui: this.ui, - analytics: this.analytics, - project: this.project, - testing: this.testing, - settings: this.settings, - }; - }, - - /** - * Looks up for the task and runs - * It also keeps the reference for the current active task - * Keeping reference for the current task allows to cleanup task on interruption - * - * @private - * @method runTask - * @throws {Error} when no task found - * @throws {Error} on attempt to run concurrent task - * @param {string} name Task name from the tasks registry. Should be capitalized - * @param {object} options - * @return {Promise} Task run - */ - runTask(name, options) { - if (this._currentTask) { - throw new Error(`Concurrent tasks are not supported`); - } - - let Task = this.tasks[name]; - if (!Task) { - throw new Error(`Unknown task "${name}"`); - } - - let task = new Task(this._env(name)); - - this._currentTask = task; - - return Promise.resolve().then(() => task.run(options)) - .finally(() => { - delete this._currentTask; - }); - }, - - /** - Hook for extending a command before it is run in the cli.run command. - Most common use case would be to extend availableOptions. - @method beforeRun - @return {Promise|null} - */ - beforeRun() { - - }, - - /** - @method validateAndRun - @return {Promise} - */ - validateAndRun(args) { - return new Promise(resolve => { - let commandOptions = this.parseArgs(args); - // if the help option was passed, resolve with 'callHelp' to call help command - if (commandOptions && (commandOptions.options.help || commandOptions.options.h)) { - return resolve('callHelp'); - } - - if (commandOptions === null) { - return resolve(); - } - - if (this.works === 'outsideProject' && this.isWithinProject) { - throw new SilentError(`You cannot use the ${chalk.green(this.name)} command inside an Angular CLI project.`); - } - - if (this.works === 'insideProject') { - if (!this.project.hasDependencies()) { - throw new SilentError('node_modules appears empty, you may need to run `npm install`'); - } - } - - resolve(this.run(commandOptions.options, commandOptions.args)); - }); - }, - - /** - Reports if the given command has a command line option by a given name - @method hasOption - @param {String} name - @return {Boolean} - */ - hasOption(name) { - for (let i = 0; i < this.availableOptions.length; i++) { - if (this.availableOptions[i].name === name) { - return true; - } - } - return false; - }, - - /** - Merges any options with duplicate keys in the availableOptions array. - Used primarily by registerOptions. - @method mergeDuplicateOption - @param {String} key - @return {Object} - */ - mergeDuplicateOption(key) { - let duplicateOptions, mergedOption, mergedAliases; - // get duplicates to merge - duplicateOptions = _.filter(this.availableOptions, { 'name': key }); - - if (duplicateOptions.length > 1) { - // TODO: warn on duplicates and overwriting - mergedAliases = []; - - _.map(duplicateOptions, 'aliases').map(alias => { - alias.map(a => { - mergedAliases.push(a); - }); - }); - - // merge duplicate options - mergedOption = _.assign.apply(null, duplicateOptions); - - // replace aliases with unique aliases - mergedOption.aliases = _.uniqBy(mergedAliases, alias => { - if (typeof alias === 'object') { - return alias[Object.keys(alias)[0]]; - } - return alias; - }); - - // remove duplicates from options - this.availableOptions = _.reject(this.availableOptions, { 'name': key }); - this.availableOptions.push(mergedOption); - } - return this.availableOptions; - }, - - /** - Normalizes option, filling in implicit values - @method normalizeOption - @param {Object} option - @return {Object} - */ - normalizeOption(option) { - option.key = camelize(option.name); - option.aliases = (option.aliases || []); - if (option.aliases.indexOf(camelize(option.name)) === -1) { - option.aliases = option.aliases.concat(camelize(option.name)); - } - option.required = option.required || false; - return option; - }, - - /** - Assigns option - @method assignOption - @param {Object} option - @param {Object} parsedOptions - @param {Object} commandOptions - @return {Boolean} - */ - assignOption(option, parsedOptions, commandOptions) { - let isValid = isValidParsedOption(option, parsedOptions[option.name]); - if (isValid) { - if (parsedOptions[option.name] === undefined) { - if (option.default !== undefined) { - commandOptions[option.key] = option.default; - } - - if (this.settings[option.name] !== undefined) { - commandOptions[option.key] = this.settings[option.name]; - } else if (this.settings[option.key] !== undefined) { - commandOptions[option.key] = this.settings[option.key]; - } - } else { - commandOptions[option.key] = parsedOptions[option.name]; - delete parsedOptions[option.name]; - } - } else { - this.ui.writeLine(`The specified command ${chalk.green(this.name)} requires the option ${chalk.green(option.name)}.`); - } - return isValid; - }, - - /** - Validates option - @method validateOption - @param {Object} option - @return {Boolean} - */ - validateOption(option) { - let parsedAliases; - - if (!option.name || !option.type) { - throw new Error(`The command "${this.name}" has an option without the required type and name fields.`); - } - - if (option.name !== option.name.toLowerCase()) { - throw new Error(`The "${option.name}" option's name of the "${this.name}" command contains a capital letter.`); - } - - this.normalizeOption(option); - - if (option.aliases) { - parsedAliases = option.aliases.map(this.parseAlias.bind(this, option)); - return parsedAliases.map(this.assignAlias.bind(this, option)).indexOf(false) === -1; - } - return false; - }, - - /** - Parses alias for an option and adds it to optionsAliases - @method parseAlias - @param {Object} option - @param {Object|String} alias - @return {Object} - */ - parseAlias(option, alias) { - let aliasType = typeof alias; - let key, value, aliasValue; - - if (isValidAlias(alias, option.type)) { - if (aliasType === 'string') { - key = alias; - value = [`--${option.name}`]; - } else if (aliasType === 'object') { - key = Object.keys(alias)[0]; - value = [`--${option.name}`, alias[key]]; - } - } else { - if (Array.isArray(alias)) { - aliasType = 'array'; - aliasValue = alias.join(','); - } else { - aliasValue = alias; - try { - aliasValue = JSON.parse(alias); - } catch (e) { - } - } - throw new Error(`The "${aliasValue}" [type:${aliasType}] alias is not an acceptable value. ` + - `It must be a string or single key object with a string value (for example, "value" or { "key" : "value" }).`); - } - - return { - key, - value, - original: alias, - }; - }, - - /** - * @method assignAlias - * @param option - * @param alias - * @return {Boolean} - */ - assignAlias(option, alias) { - let isValid = this.validateAlias(option, alias); - - if (isValid) { - this.optionsAliases[alias.key] = alias.value; - } - return isValid; - }, - - /** - Validates alias value - @method validateAlias - @param {Object} alias - @return {Boolean} - */ - validateAlias(option, alias) { - let key = alias.key; - let value = alias.value; - - if (!this.optionsAliases[key]) { - return true; - } else { - if (value[0] !== this.optionsAliases[key][0]) { - throw new SilentError(`The "${key}" alias is already in use by the "${this.optionsAliases[key][0]}" option ` + - `and cannot be used by the "${value[0]}" option. Please use a different alias.`); - - } else if (value[1] !== this.optionsAliases[key][1]) { - this.ui.writeLine(chalk.yellow(`The "${key}" alias cannot be overridden. Please use a different alias.`)); - // delete offending alias from options - let index = this.availableOptions.indexOf(option); - let aliasIndex = this.availableOptions[index].aliases.indexOf(alias.original); - if (this.availableOptions[index].aliases[aliasIndex]) { - delete this.availableOptions[index].aliases[aliasIndex]; - } - } - return false; - } - }, - - /** - Parses command arguments and processes - @method parseArgs - @param {Object} commandArgs - @return {Object|null} - */ - parseArgs(commandArgs, showErrors = true) { - let knownOpts = {}; // Parse options - let commandOptions = {}; - let parsedOptions; - - let assembleAndValidateOption = function(option) { - return this.assignOption(option, parsedOptions, commandOptions); - }; - - let validateParsed = function(key) { - // ignore 'argv', 'h', and 'help' - if (!commandOptions.hasOwnProperty(key) && key !== 'argv' && key !== 'h' && key !== 'help' && showErrors) { - this.ui.writeLine(chalk.yellow(`The option '--${key}' is not registered with the ${this.name} command. ` + - `Run \`ng ${this.name} --help\` for a list of supported options.`)); - } - if (typeof parsedOptions[key] !== 'object') { - commandOptions[camelize(key)] = parsedOptions[key]; - } - }; - - this.availableOptions.forEach(option => { - if (typeof option.type !== 'string') { - knownOpts[option.name] = option.type; - } else if (option.type === 'Path') { - knownOpts[option.name] = path; - } else { - knownOpts[option.name] = String; - } - }); - - parsedOptions = nopt(knownOpts, this.optionsAliases, commandArgs, 0); - - if (!this.availableOptions.every(assembleAndValidateOption.bind(this))) { - return null; - } - - _.keys(parsedOptions).map(validateParsed.bind(this)); - - return { - options: _.defaults(commandOptions, this.settings), - args: parsedOptions.argv.remain, - }; - }, - - /** - * @method run - * @param commandArgs - */ - run(commandArgs) { - throw new Error(`command must implement run${commandArgs.toString()}`); - }, - - _printCommand: printCommand, - - /** - Prints short help for the command. - Short help looks like this: - ng generate - Generates new code from blueprints - aliases: g - The default implementation is designed to cover all bases - but may be overridden if necessary. - @method printShortHelp - */ - printShortHelp() { - // ng command-name - let output; - if (this.isRoot) { - output = `Usage: ${this.name}`; - } else { - output = `ng ${this.name}`; - } - - output += EOL; - output += ` ${this.description}`; - output += EOL; - - return output; - }, - - /** - Prints basic help for the command. - Basic help looks like this: - ng generate - Generates new code from blueprints - aliases: g - --dry-run (Default: false) - --verbose (Default: false) - The default implementation is designed to cover all bases - but may be overridden if necessary. - @method printBasicHelp - */ - printBasicHelp() { - // ng command-name - let output; - if (this.isRoot) { - output = `Usage: ${this.name}`; - } else { - output = `ng ${this.name}`; - } - - output += this._printCommand(); - output += EOL; - - return output; - }, - - /** - Prints detailed help for the command. - The default implementation is no-op and should be overridden - for each command where further help text is required. - @method printDetailedHelp - */ - printDetailedHelp() {}, - - /** - * @method getJson - * @param {Object} options - * @return {Object} - */ - getJson(options) { - let json = {}; - this._printableProperties.forEach(key => (json[key] = this[key])); - - if (this.addAdditionalJsonForHelp) { - this.addAdditionalJsonForHelp(json, options); - } - - return json; - }, -}); - -/* - Validates options parsed by nopt -*/ -function isValidParsedOption(option, parsedOption) { - // option.name didn't parse - if (parsedOption === undefined) { - // no default - if (option.default === undefined) { - if (option.required) { - return false; - } - } - } - - return true; -} - -/* - Validates alias. Must be a string or single key object -*/ -function isValidAlias(alias, expectedType) { - let type = typeof alias; - let value, valueType; - if (type === 'string') { - return true; - } else if (type === 'object') { - - // no arrays, no multi-key objects - if (!Array.isArray(alias) && Object.keys(alias).length === 1) { - value = alias[Object.keys(alias)[0]]; - valueType = typeof value; - if (!Array.isArray(expectedType)) { - if (valueType === expectedType.name.toLowerCase()) { - return true; - } - - } else if (expectedType.indexOf(value) > -1) { - return true; - } - } - } - - return false; -} - -module.exports = Command; diff --git a/packages/@angular/cli/ember-cli/lib/models/installation-checker.js b/packages/@angular/cli/ember-cli/lib/models/installation-checker.js deleted file mode 100644 index 2cdb340b3c19..000000000000 --- a/packages/@angular/cli/ember-cli/lib/models/installation-checker.js +++ /dev/null @@ -1,75 +0,0 @@ -'use strict'; - -const fs = require('fs-extra'); -const path = require('path'); -const SilentError = require('silent-error'); - -class InstallationChecker { - constructor(options) { - this.project = options.project; - } - - /** - * Check if npm and bower installation directories are present, - * and raise an error message with instructions on how to proceed. - * - * If some of these package managers aren't being used in the project - * we just ignore them. Their usage is considered by checking the - * presence of your manifest files: package.json for npm and bower.json for bower. - * - * @method checkInstallations - */ - checkInstallations() { - let commands = []; - - if (this.usingNpm() && this.npmDependenciesNotPresent()) { - commands.push('`npm install`'); - } - if (this.usingBower() && this.bowerDependenciesNotPresent()) { - commands.push('`bower install`'); - } - if (commands.length) { - let commandText = commands.join(' and '); - throw new SilentError(`No dependencies installed. Run ${commandText} to install missing dependencies.`); - } - } - - hasBowerDeps() { - return hasDependencies(readJSON(path.join(this.project.root, 'bower.json'))); - } - - usingBower() { - return fs.existsSync(path.join(this.project.root, 'bower.json')) && this.hasBowerDeps(); - } - - bowerDependenciesNotPresent() { - return !fs.existsSync(this.project.bowerDirectory); - } - - hasNpmDeps() { - return hasDependencies(readJSON(path.join(this.project.root, 'package.json'))); - } - - usingNpm() { - return fs.existsSync(path.join(this.project.root, 'package.json')) && this.hasNpmDeps(); - } - - npmDependenciesNotPresent() { - return !fs.existsSync(this.project.nodeModulesPath); - } -} - -module.exports = InstallationChecker; - -function hasDependencies(pkg) { - return (pkg.dependencies && pkg.dependencies.length) || - (pkg.devDependencies && pkg.devDependencies.length); -} - -function readJSON(path) { - try { - return fs.readJsonSync(path); - } catch (e) { - throw new SilentError(`InstallationChecker: Unable to parse: ${path}`); - } -} diff --git a/packages/@angular/cli/ember-cli/lib/models/project.js b/packages/@angular/cli/ember-cli/lib/models/project.js deleted file mode 100644 index d50982ae0b0a..000000000000 --- a/packages/@angular/cli/ember-cli/lib/models/project.js +++ /dev/null @@ -1,384 +0,0 @@ -'use strict'; - -/** -@module ember-cli -*/ -const denodeify = require('denodeify'); -const path = require('path'); -const findUp = require('../../../utilities/find-up').findUp; -let resolve = denodeify(require('resolve')); -const fs = require('fs-extra'); -const _ = require('lodash'); -const nodeModulesPath = require('node-modules-path'); - -let processCwd = process.cwd(); -// ensure NULL_PROJECT is a singleton -let NULL_PROJECT; - -class Project { - /** - The Project model is tied to your package.json. It is instantiated - by giving {{#crossLink "Project/closestSync:method"}}{{/crossLink}} - the path to your project. - @class Project - @constructor - @param {String} root Root directory for the project - @param {Object} pkg Contents of package.json - @param {UI} ui - @param {CLI} cli - */ - constructor(root, pkg, ui, cli) { - this.root = root; - this.pkg = pkg; - this.ui = ui; - this.cli = cli; - this.addonPackages = {}; - this.addons = []; - this.liveReloadFilterPatterns = []; - this.setupNodeModulesPath(); - - /** - Set when the `Watcher.detectWatchman` helper method finishes running, - so that other areas of the system can be aware that watchman is being used. - For example, this information is used in the broccoli build pipeline to know - if we can watch additional directories (like bower_components) "cheaply". - Contains `enabled` and `version`. - @private - @property _watchmanInfo - @return {Object} - @default false - */ - this._watchmanInfo = { - enabled: false, - version: null, - canNestRoots: false, - }; - - let instrumentation = this._instrumentation = ensureInstrumentation(cli, ui); - if (instrumentation) { - instrumentation.project = this; - } - } - - hasDependencies() { - return !!this.nodeModulesPath; - } - - /** - Sets the path to the node_modules directory for this - project. - @private - @method setupNodeModulesPath - */ - setupNodeModulesPath() { - this.nodeModulesPath = nodeModulesPath(this.root); - } - - static nullProject(ui, cli) { - if (NULL_PROJECT) { return NULL_PROJECT; } - - NULL_PROJECT = new Project(processCwd, {}, ui, cli); - - NULL_PROJECT.isEmberCLIProject = function() { - return false; - }; - - NULL_PROJECT.name = function() { - return path.basename(process.cwd()); - }; - - return NULL_PROJECT; - } - - /** - Returns the name from package.json. - @private - @method name - @return {String} Package name - */ - name() { - const getPackageBaseName = require('../utilities/get-package-base-name'); - - return getPackageBaseName(this.pkg.name); - } - - /** - Returns whether or not this is an Ember CLI project. - This checks whether ember-cli is listed in devDependencies. - @private - @method isEmberCLIProject - @return {Boolean} Whether this is an Ember CLI project - */ - isEmberCLIProject() { - return 'angular-cli' in this.dependencies() - || '@angular/cli' in this.dependencies(); - } - - /** - Loads the configuration for this project and its addons. - @public - @method config - @param {String} env Environment name - @return {Object} Merged confiration object - */ - config(env) { - let initialConfig = {}; - - return this.addons.reduce((config, addon) => { - if (addon.config) { - _.merge(config, addon.config(env, config)); - } - - return config; - }, initialConfig); - } - - /** - Returns whether or not the given file name is present in this project. - @private - @method has - @param {String} file File name - @return {Boolean} Whether or not the file is present - */ - has(file) { - return fs.existsSync(path.join(this.root, file)) || fs.existsSync(path.join(this.root, `${file}.js`)); - } - - /** - Resolves the absolute path to a file. - @private - @method resolve - @param {String} file File to resolve - @return {String} Absolute path to file - */ - resolve(file) { - return resolve(file, { - basedir: this.root, - }); - } - - /** - Resolves the absolute path to a file synchronously - @private - @method resolveSync - @param {String} file File to resolve - @return {String} Absolute path to file - */ - resolveSync(file) { - return resolve.sync(file, { - basedir: this.root, - }); - } - - /** - Calls `require` on a given module from the context of the project. For - instance, an addon may want to require a class from the root project's - version of ember-cli. - @public - @method require - @param {String} file File path or module name - @return {Object} Imported module - */ - require(file) { - if (/^\.\//.test(file)) { // Starts with ./ - return require(path.join(this.root, file)); - } else if (file.slice(0, this.root.length) === this.root) { // Starts with this.root - return require(file); - } else { - return require(path.join(this.nodeModulesPath, file)); - } - } - - /** - Returns the dependencies from a package.json - @private - @method dependencies - @param {Object} [pkg=this.pkg] Package object - @param {Boolean} [excludeDevDeps=false] Whether or not development dependencies should be excluded - @return {Object} Dependencies - */ - dependencies(pkg, excludeDevDeps) { - pkg = pkg || this.pkg || {}; - - let devDependencies = pkg['devDependencies']; - if (excludeDevDeps) { - devDependencies = {}; - } - - return _.assign({}, devDependencies, pkg['dependencies']); - } - - /** - Reloads package.json - @private - @method reloadPkg - @return {Object} Package content - */ - reloadPkg() { - let pkgPath = path.join(this.root, 'package.json'); - - // We use readFileSync instead of require to avoid the require cache. - this.pkg = fs.readJsonSync(pkgPath); - - return this.pkg; - } - - /** - Returns a new project based on the first package.json that is found - in `pathName`. - @deprecated - @private - @static - @method closest - @param {String} pathName Path to your project - @return {Promise} Promise which resolves to a {Project} - */ - static closest(pathName, _ui, _cli) { - let ui = ensureUI(_ui); - - ui.writeDeprecateLine('`Project.closest` is a private method that will be removed, please use `Project.closestSync` instead.'); - - return closestPackageJSON(pathName).then(result => { - if (result.pkg && result.pkg.name === 'ember-cli') { - return Project.nullProject(_ui, _cli); - } - - return new Project(result.directory, result.pkg, ui, _cli); - }); - } - - /** - Returns a new project based on the first package.json that is found - in `pathName`. - @private - @static - @method closestSync - @param {String} pathName Path to your project - @param {UI} _ui The UI instance to provide to the created Project. - @return {Project} Project instance - */ - static closestSync(pathName, _ui, _cli) { - let ui = ensureUI(_ui); - - let directory = findupPath(pathName); - - let relative = path.relative(directory, pathName); - if (relative.indexOf('tmp') === 0) { - return Project.nullProject(_ui, _cli); - } - - let pkg = fs.readJsonSync(path.join(directory, 'package.json')); - - if (!isEmberCliProject(pkg)) { - return Project.nullProject(_ui, _cli); - } - - return new Project(directory, pkg, ui, _cli); - } - - /** - Returns a new project based on the first package.json that is found - in `pathName`, or the nullProject. - The nullProject signifies no-project, but abides by the null object pattern - @private - @static - @method projectOrnullProject - @param {UI} _ui The UI instance to provide to the created Project. - @return {Project} Project instance - */ - static projectOrnullProject(_ui, _cli) { - try { - return Project.closestSync(process.cwd(), _ui, _cli); - } catch (reason) { - if (reason instanceof Project.NotFoundError) { - return Project.nullProject(_ui, _cli); - } else { - throw reason; - } - } - } - - /** - Returns the project root based on the first package.json that is found - @static - @method getProjectRoot - @return {String} The project root directory - */ - static getProjectRoot() { - let packagePath = findUp(process.cwd(), 'package.json'); - if (!packagePath) { - return process.cwd(); - } - - let directory = path.dirname(packagePath); - const pkg = require(packagePath); - - if (pkg && pkg.name === 'ember-cli') { - return process.cwd(); - } - - return directory; - } -} - -class NotFoundError extends Error { - constructor(message) { - super(message); - this.name = 'NotFoundError'; - this.stack = (new Error()).stack; - } -} - -Project.NotFoundError = NotFoundError; - -function ensureInstrumentation(cli, ui) { - if (cli && cli.instrumentation) { - return cli.instrumentation; - } - - return null; -} - -function ensureUI(_ui) { - let ui = _ui; - - if (!ui) { - // TODO: one UI (lib/cli/index.js also has one for now...) - const UI = require('../ui'); - ui = new UI({ - inputStream: process.stdin, - outputStream: process.stdout, - ci: process.env.CI || (/^(dumb|emacs)$/).test(process.env.TERM), - writeLevel: (process.argv.indexOf('--silent') !== -1) ? 'ERROR' : undefined, - }); - } - - return ui; -} - -function closestPackageJSON(pathName) { - return Promise.resolve() - .then(() => findUp('package.json', pathName)) - .then(filePath => ({ - directory: path.dirname(filePath), - pkg: require(filePath) - })); -} - -function findupPath(pathName) { - try { - return path.dirname(findUp('package.json', pathName)); - } catch (reason) { - throw new NotFoundError(`No project found at or up from: \`${pathName}\``); - } -} - -function isEmberCliProject(pkg) { - return pkg && ( - (pkg.dependencies && Object.keys(pkg.dependencies).indexOf('@angular/cli') !== -1) || - (pkg.devDependencies && Object.keys(pkg.devDependencies).indexOf('@angular/cli') !== -1) - ); -} - -// Export -module.exports = Project; diff --git a/packages/@angular/cli/ember-cli/lib/models/task.js b/packages/@angular/cli/ember-cli/lib/models/task.js deleted file mode 100644 index bad95341a5ec..000000000000 --- a/packages/@angular/cli/ember-cli/lib/models/task.js +++ /dev/null @@ -1,22 +0,0 @@ -'use strict'; - -const CoreObject = require('core-object'); - -class Task extends CoreObject { - run(/*options*/) { - throw new Error('Task needs to have run() defined.'); - } - - /** - * Interrupt comamd with an exit code - * Called when the process is interrupted from outside, e.g. CTRL+C or `process.kill()` - * - * @private - * @method onInterrupt - */ - onInterrupt() { - process.exit(1); - } -} - -module.exports = Task; diff --git a/packages/@angular/cli/ember-cli/lib/ui/index.js b/packages/@angular/cli/ember-cli/lib/ui/index.js deleted file mode 100644 index 31f38d5a22fb..000000000000 --- a/packages/@angular/cli/ember-cli/lib/ui/index.js +++ /dev/null @@ -1,196 +0,0 @@ -'use strict'; - -var EOL = require('os').EOL; -var chalk = require('chalk'); -var writeError = require('./write-error'); - -var DEFAULT_WRITE_LEVEL = 'INFO'; - -// Note: You should use `ui.outputStream`, `ui.inputStream` and `ui.write()` -// instead of `process.stdout` and `console.log`. -// Thus the pleasant progress indicator automatically gets -// interrupted and doesn't mess up the output! -> Convenience :P - -module.exports = UI; - -/* - @constructor - - The UI provides the CLI with a unified mechanism for providing output and - requesting input from the user. This becomes useful when wanting to adjust - logLevels, or mock input/output for tests. - - new UI({ - inputStream: process.stdin, - outputStream: process.stdout, - writeLevel: 'DEBUG' | 'INFO' | 'WARNING' | 'ERROR', - ci: true | false - }); - -**/ - -function UI(options) { - // Output stream - this.outputStream = options.outputStream; - this.inputStream = options.inputStream; - this.errorStream = options.errorStream; - - this.errorLog = options.errorLog || []; - this.writeLevel = options.writeLevel || DEFAULT_WRITE_LEVEL; - this.ci = !!options.ci; -} - -/** - Unified mechanism to write a string to the console. - Optionally include a writeLevel, this is used to decide if the specific - logging mechanism should or should not be printed. - - @method write - @param {String} data - @param {Number} writeLevel -*/ -UI.prototype.write = function(data, writeLevel) { - if (writeLevel === 'ERROR') { - this.errorStream.write(data); - } else if (this.writeLevelVisible(writeLevel)) { - this.outputStream.write(data); - } -}; - -/** - Unified mechanism to write a string and new line to the console. - Optionally include a writeLevel, this is used to decide if the specific - logging mechanism should or should not be printed. - @method writeLine - @param {String} data - @param {Number} writeLevel -*/ -UI.prototype.writeLine = function(data, writeLevel) { - this.write(data + EOL, writeLevel); -}; - -/** - Helper method to write a string with the DEBUG writeLevel and gray chalk - @method writeDebugLine - @param {String} data -*/ -UI.prototype.writeDebugLine = function(data) { - this.writeLine(chalk.gray(data), 'DEBUG'); -}; - -/** - Helper method to write a string with the INFO writeLevel and cyan chalk - @method writeInfoLine - @param {String} data -*/ -UI.prototype.writeInfoLine = function(data) { - this.writeLine(chalk.cyan(data), 'INFO'); -}; - -/** - Helper method to write a string with the WARNING writeLevel and yellow chalk. - Optionally include a test. If falsy, the warning will be printed. By default, warnings - will be prepended with WARNING text when printed. - @method writeWarnLine - @param {String} data - @param {Boolean} test - @param {Boolean} prepend -*/ -UI.prototype.writeWarnLine = function(data, test, prepend) { - if (test) { return; } - - data = this.prependLine('WARNING', data, prepend); - this.writeLine(chalk.yellow(data), 'WARNING', test); -}; - -/** - Helper method to write a string with the WARNING writeLevel and yellow chalk. - Optionally include a test. If falsy, the deprecation will be printed. By default deprecations - will be prepended with DEPRECATION text when printed. - @method writeDeprecateLine - @param {String} data - @param {Boolean} test - @param {Boolean} prepend -*/ -UI.prototype.writeDeprecateLine = function(data, test, prepend) { - data = this.prependLine('DEPRECATION', data, prepend); - this.writeWarnLine(data, test, false); -}; - -/** - Utility method to prepend a line with a flag-like string (i.e., WARNING). - @method prependLine - @param {String} prependData - @param {String} data - @param {Boolean} prepend -*/ -UI.prototype.prependLine = function(prependData, data, prepend) { - if (typeof prepend === 'undefined' || prepend) { - data = prependData + ': ' + data; - } - - return data; -}; - -/** - Unified mechanism to an Error to the console. - This will occure at a writeLevel of ERROR - - @method writeError - @param {Error} error -*/ -UI.prototype.writeError = function(error) { - writeError(this, error); -}; - -/** - Sets the write level for the UI. Valid write levels are 'DEBUG', 'INFO', - 'WARNING', and 'ERROR'. - - @method setWriteLevel - @param {String} level -*/ -UI.prototype.setWriteLevel = function(level) { - if (Object.keys(this.WRITE_LEVELS).indexOf(level) === -1) { - throw new Error('Unknown write level. Valid values are \'DEBUG\', \'INFO\', \'WARNING\', and \'ERROR\'.'); - } - - this.writeLevel = level; -}; - -UI.prototype.startProgress = function(message/*, stepString*/) { - if (this.writeLevelVisible('INFO')) { - this.writeLine(message); - } -}; - -UI.prototype.stopProgress = function() { - -}; - -/** - @property WRITE_LEVELS - @private - @type Object -*/ -UI.prototype.WRITE_LEVELS = { - 'DEBUG': 1, - 'INFO': 2, - 'WARNING': 3, - 'ERROR': 4 -}; - -/** - Whether or not the specified write level should be printed by this UI. - - @method writeLevelVisible - @private - @param {String} writeLevel - @return {Boolean} -*/ -UI.prototype.writeLevelVisible = function(writeLevel) { - var levels = this.WRITE_LEVELS; - writeLevel = writeLevel || DEFAULT_WRITE_LEVEL; - - return levels[writeLevel] >= levels[this.writeLevel]; -}; diff --git a/packages/@angular/cli/ember-cli/lib/ui/write-error.js b/packages/@angular/cli/ember-cli/lib/ui/write-error.js deleted file mode 100644 index 5114f9da409e..000000000000 --- a/packages/@angular/cli/ember-cli/lib/ui/write-error.js +++ /dev/null @@ -1,25 +0,0 @@ -'use strict'; -var chalk = require('chalk'); - -module.exports = function writeError(ui, error) { - if (!error) { return; } - - // Uglify errors have a filename instead - var fileName = error.file || error.filename; - if (fileName) { - if (error.line) { - fileName += error.col ? ' (' + error.line + ':' + error.col + ')' : ' (' + error.line + ')'; - } - ui.writeLine(chalk.red('File: ' + fileName), 'ERROR'); - } - - if (error.message) { - ui.writeLine(chalk.red(error.message), 'ERROR'); - } else { - ui.writeLine(chalk.red(error), 'ERROR'); - } - - if (error.stack) { - ui.writeLine(error.stack, 'ERROR'); - } -}; diff --git a/packages/@angular/cli/ember-cli/lib/utilities/get-option-args.js b/packages/@angular/cli/ember-cli/lib/utilities/get-option-args.js deleted file mode 100644 index d1cef9fd47fa..000000000000 --- a/packages/@angular/cli/ember-cli/lib/utilities/get-option-args.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -module.exports = function(option, commandArgs) { - let results = [], value, i; - let optionIndex = commandArgs.indexOf(option); - if (optionIndex === -1) { return results; } - - for (i = optionIndex + 1; i < commandArgs.length; i++) { - value = commandArgs[i]; - if (/^\-+/.test(value)) { break; } - results.push(value); - } - - return results; -}; diff --git a/packages/@angular/cli/ember-cli/lib/utilities/get-package-base-name.js b/packages/@angular/cli/ember-cli/lib/utilities/get-package-base-name.js deleted file mode 100644 index a774ec8a93fc..000000000000 --- a/packages/@angular/cli/ember-cli/lib/utilities/get-package-base-name.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict'; - -module.exports = function(name) { - if (!name) { - return null; - } - - const packageParts = name.split('/'); - return packageParts[(packageParts.length - 1)]; -}; diff --git a/packages/@angular/cli/ember-cli/lib/utilities/print-command.js b/packages/@angular/cli/ember-cli/lib/utilities/print-command.js deleted file mode 100644 index e50df8bc3478..000000000000 --- a/packages/@angular/cli/ember-cli/lib/utilities/print-command.js +++ /dev/null @@ -1,92 +0,0 @@ -'use strict'; - -const chalk = require('chalk'); -const EOL = require('os').EOL; - -module.exports = function(initialMargin, shouldDescriptionBeGrey) { - initialMargin = initialMargin || ''; - - let output = ''; - - let options = this.anonymousOptions; - - // ... - if (options.length) { - output += ` ${chalk.yellow(options.map(option => { - // blueprints we insert brackets, commands already have them - if (option.indexOf('<') === 0) { - return option; - } else { - return `<${option}>`; - } - }).join(' '))}`; - } - - options = this.availableOptions.filter(option => !option.hidden); - - // - if (options.length) { - output += ` ${chalk.cyan('')}`; - } - - // Description - let description = this.description; - if (description) { - if (shouldDescriptionBeGrey) { - description = chalk.grey(description); - } - output += `${EOL + initialMargin} ${description}`; - } - - // aliases: a b c - if (this.aliases && this.aliases.length) { - output += `${EOL + initialMargin} ${chalk.grey(`aliases: ${this.aliases.filter(a => a).join(', ')}`)}`; - } - - // --available-option (Required) (Default: value) - // ... - options.forEach(option => { - output += `${EOL + initialMargin} ${chalk.cyan(`--${option.name}`)}`; - - if (option.values) { - output += chalk.cyan(`=${option.values.join('|')}`); - } - - if (option.type) { - let types = Array.isArray(option.type) ? - option.type.map(formatType).join(', ') : - formatType(option.type); - - output += ` ${chalk.cyan(`(${types})`)}`; - } - - if (option.required) { - output += ` ${chalk.cyan('(Required)')}`; - } - - if (option.default !== undefined) { - output += ` ${chalk.cyan(`(Default: ${option.default})`)}`; - } - - if (option.description) { - output += ` ${option.description}`; - } - - if (option.aliases && option.aliases.length) { - output += `${EOL + initialMargin} ${chalk.grey(`aliases: ${option.aliases.map(a => { - if (typeof a === 'string') { - return (a.length > 4 ? '--' : '-') + a + (option.type === Boolean ? '' : ' '); - } else { - let key = Object.keys(a)[0]; - return `${(key.length > 4 ? '--' : '-') + key} (--${option.name}=${a[key]})`; - } - }).join(', ')}`)}`; - } - }); - - return output; -}; - -function formatType(type) { - return typeof type === 'string' ? type : type.name; -} diff --git a/packages/@angular/cli/lib/base-href-webpack/base-href-webpack-plugin.spec.ts b/packages/@angular/cli/lib/base-href-webpack/base-href-webpack-plugin.spec.ts deleted file mode 100644 index 1f75d44e43bf..000000000000 --- a/packages/@angular/cli/lib/base-href-webpack/base-href-webpack-plugin.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import {oneLineTrim} from 'common-tags'; -import {BaseHrefWebpackPlugin} from './base-href-webpack-plugin'; - - -function mockCompiler(indexHtml: string, callback: Function) { - return { - plugin: function (_event: any, compilerCallback: Function) { - const compilation = { - plugin: function (_hook: any, compilationCallback: Function) { - const htmlPluginData = { - html: indexHtml - }; - compilationCallback(htmlPluginData, callback); - } - }; - compilerCallback(compilation); - } - }; -} - -describe('base href webpack plugin', () => { - const html = oneLineTrim` - - - - - `; - - it('should do nothing when baseHref is null', () => { - const plugin = new BaseHrefWebpackPlugin({ baseHref: null }); - - const compiler = mockCompiler(html, (_x: any, htmlPluginData: any) => { - expect(htmlPluginData.html).toEqual(''); - }); - plugin.apply(compiler); - }); - - it('should insert base tag when not exist', function () { - const plugin = new BaseHrefWebpackPlugin({ baseHref: '/' }); - const compiler = mockCompiler(html, (_x: any, htmlPluginData: any) => { - expect(htmlPluginData.html).toEqual(oneLineTrim` - - - - - `); - }); - - plugin.apply(compiler); - }); - - it('should replace href attribute when base tag already exists', function () { - const plugin = new BaseHrefWebpackPlugin({ baseHref: '/myUrl/' }); - - const compiler = mockCompiler(oneLineTrim` - - - `, (_x: any, htmlPluginData: any) => { - expect(htmlPluginData.html).toEqual(oneLineTrim` - - - `); - }); - plugin.apply(compiler); - }); - - it('should replace href attribute when baseHref is empty', function () { - const plugin = new BaseHrefWebpackPlugin({ baseHref: '' }); - - const compiler = mockCompiler(oneLineTrim` - - - `, (_x: any, htmlPluginData: any) => { - expect(htmlPluginData.html).toEqual(oneLineTrim` - - - `); - }); - plugin.apply(compiler); - }); -}); diff --git a/packages/@angular/cli/lib/base-href-webpack/base-href-webpack-plugin.ts b/packages/@angular/cli/lib/base-href-webpack/base-href-webpack-plugin.ts deleted file mode 100644 index c7a844926a81..000000000000 --- a/packages/@angular/cli/lib/base-href-webpack/base-href-webpack-plugin.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface BaseHrefWebpackPluginOptions { - baseHref: string; -} - -export class BaseHrefWebpackPlugin { - constructor(public readonly options: BaseHrefWebpackPluginOptions) { } - - apply(compiler: any): void { - // Ignore if baseHref is not passed - if (!this.options.baseHref && this.options.baseHref !== '') { - return; - } - - compiler.plugin('compilation', (compilation: any) => { - compilation.plugin( - 'html-webpack-plugin-before-html-processing', - (htmlPluginData: any, callback: Function) => { - // Check if base tag already exists - const baseTagRegex = //i; - const baseTagMatches = htmlPluginData.html.match(baseTagRegex); - if (!baseTagMatches) { - // Insert it in top of the head if not exist - htmlPluginData.html = htmlPluginData.html.replace( - //i, '$&' + `` - ); - } else { - // Replace only href attribute if exists - const modifiedBaseTag = baseTagMatches[0].replace( - /href="\S+"/i, `href="${this.options.baseHref}"` - ); - htmlPluginData.html = htmlPluginData.html.replace(baseTagRegex, modifiedBaseTag); - } - - callback(null, htmlPluginData); - } - ); - }); - } -} diff --git a/packages/@angular/cli/lib/base-href-webpack/index.ts b/packages/@angular/cli/lib/base-href-webpack/index.ts deleted file mode 100644 index 3140fa868c4e..000000000000 --- a/packages/@angular/cli/lib/base-href-webpack/index.ts +++ /dev/null @@ -1,2 +0,0 @@ - -export * from './base-href-webpack-plugin'; diff --git a/packages/@angular/cli/lib/cli/index.ts b/packages/@angular/cli/lib/cli/index.ts deleted file mode 100644 index e47fe33117c9..000000000000 --- a/packages/@angular/cli/lib/cli/index.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Prevent the dependency validation from tripping because we don't import these. We need -// it as a peer dependency of @angular/core. -// require('zone.js') - -import * as path from 'path'; - -const cli = require('../../ember-cli/lib/cli'); -const UI = require('../../ember-cli/lib/ui'); - - -function loadCommands() { - return { - 'build': require('../../commands/build').default, - 'serve': require('../../commands/serve').default, - 'eject': require('../../commands/eject').default, - 'new': require('../../commands/new').default, - 'generate': require('../../commands/generate').default, - 'destroy': require('../../commands/destroy').default, - 'test': require('../../commands/test').default, - 'e2e': require('../../commands/e2e').default, - 'help': require('../../commands/help').default, - 'lint': require('../../commands/lint').default, - 'version': require('../../commands/version').default, - 'completion': require('../../commands/completion').default, - 'doc': require('../../commands/doc').default, - 'xi18n': require('../../commands/xi18n').default, - - // Easter eggs. - 'make-this-awesome': require('../../commands/easter-egg').default, - - // Configuration. - 'set': require('../../commands/set').default, - 'get': require('../../commands/get').default - }; -} - -export default function(options: any) { - - // patch UI to not print Ember-CLI warnings (which don't apply to Angular CLI) - UI.prototype.writeWarnLine = function () { }; - - options.cli = { - name: 'ng', - root: path.join(__dirname, '..', '..'), - npmPackage: '@angular/cli' - }; - - options.commands = loadCommands(); - - // ensure the environemnt variable for dynamic paths - process.env.PWD = path.normalize(process.env.PWD || process.cwd()); - process.env.CLI_ROOT = process.env.CLI_ROOT || path.resolve(__dirname, '..', '..'); - - return cli(options); -} diff --git a/packages/@angular/cli/lib/config/.gitignore b/packages/@angular/cli/lib/config/.gitignore deleted file mode 100644 index 879ebeae0a5f..000000000000 --- a/packages/@angular/cli/lib/config/.gitignore +++ /dev/null @@ -1 +0,0 @@ -schema.d.ts \ No newline at end of file diff --git a/packages/@angular/cli/lib/config/schema.json b/packages/@angular/cli/lib/config/schema.json deleted file mode 100644 index 8520dcc1c9b9..000000000000 --- a/packages/@angular/cli/lib/config/schema.json +++ /dev/null @@ -1,609 +0,0 @@ -{ - "$schema": "http://json-schema.org/schema", - "id": "https://github.com/angular/angular-cli/blob/master/packages/@angular/cli/lib/config/schema.json#CliConfig", - "title": "Angular CLI Config Schema", - "type": "object", - "properties": { - "$schema": { - "type": "string" - }, - "project": { - "description": "The global configuration of the project.", - "type": "object", - "properties": { - "name": { - "description": "The name of the project.", - "type": "string" - }, - "ejected": { - "description": "Whether or not this project was ejected.", - "type": "boolean", - "default": false - } - }, - "additionalProperties": false - }, - "apps": { - "description": "Properties of the different applications in this project.", - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Name of the app." - }, - "appRoot": { - "type": "string", - "description": "Directory where app files are placed.", - "default": "app" - }, - "root": { - "type": "string", - "description": "The root directory of the app." - }, - "outDir": { - "type": "string", - "default": "dist/", - "description": "The output directory for build results." - }, - "assets": { - "type": "array", - "description": "List of application assets.", - "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "glob": { - "type": "string", - "default": "", - "description": "The pattern to match." - }, - "input": { - "type": "string", - "default": "", - "description": "The dir to search within." - }, - "output": { - "type": "string", - "default": "", - "description": "The output path (relative to the outDir)." - }, - "allowOutsideOutDir": { - "type": "boolean", - "description": "Allow assets to be copied outside the outDir.", - "default": false - } - }, - "additionalProperties": false - } - ] - }, - "default": [] - }, - "deployUrl": { - "type": "string", - "description": "URL where files will be deployed." - }, - "baseHref": { - "type": "string", - "description": "Base url for the application being built." - }, - "platform": { - "type": "string", - "enum": ["browser", "server"], - "default": "browser", - "description": "The runtime platform of the app." - }, - "index": { - "type": "string", - "default": "index.html", - "description": "The name of the start HTML file." - }, - "main": { - "type": "string", - "description": "The name of the main entry-point file." - }, - "polyfills": { - "type": "string", - "description": "The name of the polyfills file." - }, - "test": { - "type": "string", - "description": "The name of the test entry-point file." - }, - "tsconfig": { - "type": "string", - "default": "tsconfig.app.json", - "description": "The name of the TypeScript configuration file." - }, - "testTsconfig": { - "type": "string", - "description": "The name of the TypeScript configuration file for unit tests." - }, - "prefix": { - "type": "string", - "description": "The prefix to apply to generated selectors." - }, - "serviceWorker": { - "description": "Experimental support for a service worker from @angular/service-worker.", - "type": "boolean", - "default": false - }, - "styles": { - "description": "Global styles to be included in the build.", - "type": "array", - "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "input": { - "type": "string" - } - }, - "additionalProperties": true - } - ] - }, - "additionalProperties": false - }, - "stylePreprocessorOptions": { - "description": "Options to pass to style preprocessors", - "type": "object", - "properties": { - "includePaths": { - "description": "Paths to include. Paths will be resolved to project root.", - "type": "array", - "items": { - "type": "string" - }, - "default": [] - } - }, - "additionalProperties": false - }, - "scripts": { - "description": "Global scripts to be included in the build.", - "type": "array", - "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "input": { - "type": "string" - } - }, - "additionalProperties": true, - "required": [ - "input" - ] - } - ] - }, - "additionalProperties": false - }, - "environmentSource":{ - "description": "Source file for environment config.", - "type": "string" - }, - "environments": { - "description": "Name and corresponding file for environment config.", - "type": "object", - "additionalProperties": true - } - }, - "additionalProperties": false - }, - "additionalProperties": false - }, - "e2e": { - "type": "object", - "description": "Configuration for end-to-end tests.", - "properties": { - "protractor": { - "type": "object", - "properties": { - "config": { - "description": "Path to the config file.", - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "lint": { - "description": "Properties to be passed to TSLint.", - "type": "array", - "items": { - "type": "object", - "properties": { - "files": { - "description": "File glob(s) to lint.", - "oneOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "default": [] - }, - "project": { - "description": "Location of the tsconfig.json project file. Will also use as files to lint if 'files' property not present.", - "type": "string" - }, - "tslintConfig": { - "description": "Location of the tslint.json configuration.", - "type": "string" - }, - "exclude": { - "description": "File glob(s) to ignore.", - "oneOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "default": [] - } - }, - "required": [ - "project" - ], - "additionalProperties": false - } - }, - "test": { - "description": "Configuration for unit tests.", - "type": "object", - "properties": { - "karma": { - "type": "object", - "properties": { - "config": { - "description": "Path to the karma config file.", - "type": "string" - } - }, - "additionalProperties": false - }, - "codeCoverage": { - "type": "object", - "properties": { - "exclude": { - "description": "Globs to exclude from code coverage.", - "type": "array", - "items": { - "type": "string" - }, - "default": [] - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "defaults": { - "description": "Specify the default values for generating.", - "type": "object", - "properties": { - "styleExt": { - "description": "The file extension to be used for style files.", - "type": "string" - }, - "poll": { - "description": "How often to check for file updates.", - "type": "number" - }, - "lintFix": { - "description": "Use lint to fix files after generation", - "type": "boolean", - "default": false - }, - "class": { - "description": "Options for generating a class.", - "type": "object", - "properties": { - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": false - } - } - }, - "component": { - "description": "Options for generating a component.", - "type": "object", - "properties": { - "flat": { - "description": "Flag to indicate if a dir is created.", - "type": "boolean", - "default": false - }, - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": true - }, - "inlineStyle": { - "description": "Specifies if the style will be in the ts file.", - "type": "boolean", - "default": false - }, - "inlineTemplate": { - "description": "Specifies if the template will be in the ts file.", - "type": "boolean", - "default": false - }, - "viewEncapsulation": { - "description": "Specifies the view encapsulation strategy.", - "enum": ["Emulated", "Native", "None"], - "type": "string" - }, - "changeDetection": { - "description": "Specifies the change detection strategy.", - "enum": ["Default", "OnPush"], - "type": "string" - } - } - }, - "directive": { - "description": "Options for generating a directive.", - "type": "object", - "properties": { - "flat": { - "description": "Flag to indicate if a dir is created.", - "type": "boolean", - "default": true - }, - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": true - } - } - }, - "guard": { - "description": "Options for generating a guard.", - "type": "object", - "properties": { - "flat": { - "description": "Flag to indicate if a dir is created.", - "type": "boolean", - "default": true - }, - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": true - } - } - }, - "interface": { - "description": "Options for generating an interface.", - "type": "object", - "properties": { - "prefix": { - "description": "Prefix to apply to interface names. (i.e. I)", - "type": "string", - "default": "" - } - } - }, - "module": { - "description": "Options for generating a module.", - "type": "object", - "properties": { - "flat": { - "description": "Flag to indicate if a dir is created.", - "type": "boolean", - "default": false - }, - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": false - } - } - }, - "pipe": { - "description": "Options for generating a pipe.", - "type": "object", - "properties": { - "flat": { - "description": "Flag to indicate if a dir is created.", - "type": "boolean", - "default": true - }, - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": true - } - } - }, - "service": { - "description": "Options for generating a service.", - "type": "object", - "properties": { - "flat": { - "description": "Flag to indicate if a dir is created.", - "type": "boolean", - "default": true - }, - "spec": { - "description": "Specifies if a spec file is generated.", - "type": "boolean", - "default": true - } - } - }, - "build": { - "description": "Properties to be passed to the build command.", - "type": "object", - "properties": { - "sourcemaps": { - "description": "Output sourcemaps.", - "type": "boolean" - }, - "baseHref": { - "description": "Base url for the application being built.", - "type": "string" - }, - "progress": { - "description": "The ssl key used by the server.", - "type": "boolean", - "default": true - }, - "poll": { - "description": "Enable and define the file watching poll time period (milliseconds).", - "type": "number" - }, - "deleteOutputPath": { - "description": "Delete output path before build.", - "type": "boolean", - "default": true - }, - "preserveSymlinks": { - "description": "Do not use the real path when resolving modules.", - "type": "boolean", - "default": false - }, - "showCircularDependencies": { - "description": "Show circular dependency warnings on builds.", - "type": "boolean", - "default": true - }, - "commonChunk": { - "description": "Use a separate bundle containing code used across multiple bundles.", - "type": "boolean", - "default": true - }, - "namedChunks": { - "description": "Use file name for lazy loaded chunks.", - "type": "boolean" - } - } - }, - "serve": { - "description": "Properties to be passed to the serve command.", - "type": "object", - "properties": { - "port": { - "description": "The port the application will be served on.", - "type": "number", - "default": 4200 - }, - "host": { - "description": "The host the application will be served on.", - "type": "string", - "default": "localhost" - - }, - "ssl": { - "description": "Enables ssl for the application.", - "type": "boolean", - "default": false - - }, - "sslKey": { - "description": "The ssl key used by the server.", - "type": "string", - "default": "ssl/server.key" - - }, - "sslCert": { - "description": "The ssl certificate used by the server.", - "type": "string", - "default": "ssl/server.crt" - }, - "proxyConfig": { - "description": "Proxy configuration file.", - "type": "string" - } - } - }, - "schematics": { - "description": "Properties about schematics.", - "type": "object", - "properties": { - "collection": { - "description": "The schematics collection to use.", - "type": "string", - "default": "@schematics/angular" - }, - "newApp": { - "description": "The new app schematic.", - "type": "string", - "default": "application" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "packageManager": { - "description": "Specify which package manager tool to use.", - "enum": [ "npm", "cnpm", "yarn", "default" ], - "default": "default", - "type": "string" - }, - "warnings": { - "description": "Allow people to disable console warnings.", - "type": "object", - "properties": { - "hmrWarning": { - "description": "Show a warning when the user enabled the --hmr option.", - "type": "boolean", - "default": true - }, - "nodeDeprecation": { - "description": "Show a warning when the node version is incompatible.", - "type": "boolean", - "default": true - }, - "packageDeprecation": { - "description": "Show a warning when the user installed angular-cli.", - "type": "boolean", - "default": true - }, - "versionMismatch": { - "description": "Show a warning when the global version is newer than the local one.", - "type": "boolean", - "default": true - }, - "typescriptMismatch": { - "description": "Show a warning when the TypeScript version is incompatible", - "type": "boolean", - "default": true - } - } - } - }, - "additionalProperties": false -} diff --git a/packages/@angular/cli/models/build-options.ts b/packages/@angular/cli/models/build-options.ts deleted file mode 100644 index 13f7c23324ed..000000000000 --- a/packages/@angular/cli/models/build-options.ts +++ /dev/null @@ -1,35 +0,0 @@ -export interface BuildOptions { - target?: string; - environment?: string; - outputPath?: string; - aot?: boolean; - sourcemaps?: boolean; - evalSourcemaps?: boolean; - vendorChunk?: boolean; - commonChunk?: boolean; - baseHref?: string; - deployUrl?: string; - verbose?: boolean; - progress?: boolean; - i18nFile?: string; - i18nFormat?: string; - i18nOutFile?: string; - i18nOutFormat?: string; - locale?: string; - missingTranslation?: string; - extractCss?: boolean; - bundleDependencies?: 'none' | 'all'; - watch?: boolean; - outputHashing?: string; - poll?: number; - app?: string; - deleteOutputPath?: boolean; - preserveSymlinks?: boolean; - extractLicenses?: boolean; - showCircularDependencies?: boolean; - buildOptimizer?: boolean; - namedChunks?: boolean; - subresourceIntegrity?: boolean; - forceTsCommonjs?: boolean; - serviceWorker?: boolean; -} diff --git a/packages/@angular/cli/models/config.ts b/packages/@angular/cli/models/config.ts deleted file mode 100644 index 21be3518b8ac..000000000000 --- a/packages/@angular/cli/models/config.ts +++ /dev/null @@ -1,121 +0,0 @@ -import {CliConfig as CliConfigBase} from './config/config'; -import {CliConfig as ConfigInterface} from '../lib/config/schema'; -import { oneLine } from 'common-tags'; -import chalk from 'chalk'; -import * as fs from 'fs'; -import * as path from 'path'; -import { homedir } from 'os'; - -import {findUp} from '../utilities/find-up'; - - -export const CLI_CONFIG_FILE_NAME = '.angular-cli.json'; -const CLI_CONFIG_FILE_NAME_ALT = 'angular-cli.json'; - - -const configCacheMap = new Map>(); - - -export class CliConfig extends CliConfigBase { - static configFilePath(projectPath?: string): string { - const configNames = [CLI_CONFIG_FILE_NAME, CLI_CONFIG_FILE_NAME_ALT]; - // Find the configuration, either where specified, in the Angular CLI project - // (if it's in node_modules) or from the current process. - return (projectPath && findUp(configNames, projectPath)) - || findUp(configNames, process.cwd()) - || findUp(configNames, __dirname); - } - - static getValue(jsonPath: string): any { - let value; - - const projectConfig = CliConfig.fromProject(); - if (projectConfig) { - value = projectConfig.get(jsonPath); - } else { - const globalConfig = CliConfig.fromGlobal(); - if (globalConfig) { - value = globalConfig.get(jsonPath); - } - } - - return value; - } - - static globalConfigFilePath(): string { - const globalConfigPath = path.join(homedir(), CLI_CONFIG_FILE_NAME); - if (fs.existsSync(globalConfigPath)) { - return globalConfigPath; - } - - const altGlobalConfigPath = path.join(homedir(), CLI_CONFIG_FILE_NAME_ALT); - if (fs.existsSync(altGlobalConfigPath)) { - return altGlobalConfigPath; - } - - return globalConfigPath; - } - - static fromGlobal(): CliConfig { - const globalConfigPath = this.globalConfigFilePath(); - - if (configCacheMap.has(globalConfigPath)) { - return configCacheMap.get(globalConfigPath); - } - - const cliConfig = CliConfigBase.fromConfigPath(globalConfigPath); - - CliConfig.addAliases(cliConfig); - configCacheMap.set(globalConfigPath, cliConfig); - return cliConfig; - } - - static fromProject(projectPath?: string): CliConfig { - const configPath = this.configFilePath(projectPath); - - if (!configPath || - (configPath === this.globalConfigFilePath() && process.cwd() !== path.dirname(configPath))) { - return null; - } - if (configCacheMap.has(configPath)) { - return configCacheMap.get(configPath); - } - - const globalConfigPath = CliConfig.globalConfigFilePath(); - const cliConfig = CliConfigBase.fromConfigPath(configPath, [globalConfigPath]); - - CliConfig.addAliases(cliConfig); - configCacheMap.set(configPath, cliConfig); - return cliConfig as CliConfig; - } - - static addAliases(cliConfig: CliConfigBase) { - - // Aliases with deprecation messages. - const aliases = [ - cliConfig.alias('apps.0.root', 'defaults.sourceDir'), - cliConfig.alias('apps.0.prefix', 'defaults.prefix') - ]; - - // If any of them returned true, output a deprecation warning. - if (aliases.some(x => x)) { - console.error(chalk.yellow(oneLine` - The "defaults.prefix" and "defaults.sourceDir" properties of .angular-cli.json - are deprecated in favor of "apps[0].root" and "apps[0].prefix".\n - Please update in order to avoid errors in future versions of Angular CLI. - `)); - } - - // Additional aliases which do not emit any messages. - cliConfig.alias('defaults.interface.prefix', 'defaults.inline.prefixInterfaces'); - cliConfig.alias('defaults.component.inlineStyle', 'defaults.inline.style'); - cliConfig.alias('defaults.component.inlineTemplate', 'defaults.inline.template'); - cliConfig.alias('defaults.component.spec', 'defaults.spec.component'); - cliConfig.alias('defaults.class.spec', 'defaults.spec.class'); - cliConfig.alias('defaults.component.directive', 'defaults.spec.directive'); - cliConfig.alias('defaults.component.module', 'defaults.spec.module'); - cliConfig.alias('defaults.component.pipe', 'defaults.spec.pipe'); - cliConfig.alias('defaults.component.service', 'defaults.spec.service'); - cliConfig.alias('defaults.build.poll', 'defaults.poll'); - } -} diff --git a/packages/@angular/cli/models/config/config.spec.ts b/packages/@angular/cli/models/config/config.spec.ts deleted file mode 100644 index cf4a95862102..000000000000 --- a/packages/@angular/cli/models/config/config.spec.ts +++ /dev/null @@ -1,109 +0,0 @@ -import {CliConfig} from './config'; -import * as fs from 'fs'; -import * as path from 'path'; -import {CliConfig as ConfigInterface} from './spec-schema'; - - -describe('Config', () => { - let schema = JSON.parse(fs.readFileSync(path.join(__dirname, 'spec-schema.json'), 'utf-8')); - - it('works', () => { - const cliConfig = new CliConfig(null, schema, { - requiredKey: 1, - stringKey: 'stringValue' - }); - const config = cliConfig.config; - - expect(config.requiredKey).toEqual(1); - expect(config.stringKey).toEqual('stringValue'); - expect(config.stringKeyDefault).toEqual('defaultValue'); - expect(config.booleanKey).toEqual(undefined); - - expect(config.arrayKey1).toEqual(undefined); - expect(() => config.arrayKey1[0]).toThrow(); - - expect(config.numberKey).toEqual(undefined); - config.numberKey = 33; - expect(config.numberKey).toEqual(33); - }); - - describe('Get', () => { - it('works', () => { - const config = new CliConfig(null, schema, { - requiredKey: 1, - stringKey: 'stringValue' - }); - - expect(JSON.parse(JSON.stringify(config.get()))).toEqual({ - requiredKey: 1, - stringKeyDefault: 'defaultValue', - stringKey: 'stringValue' - }); - expect(config.get('requiredKey')).toEqual(1); - expect(config.get('stringKey')).toEqual('stringValue'); - expect(config.get('booleanKey')).toEqual(undefined); - }); - - it('will never throw', () => { - const config = new CliConfig(null, schema, { - requiredKey: 1 - }); - - expect(config.get('arrayKey1')).toEqual(undefined); - expect(config.get('arrayKey2[0]')).toEqual(undefined); - expect(config.get('arrayKey2[0].stringKey')).toEqual(undefined); - expect(config.get('arrayKey2[0].stringKey.a.b.c.d')).toEqual(undefined); - }); - }); - - it('handles fallback values', () => { - const cliConfig = new CliConfig(null, schema, - { requiredKey: 1 }, - [ - { requiredKey: 1, stringKey: 'stringValue' }, - { requiredKey: 1, numberKey: 1 } - ] - ); - - // Check on string. - expect(cliConfig.isDefined('stringKey')).toEqual(false); - expect(cliConfig.config.stringKey).toEqual('stringValue'); - - cliConfig.config.stringKey = 'stringValue2'; - expect(cliConfig.isDefined('stringKey')).toEqual(true); - expect(cliConfig.config.stringKey).toEqual('stringValue2'); - - cliConfig.deletePath('stringKey'); - expect(cliConfig.isDefined('stringKey')).toEqual(false); - expect(cliConfig.config.stringKey).toEqual('stringValue'); - - // Check on number (which is 2 fallbacks behind) - expect(cliConfig.isDefined('numberKey')).toEqual(false); - expect(cliConfig.config.numberKey).toEqual(1); - - cliConfig.config.numberKey = 2; - expect(cliConfig.isDefined('numberKey')).toEqual(true); - expect(cliConfig.config.numberKey).toEqual(2); - - cliConfig.deletePath('numberKey'); - expect(cliConfig.isDefined('numberKey')).toEqual(false); - expect(cliConfig.config.numberKey).toEqual(1); - }); - - it('saves', () => { - const jsonObject = { - requiredKey: 1, - arrayKey2: [{ stringKey: 'value1' }, { stringKey: 'value2' }] - }; - - const cliConfig = new CliConfig(null, schema, - jsonObject, [ - { requiredKey: 1, stringKey: 'stringValue' }, - { requiredKey: 1, numberKey: 1 } - ] - ); - - expect(cliConfig.config.arrayKey2[0].stringKey).toEqual('value1'); - expect(JSON.stringify(JSON.parse(cliConfig.serialize()))).toEqual(JSON.stringify(jsonObject)); - }); -}); diff --git a/packages/@angular/cli/models/config/config.ts b/packages/@angular/cli/models/config/config.ts deleted file mode 100644 index 6c988040853a..000000000000 --- a/packages/@angular/cli/models/config/config.ts +++ /dev/null @@ -1,137 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import { stripIndent } from 'common-tags'; - -import {SchemaClass, SchemaClassFactory} from '@ngtools/json-schema'; - -import { stripBom } from '../../utilities/strip-bom'; - - -const DEFAULT_CONFIG_SCHEMA_PATH = path.join(__dirname, '../../lib/config/schema.json'); - -class InvalidConfigError extends Error { - constructor(message: string) { - super(message); - this.message = message; - this.name = 'InvalidConfigError'; - } -} - - -export class CliConfig { - private _config: SchemaClass; - - constructor(private _configPath: string, - schema: Object, - configJson: JsonType, - fallbacks: JsonType[] = []) { - this._config = new (SchemaClassFactory(schema))(configJson, ...fallbacks); - } - - get config(): JsonType { return this._config; } - - save(path: string = this._configPath) { - return fs.writeFileSync(path, this.serialize(), {encoding: 'utf-8'}); - } - serialize(mimetype = 'application/json'): string { - return this._config.$$serialize(mimetype); - } - - alias(path: string, newPath: string): boolean { - return this._config.$$alias(path, newPath); - } - - get(jsonPath?: string) { - if (!jsonPath) { - return this._config.$$root(); - } - return this._config.$$get(jsonPath); - } - - typeOf(jsonPath: string): string { - return this._config.$$typeOf(jsonPath); - } - isDefined(jsonPath: string): boolean { - return this._config.$$defined(jsonPath); - } - deletePath(jsonPath: string) { - return this._config.$$delete(jsonPath); - } - - set(jsonPath: string, value: any) { - this._config.$$set(jsonPath, value); - } - - getPaths(baseJsonPath: string, keys: string[]) { - const ret: { [k: string]: any } = {}; - keys.forEach(key => ret[key] = this.get(`${baseJsonPath}.${key}`)); - return ret; - } - - static fromJson(content: ConfigType, ...global: ConfigType[]) { - const schemaContent = fs.readFileSync(DEFAULT_CONFIG_SCHEMA_PATH, 'utf-8'); - let schema: Object; - try { - schema = JSON.parse(schemaContent); - } catch (err) { - throw new InvalidConfigError(err.message); - } - - return new CliConfig(null, schema, content, global); - } - - static fromConfigPath(configPath: string, otherPath: string[] = []): CliConfig { - const schemaContent = fs.readFileSync(DEFAULT_CONFIG_SCHEMA_PATH, 'utf-8'); - let configContent = '{}'; - if (fs.existsSync(configPath)) { - configContent = stripBom(fs.readFileSync(configPath, 'utf-8') || '{}'); - } - - - let otherContents = new Array(); - if (configPath !== otherPath[0]) { - otherContents = otherPath - .map(path => { - if (fs.existsSync(path)) { - return stripBom(fs.readFileSync(path, 'utf-8')); - } - return undefined; - }) - .filter(content => !!content); - } - - let content: T; - let schema: Object; - let others: T[]; - - try { - content = JSON.parse(configContent); - } catch (err) { - throw new InvalidConfigError(stripIndent` - Parsing '${configPath}' failed. Ensure the file is valid JSON. - Error: ${err.message} - `); - } - - others = otherContents.map(otherContent => { - try { - return JSON.parse(otherContent); - } catch (err) { - throw new InvalidConfigError(stripIndent` - Parsing '${configPath}' failed. Ensure the file is valid JSON. - Error: ${err.message} - `); - } - }); - - try { - schema = JSON.parse(schemaContent); - } catch (err) { - throw new InvalidConfigError( - `Parsing Angular CLI schema failed. Error:\n${err.message}` - ); - } - - return new CliConfig(configPath, schema, content, others); - } -} diff --git a/packages/@angular/cli/models/config/spec-schema.d.ts b/packages/@angular/cli/models/config/spec-schema.d.ts deleted file mode 100644 index 38cc0629a200..000000000000 --- a/packages/@angular/cli/models/config/spec-schema.d.ts +++ /dev/null @@ -1,19 +0,0 @@ -export interface CliConfig { - requiredKey: number; - stringKeyDefault?: string; - stringKey?: string; - booleanKey?: boolean; - numberKey?: number; - objectKey1?: { - stringKey?: string; - objectKey?: { - stringKey?: string; - }; - }; - objectKey2?: { - [name: string]: any; - stringKey?: string; - }; - arrayKey1?: any[]; - arrayKey2?: any[]; -} diff --git a/packages/@angular/cli/models/config/spec-schema.json b/packages/@angular/cli/models/config/spec-schema.json deleted file mode 100644 index 9922d87cba96..000000000000 --- a/packages/@angular/cli/models/config/spec-schema.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "CliConfig", - "type": "object", - "properties": { - "requiredKey": { - "type": "number" - }, - "stringKeyDefault": { - "type": "string", - "default": "defaultValue" - }, - "stringKey": { - "type": "string" - }, - "booleanKey": { - "type": "boolean" - }, - "numberKey": { - "type": "number" - }, - "objectKey1": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - }, - "objectKey": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - } - }, - "objectKey2": { - "type": "object", - "properties": { - "stringKey": { - "type": "string", - "default": "default objectKey2.stringKey" - } - }, - "additionalProperties": true - }, - "arrayKey1": { - "type": "array", - "items": { - "type": "string" - } - }, - "arrayKey2": { - "type": "array", - "items": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - } - }, - "required": ["requiredKey"] -} \ No newline at end of file diff --git a/packages/@angular/cli/models/error.ts b/packages/@angular/cli/models/error.ts deleted file mode 100644 index 4dc5e590012f..000000000000 --- a/packages/@angular/cli/models/error.ts +++ /dev/null @@ -1,11 +0,0 @@ -export class NgToolkitError extends Error { - constructor(message?: string) { - super(); - - if (message) { - this.message = message; - } else { - this.message = (this.constructor).name; - } - } -} diff --git a/packages/@angular/cli/models/webpack-config.ts b/packages/@angular/cli/models/webpack-config.ts deleted file mode 100644 index 0ac692360951..000000000000 --- a/packages/@angular/cli/models/webpack-config.ts +++ /dev/null @@ -1,165 +0,0 @@ -// @ignoreDep typescript - used only for type information -import * as ts from 'typescript'; -import { AngularCompilerPlugin } from '@ngtools/webpack'; -import { readTsconfig } from '../utilities/read-tsconfig'; -import { requireProjectModule } from '../utilities/require-project-module'; -const webpackMerge = require('webpack-merge'); -import { CliConfig } from './config'; -import { BuildOptions } from './build-options'; -import { - getBrowserConfig, - getCommonConfig, - getDevConfig, - getProdConfig, - getStylesConfig, - getServerConfig, - getNonAotConfig, - getAotConfig -} from './webpack-configs'; -import * as path from 'path'; - -export interface WebpackConfigOptions { - projectRoot: string; - buildOptions: T; - appConfig: any; - tsConfig: any; - supportES2015: boolean; -} - -export class NgCliWebpackConfig { - public config: any; - public wco: WebpackConfigOptions; - constructor(buildOptions: T, appConfig: any) { - - this.validateBuildOptions(buildOptions); - - const configPath = CliConfig.configFilePath(); - const projectRoot = path.dirname(configPath); - - appConfig = this.addAppConfigDefaults(appConfig); - buildOptions = this.addTargetDefaults(buildOptions); - buildOptions = this.mergeConfigs(buildOptions, appConfig, projectRoot); - - const tsconfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig); - const tsConfig = readTsconfig(tsconfigPath); - - const projectTs = requireProjectModule(projectRoot, 'typescript') as typeof ts; - - const supportES2015 = tsConfig.options.target !== projectTs.ScriptTarget.ES3 - && tsConfig.options.target !== projectTs.ScriptTarget.ES5; - - this.wco = { projectRoot, buildOptions, appConfig, tsConfig, supportES2015 }; - } - - public buildConfig() { - const platformConfig = this.wco.appConfig.platform === 'server' ? - getServerConfig(this.wco) : getBrowserConfig(this.wco); - - let webpackConfigs = [ - getCommonConfig(this.wco), - platformConfig, - getStylesConfig(this.wco), - this.getTargetConfig(this.wco) - ]; - - if (this.wco.appConfig.main || this.wco.appConfig.polyfills) { - const typescriptConfigPartial = this.wco.buildOptions.aot - ? getAotConfig(this.wco) - : getNonAotConfig(this.wco); - webpackConfigs.push(typescriptConfigPartial); - } - - this.config = webpackMerge(webpackConfigs); - return this.config; - } - - public getTargetConfig(webpackConfigOptions: WebpackConfigOptions): any { - switch (webpackConfigOptions.buildOptions.target) { - case 'development': - return getDevConfig(webpackConfigOptions); - case 'production': - return getProdConfig(webpackConfigOptions); - } - } - - // Validate build options - public validateBuildOptions(buildOptions: BuildOptions) { - buildOptions.target = buildOptions.target || 'development'; - if (buildOptions.target !== 'development' && buildOptions.target !== 'production') { - throw new Error("Invalid build target. Only 'development' and 'production' are available."); - } - - if (buildOptions.buildOptimizer - && !(buildOptions.aot || buildOptions.target === 'production')) { - throw new Error('The `--build-optimizer` option cannot be used without `--aot`.'); - } - } - - // Fill in defaults for build targets - public addTargetDefaults(buildOptions: T): T { - const targetDefaults: { [target: string]: Partial } = { - development: { - environment: 'dev', - outputHashing: 'media', - sourcemaps: true, - extractCss: false, - namedChunks: true, - aot: false, - buildOptimizer: false - }, - production: { - environment: 'prod', - outputHashing: 'all', - sourcemaps: false, - extractCss: true, - namedChunks: false, - aot: true - } - }; - - let merged = Object.assign({}, targetDefaults[buildOptions.target], buildOptions); - - // Use Build Optimizer on prod AOT builds by default when AngularCompilerPlugin is supported. - const buildOptimizerDefault = { - buildOptimizer: buildOptions.target == 'production' && buildOptions.aot !== false - && AngularCompilerPlugin.isSupported() - }; - - merged = Object.assign({}, buildOptimizerDefault, merged); - - // Default vendor chunk to false when build optimizer is on. - const vendorChunkDefault = { - vendorChunk: !merged.buildOptimizer - }; - - merged = Object.assign({}, vendorChunkDefault, merged); - - return merged; - } - - // Fill in defaults from .angular-cli.json - public mergeConfigs(buildOptions: T, appConfig: any, projectRoot: string): T { - const mergeableOptions: Partial = { - outputPath: path.resolve(projectRoot, appConfig.outDir), - deployUrl: appConfig.deployUrl, - baseHref: appConfig.baseHref - }; - - return Object.assign({}, mergeableOptions, buildOptions); - } - - public addAppConfigDefaults(appConfig: any) { - const appConfigDefaults: any = { - testTsconfig: appConfig.tsconfig, - scripts: [], - styles: [] - }; - - // can't use Object.assign here because appConfig has a lot of getters/setters - for (let key of Object.keys(appConfigDefaults)) { - appConfig[key] = appConfig[key] || appConfigDefaults[key]; - } - - return appConfig; - } -} diff --git a/packages/@angular/cli/models/webpack-configs/browser.ts b/packages/@angular/cli/models/webpack-configs/browser.ts deleted file mode 100644 index 3ec6bb723a01..000000000000 --- a/packages/@angular/cli/models/webpack-configs/browser.ts +++ /dev/null @@ -1,123 +0,0 @@ -import * as fs from 'fs'; -import * as webpack from 'webpack'; -import * as path from 'path'; -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const SubresourceIntegrityPlugin = require('webpack-subresource-integrity'); - -import { packageChunkSort } from '../../utilities/package-chunk-sort'; -import { BaseHrefWebpackPlugin } from '../../lib/base-href-webpack'; -import { extraEntryParser, lazyChunksFilter } from './utils'; -import { WebpackConfigOptions } from '../webpack-config'; - - -export function getBrowserConfig(wco: WebpackConfigOptions) { - const { projectRoot, buildOptions, appConfig } = wco; - - const appRoot = path.resolve(projectRoot, appConfig.root); - - let extraPlugins: any[] = []; - - // figure out which are the lazy loaded entry points - const lazyChunks = lazyChunksFilter([ - ...extraEntryParser(appConfig.scripts, appRoot, 'scripts'), - ...extraEntryParser(appConfig.styles, appRoot, 'styles') - ]); - - if (buildOptions.vendorChunk) { - // Separate modules from node_modules into a vendor chunk. - const nodeModules = path.resolve(projectRoot, 'node_modules'); - // Resolves all symlink to get the actual node modules folder. - const realNodeModules = fs.realpathSync(nodeModules); - // --aot puts the generated *.ngfactory.ts in src/$$_gendir/node_modules. - const genDirNodeModules = path.resolve(appRoot, '$$_gendir', 'node_modules'); - - extraPlugins.push(new webpack.optimize.CommonsChunkPlugin({ - name: 'vendor', - chunks: ['main'], - minChunks: (module: any) => { - return module.resource - && ( module.resource.startsWith(nodeModules) - || module.resource.startsWith(genDirNodeModules) - || module.resource.startsWith(realNodeModules)); - } - })); - } - - if (buildOptions.sourcemaps) { - // See https://webpack.js.org/configuration/devtool/ for sourcemap types. - if (buildOptions.evalSourcemaps && buildOptions.target === 'development') { - // Produce eval sourcemaps for development with serve, which are faster. - extraPlugins.push(new webpack.EvalSourceMapDevToolPlugin({ - moduleFilenameTemplate: '[resource-path]', - sourceRoot: 'webpack:///' - })); - } else { - // Produce full separate sourcemaps for production. - extraPlugins.push(new webpack.SourceMapDevToolPlugin({ - filename: '[file].map[query]', - moduleFilenameTemplate: '[resource-path]', - fallbackModuleFilenameTemplate: '[resource-path]?[hash]', - sourceRoot: 'webpack:///' - })); - } - } - - if (buildOptions.commonChunk) { - extraPlugins.push(new webpack.optimize.CommonsChunkPlugin({ - name: 'main', - async: 'common', - children: true, - minChunks: 2 - })); - } - - if (buildOptions.subresourceIntegrity) { - extraPlugins.push(new SubresourceIntegrityPlugin({ - hashFuncNames: ['sha384'] - })); - } - - return { - resolve: { - mainFields: [ - ...(wco.supportES2015 ? ['es2015'] : []), - 'browser', 'module', 'main' - ] - }, - output: { - crossOriginLoading: buildOptions.subresourceIntegrity ? 'anonymous' : false - }, - plugins: [ - new HtmlWebpackPlugin({ - template: path.resolve(appRoot, appConfig.index), - filename: path.resolve(buildOptions.outputPath, appConfig.index), - chunksSortMode: packageChunkSort(appConfig), - excludeChunks: lazyChunks, - xhtml: true, - minify: buildOptions.target === 'production' ? { - caseSensitive: true, - collapseWhitespace: true, - keepClosingSlash: true - } : false - }), - new BaseHrefWebpackPlugin({ - baseHref: buildOptions.baseHref - }), - new webpack.optimize.CommonsChunkPlugin({ - minChunks: Infinity, - name: 'inline' - }) - ].concat(extraPlugins), - node: { - fs: 'empty', - global: true, - crypto: 'empty', - tls: 'empty', - net: 'empty', - process: true, - module: false, - clearImmediate: false, - setImmediate: false - } - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/common.ts b/packages/@angular/cli/models/webpack-configs/common.ts deleted file mode 100644 index ecb60283a19c..000000000000 --- a/packages/@angular/cli/models/webpack-configs/common.ts +++ /dev/null @@ -1,230 +0,0 @@ -import * as webpack from 'webpack'; -import * as path from 'path'; -import * as CopyWebpackPlugin from 'copy-webpack-plugin'; -import { NamedLazyChunksWebpackPlugin } from '../../plugins/named-lazy-chunks-webpack-plugin'; -import { InsertConcatAssetsWebpackPlugin } from '../../plugins/insert-concat-assets-webpack-plugin'; -import { extraEntryParser, getOutputHashFormat, AssetPattern } from './utils'; -import { isDirectory } from '../../utilities/is-directory'; -import { requireProjectModule } from '../../utilities/require-project-module'; -import { WebpackConfigOptions } from '../webpack-config'; - -const ConcatPlugin = require('webpack-concat-plugin'); -const ProgressPlugin = require('webpack/lib/ProgressPlugin'); -const CircularDependencyPlugin = require('circular-dependency-plugin'); -const SilentError = require('silent-error'); - -/** - * Enumerate loaders and their dependencies from this file to let the dependency validator - * know they are used. - * - * require('source-map-loader') - * require('raw-loader') - * require('url-loader') - * require('file-loader') - * require('@angular-devkit/build-optimizer') - */ - -export function getCommonConfig(wco: WebpackConfigOptions) { - const { projectRoot, buildOptions, appConfig } = wco; - - const appRoot = path.resolve(projectRoot, appConfig.root); - const nodeModules = path.resolve(projectRoot, 'node_modules'); - - let extraPlugins: any[] = []; - let extraRules: any[] = []; - let entryPoints: { [key: string]: string[] } = {}; - - if (appConfig.main) { - entryPoints['main'] = [path.resolve(appRoot, appConfig.main)]; - } - - if (appConfig.polyfills) { - entryPoints['polyfills'] = [path.resolve(appRoot, appConfig.polyfills)]; - } - - // determine hashing format - const hashFormat = getOutputHashFormat(buildOptions.outputHashing); - - // process global scripts - if (appConfig.scripts.length > 0) { - const globalScripts = extraEntryParser(appConfig.scripts, appRoot, 'scripts'); - const globalScriptsByEntry = globalScripts - .reduce((prev: { entry: string, paths: string[], lazy: boolean }[], curr) => { - - let existingEntry = prev.find((el) => el.entry === curr.entry); - if (existingEntry) { - existingEntry.paths.push(curr.path); - // All entries have to be lazy for the bundle to be lazy. - existingEntry.lazy = existingEntry.lazy && curr.lazy; - } else { - prev.push({ entry: curr.entry, paths: [curr.path], lazy: curr.lazy }); - } - return prev; - }, []); - - - // Add a new asset for each entry. - globalScriptsByEntry.forEach((script) => { - const hash = hashFormat.chunk !== '' && !script.lazy ? '.[hash]' : ''; - extraPlugins.push(new ConcatPlugin({ - uglify: buildOptions.target === 'production' ? { sourceMapIncludeSources: true } : false, - sourceMap: buildOptions.sourcemaps, - name: script.entry, - // Lazy scripts don't get a hash, otherwise they can't be loaded by name. - fileName: `[name]${script.lazy ? '' : hash}.bundle.js`, - filesToConcat: script.paths - })); - }); - - // Insert all the assets created by ConcatPlugin in the right place in index.html. - extraPlugins.push(new InsertConcatAssetsWebpackPlugin( - globalScriptsByEntry - .filter((el) => !el.lazy) - .map((el) => el.entry) - )); - } - - // process asset entries - if (appConfig.assets) { - const copyWebpackPluginPatterns = appConfig.assets.map((asset: string | AssetPattern) => { - // Convert all string assets to object notation. - asset = typeof asset === 'string' ? { glob: asset } : asset; - // Add defaults. - // Input is always resolved relative to the appRoot. - asset.input = path.resolve(appRoot, asset.input || ''); - asset.output = asset.output || ''; - asset.glob = asset.glob || ''; - - // Prevent asset configurations from writing outside of the output path, except if the user - // specify a configuration flag. - // Also prevent writing outside the project path. That is not overridable. - const fullOutputPath = path.resolve(buildOptions.outputPath, asset.output); - if (!fullOutputPath.startsWith(projectRoot)) { - const message = 'An asset cannot be written to a location outside the project.'; - throw new SilentError(message); - } - if (!fullOutputPath.startsWith(path.resolve(buildOptions.outputPath))) { - if (!asset.allowOutsideOutDir) { - const message = 'An asset cannot be written to a location outside of the output path. ' - + 'You can override this message by setting the `allowOutsideOutDir` ' - + 'property on the asset to true in the CLI configuration.'; - throw new SilentError(message); - } - } - - // Prevent asset configurations from reading files outside of the project. - if (!asset.input.startsWith(projectRoot)) { - const message = 'An asset cannot be read from a location outside the project.'; - throw new SilentError(message); - } - - // Ensure trailing slash. - if (isDirectory(path.resolve(asset.input))) { - asset.input += '/'; - } - - // Convert dir patterns to globs. - if (isDirectory(path.resolve(asset.input, asset.glob))) { - asset.glob = asset.glob + '/**/*'; - } - - return { - context: asset.input, - to: asset.output, - from: { - glob: asset.glob, - dot: true - } - }; - }); - const copyWebpackPluginOptions = { ignore: ['.gitkeep', '**/.DS_Store', '**/Thumbs.db'] }; - - const copyWebpackPluginInstance = new CopyWebpackPlugin(copyWebpackPluginPatterns, - copyWebpackPluginOptions); - - // Save options so we can use them in eject. - (copyWebpackPluginInstance as any)['copyWebpackPluginPatterns'] = copyWebpackPluginPatterns; - (copyWebpackPluginInstance as any)['copyWebpackPluginOptions'] = copyWebpackPluginOptions; - - extraPlugins.push(copyWebpackPluginInstance); - } - - if (buildOptions.progress) { - extraPlugins.push(new ProgressPlugin({ profile: buildOptions.verbose, colors: true })); - } - - if (buildOptions.showCircularDependencies) { - extraPlugins.push(new CircularDependencyPlugin({ - exclude: /(\\|\/)node_modules(\\|\/)/ - })); - } - - if (buildOptions.buildOptimizer) { - extraRules.push({ - test: /\.js$/, - use: [{ - loader: '@angular-devkit/build-optimizer/webpack-loader', - options: { sourceMap: buildOptions.sourcemaps } - }] - }); - } - - if (buildOptions.namedChunks) { - extraPlugins.push(new NamedLazyChunksWebpackPlugin()); - } - - // Load rxjs path aliases. - // https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#build-and-treeshaking - let alias = {}; - try { - const rxjsPathMappingImport = wco.supportES2015 - ? 'rxjs/_esm2015/path-mapping' - : 'rxjs/_esm5/path-mapping'; - const rxPaths = requireProjectModule(projectRoot, rxjsPathMappingImport); - alias = rxPaths(nodeModules); - } catch (e) { } - - return { - resolve: { - extensions: ['.ts', '.js'], - modules: ['node_modules', nodeModules], - symlinks: !buildOptions.preserveSymlinks, - alias - }, - resolveLoader: { - modules: [nodeModules, 'node_modules'] - }, - context: __dirname, - entry: entryPoints, - output: { - path: path.resolve(buildOptions.outputPath), - publicPath: buildOptions.deployUrl, - filename: `[name]${hashFormat.chunk}.bundle.js`, - chunkFilename: `[id]${hashFormat.chunk}.chunk.js` - }, - module: { - rules: [ - { test: /\.html$/, loader: 'raw-loader' }, - { - test: /\.(eot|svg|cur)$/, - loader: 'file-loader', - options: { - name: `[name]${hashFormat.file}.[ext]`, - limit: 10000 - } - }, - { - test: /\.(jpg|png|webp|gif|otf|ttf|woff|woff2|ani)$/, - loader: 'url-loader', - options: { - name: `[name]${hashFormat.file}.[ext]`, - limit: 10000 - } - } - ].concat(extraRules) - }, - plugins: [ - new webpack.NoEmitOnErrorsPlugin() - ].concat(extraPlugins) - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/development.ts b/packages/@angular/cli/models/webpack-configs/development.ts deleted file mode 100644 index 5b2227cc51a6..000000000000 --- a/packages/@angular/cli/models/webpack-configs/development.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { NamedModulesPlugin } from 'webpack'; - -import { WebpackConfigOptions } from '../webpack-config'; - -export function getDevConfig(_wco: WebpackConfigOptions) { - return { - plugins: [new NamedModulesPlugin()] - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/index.ts b/packages/@angular/cli/models/webpack-configs/index.ts deleted file mode 100644 index 70560367f79f..000000000000 --- a/packages/@angular/cli/models/webpack-configs/index.ts +++ /dev/null @@ -1,10 +0,0 @@ -export * from './browser'; -export * from './common'; -export * from './development'; -export * from './production'; -export * from './server'; -export * from './styles'; -export * from './test'; -export * from './typescript'; -export * from './utils'; -export * from './xi18n'; diff --git a/packages/@angular/cli/models/webpack-configs/production.ts b/packages/@angular/cli/models/webpack-configs/production.ts deleted file mode 100644 index fddc7f373861..000000000000 --- a/packages/@angular/cli/models/webpack-configs/production.ts +++ /dev/null @@ -1,156 +0,0 @@ -import * as path from 'path'; -import * as webpack from 'webpack'; -import * as fs from 'fs'; -import * as semver from 'semver'; -import { stripIndent } from 'common-tags'; -import { LicenseWebpackPlugin } from 'license-webpack-plugin'; -import { PurifyPlugin } from '@angular-devkit/build-optimizer'; -import { StaticAssetPlugin } from '../../plugins/static-asset'; -import { GlobCopyWebpackPlugin } from '../../plugins/glob-copy-webpack-plugin'; -import { WebpackConfigOptions } from '../webpack-config'; -import { NEW_SW_VERSION } from '../../utilities/service-worker'; - -const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); - -const OLD_SW_VERSION = '>= 1.0.0-beta.5 < 2.0.0'; - -/** - * license-webpack-plugin has a peer dependency on webpack-sources, list it in a comment to - * let the dependency validator know it is used. - * - * require('webpack-sources') - */ - - -export function getProdConfig(wco: WebpackConfigOptions) { - const { projectRoot, buildOptions, appConfig } = wco; - - let extraPlugins: any[] = []; - let entryPoints: { [key: string]: string[] } = {}; - - if (appConfig.serviceWorker) { - const nodeModules = path.resolve(projectRoot, 'node_modules'); - const swModule = path.resolve(nodeModules, '@angular/service-worker'); - - // @angular/service-worker is required to be installed when serviceWorker is true. - if (!fs.existsSync(swModule)) { - throw new Error(stripIndent` - Your project is configured with serviceWorker = true, but @angular/service-worker - is not installed. Run \`npm install --save-dev @angular/service-worker\` - and try again, or run \`ng set apps.0.serviceWorker=false\` in your .angular-cli.json. - `); - } - - // Read the version of @angular/service-worker and throw if it doesn't match the - // expected version. - const swPackageJson = fs.readFileSync(`${swModule}/package.json`).toString(); - const swVersion = JSON.parse(swPackageJson)['version']; - - const isLegacySw = semver.satisfies(swVersion, OLD_SW_VERSION); - const isModernSw = semver.satisfies(swVersion, NEW_SW_VERSION); - - if (!isLegacySw && !isModernSw) { - throw new Error(stripIndent` - The installed version of @angular/service-worker is ${swVersion}. This version of the CLI - requires the @angular/service-worker version to satisfy ${OLD_SW_VERSION}. Please upgrade - your service worker version. - `); - } - - if (isLegacySw) { - // Path to the worker script itself. - const workerPath = path.resolve(swModule, 'bundles/worker-basic.min.js'); - - // Path to a small script to register a service worker. - const registerPath = path.resolve(swModule, 'build/assets/register-basic.min.js'); - - // Sanity check - both of these files should be present in @angular/service-worker. - if (!fs.existsSync(workerPath) || !fs.existsSync(registerPath)) { - throw new Error(stripIndent` - The installed version of @angular/service-worker isn't supported by the CLI. - Please install a supported version. The following files should exist: - - ${registerPath} - - ${workerPath} - `); - } - - // CopyWebpackPlugin replaces GlobCopyWebpackPlugin, but AngularServiceWorkerPlugin depends - // on specific behaviour from latter. - // AngularServiceWorkerPlugin expects the ngsw-manifest.json to be present in the 'emit' phase - // but with CopyWebpackPlugin it's only there on 'after-emit'. - // So for now we keep it here, but if AngularServiceWorkerPlugin changes we remove it. - extraPlugins.push(new GlobCopyWebpackPlugin({ - patterns: [ - 'ngsw-manifest.json', - { glob: 'ngsw-manifest.json', - input: path.resolve(projectRoot, appConfig.root), output: '' } - ], - globOptions: { - cwd: projectRoot, - optional: true, - }, - })); - - // Load the Webpack plugin for manifest generation and install it. - const AngularServiceWorkerPlugin = require('@angular/service-worker/build/webpack') - .AngularServiceWorkerPlugin; - extraPlugins.push(new AngularServiceWorkerPlugin({ - baseHref: buildOptions.baseHref || '/', - })); - - // Copy the worker script into assets. - const workerContents = fs.readFileSync(workerPath).toString(); - extraPlugins.push(new StaticAssetPlugin('worker-basic.min.js', workerContents)); - - // Add a script to index.html that registers the service worker. - // TODO(alxhub): inline this script somehow. - entryPoints['sw-register'] = [registerPath]; - } - } - - if (buildOptions.extractLicenses) { - extraPlugins.push(new LicenseWebpackPlugin({ - pattern: /^(MIT|ISC|BSD.*)$/, - suppressErrors: true, - perChunkOutput: false, - outputFilename: `3rdpartylicenses.txt` - })); - } - - const uglifyCompressOptions: any = {}; - - if (buildOptions.buildOptimizer) { - // This plugin must be before webpack.optimize.UglifyJsPlugin. - extraPlugins.push(new PurifyPlugin()); - uglifyCompressOptions.pure_getters = true; - // PURE comments work best with 3 passes. - // See https://github.com/webpack/webpack/issues/2899#issuecomment-317425926. - uglifyCompressOptions.passes = 3; - } - - return { - entry: entryPoints, - plugins: [ - new webpack.EnvironmentPlugin({ - 'NODE_ENV': 'production' - }), - new webpack.HashedModuleIdsPlugin(), - new webpack.optimize.ModuleConcatenationPlugin(), - new UglifyJSPlugin({ - sourceMap: buildOptions.sourcemaps, - uglifyOptions: { - ecma: wco.supportES2015 ? 6 : 5, - warnings: buildOptions.verbose, - ie8: false, - mangle: true, - compress: uglifyCompressOptions, - output: { - ascii_only: true, - comments: false - }, - } - }), - ...extraPlugins - ] - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/server.ts b/packages/@angular/cli/models/webpack-configs/server.ts deleted file mode 100644 index dcfcecd0d6bd..000000000000 --- a/packages/@angular/cli/models/webpack-configs/server.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { WebpackConfigOptions } from '../webpack-config'; - -/** - * Returns a partial specific to creating a bundle for node - * @param wco Options which are include the build options and app config - */ -export function getServerConfig(wco: WebpackConfigOptions) { - - const config: any = { - resolve: { - mainFields: [ - ...(wco.supportES2015 ? ['es2015'] : []), - 'main', 'module', - ], - }, - target: 'node', - output: { - libraryTarget: 'commonjs' - }, - node: false, - }; - - if (wco.buildOptions.bundleDependencies == 'none') { - config.externals = [ - /^@angular/, - (_: any, request: any, callback: (error?: any, result?: any) => void) => { - // Absolute & Relative paths are not externals - if (request.match(/^\.{0,2}\//)) { - return callback(); - } - - try { - // Attempt to resolve the module via Node - const e = require.resolve(request); - if (/node_modules/.test(e)) { - // It's a node_module - callback(null, request); - } else { - // It's a system thing (.ie util, fs...) - callback(); - } - } catch (e) { - // Node couldn't find it, so it must be user-aliased - callback(); - } - } - ]; - } - - return config; -} diff --git a/packages/@angular/cli/models/webpack-configs/styles.ts b/packages/@angular/cli/models/webpack-configs/styles.ts deleted file mode 100644 index 83392219cbdb..000000000000 --- a/packages/@angular/cli/models/webpack-configs/styles.ts +++ /dev/null @@ -1,227 +0,0 @@ -import * as webpack from 'webpack'; -import * as path from 'path'; -import { - SuppressExtractedTextChunksWebpackPlugin -} from '../../plugins/suppress-entry-chunks-webpack-plugin'; -import { extraEntryParser, getOutputHashFormat } from './utils'; -import { WebpackConfigOptions } from '../webpack-config'; -import { pluginArgs, postcssArgs } from '../../tasks/eject'; - -const cssnano = require('cssnano'); -const postcssUrl = require('postcss-url'); -const autoprefixer = require('autoprefixer'); -const ExtractTextPlugin = require('extract-text-webpack-plugin'); -const customProperties = require('postcss-custom-properties'); - -/** - * Enumerate loaders and their dependencies from this file to let the dependency validator - * know they are used. - * - * require('exports-loader') - * require('style-loader') - * require('postcss-loader') - * require('css-loader') - * require('stylus') - * require('stylus-loader') - * require('less') - * require('less-loader') - * require('node-sass') - * require('sass-loader') - */ - -export function getStylesConfig(wco: WebpackConfigOptions) { - const { projectRoot, buildOptions, appConfig } = wco; - - const appRoot = path.resolve(projectRoot, appConfig.root); - const entryPoints: { [key: string]: string[] } = {}; - const globalStylePaths: string[] = []; - const extraPlugins: any[] = []; - // style-loader does not support sourcemaps without absolute publicPath, so it's - // better to disable them when not extracting css - // https://github.com/webpack-contrib/style-loader#recommended-configuration - const cssSourceMap = buildOptions.extractCss && buildOptions.sourcemaps; - - // Minify/optimize css in production. - const minimizeCss = buildOptions.target === 'production'; - // Convert absolute resource URLs to account for base-href and deploy-url. - const baseHref = wco.buildOptions.baseHref || ''; - const deployUrl = wco.buildOptions.deployUrl || ''; - - const postcssPluginCreator = function() { - // safe settings based on: https://github.com/ben-eb/cssnano/issues/358#issuecomment-283696193 - const importantCommentRe = /@preserve|@license|[@#]\s*source(?:Mapping)?URL|^!/i; - const minimizeOptions = { - autoprefixer: false, // full pass with autoprefixer is run separately - safe: true, - mergeLonghand: false, // version 3+ should be safe; cssnano currently uses 2.x - discardComments : { remove: (comment: string) => !importantCommentRe.test(comment) } - }; - - return [ - postcssUrl({ - url: (URL: { url: string }) => { - const { url } = URL; - // Only convert root relative URLs, which CSS-Loader won't process into require(). - if (!url.startsWith('/') || url.startsWith('//')) { - return URL.url; - } - - if (deployUrl.match(/:\/\//)) { - // If deployUrl contains a scheme, ignore baseHref use deployUrl as is. - return `${deployUrl.replace(/\/$/, '')}${url}`; - } else if (baseHref.match(/:\/\//)) { - // If baseHref contains a scheme, include it as is. - return baseHref.replace(/\/$/, '') + - `/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); - } else { - // Join together base-href, deploy-url and the original URL. - // Also dedupe multiple slashes into single ones. - return `/${baseHref}/${deployUrl}/${url}`.replace(/\/\/+/g, '/'); - } - } - }), - autoprefixer(), - customProperties({ preserve: true}) - ].concat( - minimizeCss ? [cssnano(minimizeOptions)] : [] - ); - }; - (postcssPluginCreator as any)[postcssArgs] = { - variableImports: { - 'autoprefixer': 'autoprefixer', - 'postcss-url': 'postcssUrl', - 'cssnano': 'cssnano', - 'postcss-custom-properties': 'customProperties' - }, - variables: { minimizeCss, baseHref, deployUrl } - }; - - // determine hashing format - const hashFormat = getOutputHashFormat(buildOptions.outputHashing); - - // use includePaths from appConfig - const includePaths: string[] = []; - let lessPathOptions: { paths: string[] }; - - if (appConfig.stylePreprocessorOptions - && appConfig.stylePreprocessorOptions.includePaths - && appConfig.stylePreprocessorOptions.includePaths.length > 0 - ) { - appConfig.stylePreprocessorOptions.includePaths.forEach((includePath: string) => - includePaths.push(path.resolve(appRoot, includePath))); - lessPathOptions = { - paths: includePaths, - }; - } - - // process global styles - if (appConfig.styles.length > 0) { - const globalStyles = extraEntryParser(appConfig.styles, appRoot, 'styles'); - // add style entry points - globalStyles.forEach(style => - entryPoints[style.entry] - ? entryPoints[style.entry].push(style.path) - : entryPoints[style.entry] = [style.path] - ); - // add global css paths - globalStylePaths.push(...globalStyles.map((style) => style.path)); - } - - // set base rules to derive final rules from - const baseRules: webpack.NewUseRule[] = [ - { test: /\.css$/, use: [] }, - { test: /\.scss$|\.sass$/, use: [{ - loader: 'sass-loader', - options: { - sourceMap: cssSourceMap, - // bootstrap-sass requires a minimum precision of 8 - precision: 8, - includePaths - } - }] - }, - { test: /\.less$/, use: [{ - loader: 'less-loader', - options: { - sourceMap: cssSourceMap, - ...lessPathOptions, - } - }] - }, - { - test: /\.styl$/, use: [{ - loader: 'stylus-loader', - options: { - sourceMap: cssSourceMap, - paths: includePaths - } - }] - } - ]; - - const commonLoaders: webpack.Loader[] = [ - { - loader: 'css-loader', - options: { - sourceMap: cssSourceMap, - importLoaders: 1 - } - }, - { - loader: 'postcss-loader', - options: { - // A non-function property is required to workaround a webpack option handling bug - ident: 'postcss', - plugins: postcssPluginCreator - } - } - ]; - - // load component css as raw strings - const rules: webpack.Rule[] = baseRules.map(({test, use}) => ({ - exclude: globalStylePaths, test, use: [ - 'exports-loader?module.exports.toString()', - ...commonLoaders, - ...(use as webpack.Loader[]) - ] - })); - - // load global css as css files - if (globalStylePaths.length > 0) { - rules.push(...baseRules.map(({test, use}) => { - const extractTextPlugin = { - use: [ - ...commonLoaders, - ...(use as webpack.Loader[]) - ], - // publicPath needed as a workaround https://github.com/angular/angular-cli/issues/4035 - publicPath: '' - }; - const ret: any = { - include: globalStylePaths, - test, -        use: buildOptions.extractCss ? ExtractTextPlugin.extract(extractTextPlugin) - : ['style-loader', ...extractTextPlugin.use] - }; - // Save the original options as arguments for eject. - if (buildOptions.extractCss) { - ret[pluginArgs] = extractTextPlugin; - } - return ret; - })); - } - - if (buildOptions.extractCss) { - // extract global css from js files into own css file - extraPlugins.push( - new ExtractTextPlugin({ filename: `[name]${hashFormat.extract}.bundle.css` })); - // suppress empty .js files in css only entry points - extraPlugins.push(new SuppressExtractedTextChunksWebpackPlugin()); - } - - return { - entry: entryPoints, - module: { rules }, - plugins: [].concat(extraPlugins) - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/test.ts b/packages/@angular/cli/models/webpack-configs/test.ts deleted file mode 100644 index 00d3942d201d..000000000000 --- a/packages/@angular/cli/models/webpack-configs/test.ts +++ /dev/null @@ -1,76 +0,0 @@ -import * as path from 'path'; -import * as glob from 'glob'; -import * as webpack from 'webpack'; - -import { CliConfig } from '../config'; -import { WebpackTestOptions } from '../webpack-test-config'; -import { WebpackConfigOptions } from '../webpack-config'; - - -/** - * Enumerate loaders and their dependencies from this file to let the dependency validator - * know they are used. - * - * require('istanbul-instrumenter-loader') - * - */ - - -export function getTestConfig(wco: WebpackConfigOptions) { - const { projectRoot, buildOptions, appConfig } = wco; - - const nodeModules = path.resolve(projectRoot, 'node_modules'); - const extraRules: any[] = []; - const extraPlugins: any[] = []; - - if (buildOptions.codeCoverage && CliConfig.fromProject()) { - const codeCoverageExclude = CliConfig.fromProject().get('test.codeCoverage.exclude'); - let exclude: (string | RegExp)[] = [ - /\.(e2e|spec)\.ts$/, - /node_modules/ - ]; - - if (codeCoverageExclude) { - codeCoverageExclude.forEach((excludeGlob: string) => { - const excludeFiles = glob - .sync(path.join(projectRoot, excludeGlob), { nodir: true }) - .map(file => path.normalize(file)); - exclude.push(...excludeFiles); - }); - } - - extraRules.push({ - test: /\.(js|ts)$/, loader: 'istanbul-instrumenter-loader', - options: { esModules: true }, - enforce: 'post', - exclude - }); - } - - return { - resolve: { - mainFields: [ - ...(wco.supportES2015 ? ['es2015'] : []), - 'browser', 'module', 'main' - ] - }, - devtool: buildOptions.sourcemaps ? 'inline-source-map' : 'eval', - entry: { - main: path.resolve(projectRoot, appConfig.root, appConfig.test) - }, - module: { - rules: [].concat(extraRules) - }, - plugins: [ - new webpack.optimize.CommonsChunkPlugin({ - minChunks: Infinity, - name: 'inline' - }), - new webpack.optimize.CommonsChunkPlugin({ - name: 'vendor', - chunks: ['main'], - minChunks: (module: any) => module.resource && module.resource.startsWith(nodeModules) - }) - ].concat(extraPlugins) - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/typescript.ts b/packages/@angular/cli/models/webpack-configs/typescript.ts deleted file mode 100644 index 86b6819deeb0..000000000000 --- a/packages/@angular/cli/models/webpack-configs/typescript.ts +++ /dev/null @@ -1,194 +0,0 @@ -import * as path from 'path'; -import { stripIndent } from 'common-tags'; -import { - AotPlugin, - AotPluginOptions, - AngularCompilerPlugin, - AngularCompilerPluginOptions, - PLATFORM -} from '@ngtools/webpack'; -import { WebpackConfigOptions } from '../webpack-config'; - -const SilentError = require('silent-error'); - - -const g: any = global; -const webpackLoader: string = g['angularCliIsLocal'] - ? g.angularCliPackages['@ngtools/webpack'].main - : '@ngtools/webpack'; - - -function _createAotPlugin(wco: WebpackConfigOptions, options: any, useMain = true) { - const { appConfig, projectRoot, buildOptions } = wco; - options.compilerOptions = options.compilerOptions || {}; - - if (wco.buildOptions.preserveSymlinks) { - options.compilerOptions.preserveSymlinks = true; - } - - // Forcing commonjs seems to drastically improve rebuild speeds on webpack. - // Dev builds on watch mode will set this option to true. - if (wco.buildOptions.forceTsCommonjs) { - options.compilerOptions.module = 'commonjs'; - } - - // Read the environment, and set it in the compiler host. - let hostReplacementPaths: any = {}; - // process environment file replacement - if (appConfig.environments) { - if (!appConfig.environmentSource) { - let migrationMessage = ''; - if ('source' in appConfig.environments) { - migrationMessage = '\n\n' + stripIndent` - A new environmentSource entry replaces the previous source entry inside environments. - - To migrate angular-cli.json follow the example below: - - Before: - - "environments": { - "source": "environments/environment.ts", - "dev": "environments/environment.ts", - "prod": "environments/environment.prod.ts" - } - - - After: - - "environmentSource": "environments/environment.ts", - "environments": { - "dev": "environments/environment.ts", - "prod": "environments/environment.prod.ts" - } - `; - } - throw new SilentError( - `Environment configuration does not contain "environmentSource" entry.${migrationMessage}` - ); - - } - if (!(buildOptions.environment in appConfig.environments)) { - throw new SilentError(`Environment "${buildOptions.environment}" does not exist.`); - } - - const appRoot = path.resolve(projectRoot, appConfig.root); - const sourcePath = appConfig.environmentSource; - const envFile = appConfig.environments[buildOptions.environment]; - - hostReplacementPaths = { - [path.resolve(appRoot, sourcePath)]: path.resolve(appRoot, envFile) - }; - } - - if (AngularCompilerPlugin.isSupported()) { - const pluginOptions: AngularCompilerPluginOptions = Object.assign({}, { - mainPath: useMain ? path.join(projectRoot, appConfig.root, appConfig.main) : undefined, - i18nInFile: buildOptions.i18nFile, - i18nInFormat: buildOptions.i18nFormat, - i18nOutFile: buildOptions.i18nOutFile, - i18nOutFormat: buildOptions.i18nOutFormat, - locale: buildOptions.locale, - platform: appConfig.platform === 'server' ? PLATFORM.Server : PLATFORM.Browser, - missingTranslation: buildOptions.missingTranslation, - hostReplacementPaths, - sourceMap: buildOptions.sourcemaps, - }, options); - return new AngularCompilerPlugin(pluginOptions); - } else { - const pluginOptions: AotPluginOptions = Object.assign({}, { - mainPath: path.join(projectRoot, appConfig.root, appConfig.main), - i18nFile: buildOptions.i18nFile, - i18nFormat: buildOptions.i18nFormat, - locale: buildOptions.locale, - replaceExport: appConfig.platform === 'server', - missingTranslation: buildOptions.missingTranslation, - hostReplacementPaths, - sourceMap: buildOptions.sourcemaps, - // If we don't explicitely list excludes, it will default to `['**/*.spec.ts']`. - exclude: [] - }, options); - return new AotPlugin(pluginOptions); - } -} - -export function getNonAotConfig(wco: WebpackConfigOptions) { - const { appConfig, projectRoot } = wco; - const tsConfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig); - - return { - module: { rules: [{ test: /\.ts$/, loader: webpackLoader }] }, - plugins: [ _createAotPlugin(wco, { tsConfigPath, skipCodeGeneration: true }) ] - }; -} - -export function getAotConfig(wco: WebpackConfigOptions) { - const { projectRoot, buildOptions, appConfig } = wco; - const tsConfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig); - const testTsConfigPath = path.resolve(projectRoot, appConfig.root, appConfig.testTsconfig); - - let pluginOptions: any = { tsConfigPath }; - - // Fallback to exclude spec files from AoT compilation on projects using a shared tsconfig. - if (testTsConfigPath === tsConfigPath) { - let exclude = [ '**/*.spec.ts' ]; - if (appConfig.test) { - exclude.push(path.join(projectRoot, appConfig.root, appConfig.test)); - } - pluginOptions.exclude = exclude; - } - - let boLoader: any = []; - if (buildOptions.buildOptimizer) { - boLoader = [{ - loader: '@angular-devkit/build-optimizer/webpack-loader', - options: { sourceMap: buildOptions.sourcemaps } - }]; - } - - const test = AngularCompilerPlugin.isSupported() - ? /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/ - : /\.ts$/; - - return { - module: { rules: [{ test, use: [...boLoader, webpackLoader] }] }, - plugins: [ _createAotPlugin(wco, pluginOptions) ] - }; -} - -export function getNonAotTestConfig(wco: WebpackConfigOptions) { - const { projectRoot, appConfig } = wco; - const tsConfigPath = path.resolve(projectRoot, appConfig.root, appConfig.testTsconfig); - const appTsConfigPath = path.resolve(projectRoot, appConfig.root, appConfig.tsconfig); - - let pluginOptions: any = { tsConfigPath, skipCodeGeneration: true }; - - if (AngularCompilerPlugin.isSupported()) { - if (appConfig.polyfills) { - // TODO: remove singleFileIncludes for 2.0, this is just to support old projects that did not - // include 'polyfills.ts' in `tsconfig.spec.json'. - const polyfillsPath = path.resolve(projectRoot, appConfig.root, appConfig.polyfills); - pluginOptions.singleFileIncludes = [polyfillsPath]; - } - } else { - // The options below only apply to AoTPlugin. - // Force include main and polyfills. - // This is needed for AngularCompilerPlugin compatibility with existing projects, - // since TS compilation there is stricter and tsconfig.spec.ts doesn't include them. - const include = [appConfig.main, appConfig.polyfills, '**/*.spec.ts']; - if (appConfig.test) { - include.push(appConfig.test); - } - - pluginOptions.include = include; - - // Fallback to correct module format on projects using a shared tsconfig. - if (tsConfigPath === appTsConfigPath) { - pluginOptions.compilerOptions = { module: 'commonjs' }; - } - } - - return { - module: { rules: [{ test: /\.ts$/, loader: webpackLoader }] }, - plugins: [ _createAotPlugin(wco, pluginOptions, false) ] - }; -} diff --git a/packages/@angular/cli/models/webpack-configs/utils.ts b/packages/@angular/cli/models/webpack-configs/utils.ts deleted file mode 100644 index 8679dc5a81cf..000000000000 --- a/packages/@angular/cli/models/webpack-configs/utils.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as path from 'path'; - -export const ngAppResolve = (resolvePath: string): string => { - return path.resolve(process.cwd(), resolvePath); -}; - -const webpackOutputOptions = { - colors: true, - hash: true, - timings: true, - chunks: true, - chunkModules: false, - children: false, // listing all children is very noisy in AOT and hides warnings/errors - modules: false, - reasons: false, - warnings: true, - assets: false, // listing all assets is very noisy when using assets directories - version: false -}; - -const verboseWebpackOutputOptions = { - children: true, - assets: true, - version: true, - reasons: true, - chunkModules: false // TODO: set to true when console to file output is fixed -}; - -export function getWebpackStatsConfig(verbose = false) { - return verbose - ? Object.assign(webpackOutputOptions, verboseWebpackOutputOptions) - : webpackOutputOptions; -} - -export interface ExtraEntry { - input: string; - output?: string; - lazy?: boolean; - path?: string; - entry?: string; -} - -// Filter extra entries out of a arran of extraEntries -export function lazyChunksFilter(extraEntries: ExtraEntry[]) { - return extraEntries - .filter(extraEntry => extraEntry.lazy) - .map(extraEntry => extraEntry.entry); -} - -// convert all extra entries into the object representation, fill in defaults -export function extraEntryParser( - extraEntries: (string | ExtraEntry)[], - appRoot: string, - defaultEntry: string -): ExtraEntry[] { - return extraEntries - .map((extraEntry: string | ExtraEntry) => - typeof extraEntry === 'string' ? { input: extraEntry } : extraEntry) - .map((extraEntry: ExtraEntry) => { - extraEntry.path = path.resolve(appRoot, extraEntry.input); - if (extraEntry.output) { - extraEntry.entry = extraEntry.output.replace(/\.(js|css)$/i, ''); - } else if (extraEntry.lazy) { - extraEntry.entry = extraEntry.input.replace(/\.(js|css|scss|sass|less|styl)$/i, ''); - } else { - extraEntry.entry = defaultEntry; - } - return extraEntry; - }); -} - -export interface HashFormat { - chunk: string; - extract: string; - file: string; - script: string; -} - -export function getOutputHashFormat(option: string, length = 20): HashFormat { - /* tslint:disable:max-line-length */ - const hashFormats: { [option: string]: HashFormat } = { - none: { chunk: '', extract: '', file: '' , script: '' }, - media: { chunk: '', extract: '', file: `.[hash:${length}]`, script: '' }, - bundles: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: '' , script: '.[hash]' }, - all: { chunk: `.[chunkhash:${length}]`, extract: `.[contenthash:${length}]`, file: `.[hash:${length}]`, script: '.[hash]' }, - }; - /* tslint:enable:max-line-length */ - return hashFormats[option] || hashFormats['none']; -} - -export interface AssetPattern { - glob: string; - input?: string; - output?: string; - allowOutsideOutDir?: boolean; -} diff --git a/packages/@angular/cli/models/webpack-configs/xi18n.ts b/packages/@angular/cli/models/webpack-configs/xi18n.ts deleted file mode 100644 index 651e018d96c4..000000000000 --- a/packages/@angular/cli/models/webpack-configs/xi18n.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as path from 'path'; -import {ExtractI18nPlugin} from '@ngtools/webpack'; - -export const getWebpackExtractI18nConfig = function( - projectRoot: string, - appConfig: any, - genDir: string, - i18nFormat: string, - locale: string, - outFile: string): any { - - let exclude: string[] = []; - if (appConfig.test) { - exclude.push(path.join(projectRoot, appConfig.root, appConfig.test)); - } - - return { - plugins: [ - new ExtractI18nPlugin({ - tsConfigPath: path.resolve(projectRoot, appConfig.root, appConfig.tsconfig), - exclude: exclude, - genDir: genDir, - i18nFormat: i18nFormat, - locale: locale, - outFile: outFile, - }) - ] - }; -}; diff --git a/packages/@angular/cli/models/webpack-test-config.ts b/packages/@angular/cli/models/webpack-test-config.ts deleted file mode 100644 index 4847293867e1..000000000000 --- a/packages/@angular/cli/models/webpack-test-config.ts +++ /dev/null @@ -1,33 +0,0 @@ -const webpackMerge = require('webpack-merge'); - -import { BuildOptions } from './build-options'; -import { NgCliWebpackConfig } from './webpack-config'; -import { - getCommonConfig, - getStylesConfig, - getNonAotTestConfig, - getTestConfig -} from './webpack-configs'; - -export interface WebpackTestOptions extends BuildOptions { - codeCoverage?: boolean; -} -export class WebpackTestConfig extends NgCliWebpackConfig { - constructor(testOptions: WebpackTestOptions, appConfig: any) { - super(testOptions, appConfig); - } - - public buildConfig() { - const webpackConfigs = [ - getCommonConfig(this.wco), - getStylesConfig(this.wco), - this.getTargetConfig(this.wco), - getNonAotTestConfig(this.wco), - getTestConfig(this.wco) - ]; - - this.config = webpackMerge(webpackConfigs); - - return this.config; - } -} diff --git a/packages/@angular/cli/models/webpack-xi18n-config.ts b/packages/@angular/cli/models/webpack-xi18n-config.ts deleted file mode 100644 index 62e144f8fec6..000000000000 --- a/packages/@angular/cli/models/webpack-xi18n-config.ts +++ /dev/null @@ -1,55 +0,0 @@ -import * as path from 'path'; - -import {CliConfig} from './config'; -import {NgCliWebpackConfig} from './webpack-config'; -const webpackMerge = require('webpack-merge'); -import {getWebpackExtractI18nConfig} from './webpack-configs'; - -export interface XI18WebpackOptions { - genDir?: string; - buildDir?: string; - i18nFormat?: string; - locale?: string; - outFile?: string; - verbose?: boolean; - progress?: boolean; - app?: string; - aot?: boolean; -} -export class XI18nWebpackConfig extends NgCliWebpackConfig { - - public config: any; - - constructor(public extractOptions: XI18WebpackOptions, public appConfig: any) { - - super({ - target: 'development', - verbose: extractOptions.verbose, - progress: extractOptions.progress, - locale: extractOptions.locale, - i18nOutFormat: extractOptions.i18nFormat, - i18nOutFile: extractOptions.outFile, - aot: extractOptions.aot - }, appConfig); - super.buildConfig(); - } - - public buildConfig() { - // The extra extraction config is only needed in Angular 2/4. - if (!this.extractOptions.aot) { - const configPath = CliConfig.configFilePath(); - const projectRoot = path.dirname(configPath); - - const extractI18nConfig = - getWebpackExtractI18nConfig(projectRoot, - this.appConfig, - this.extractOptions.genDir, - this.extractOptions.i18nFormat, - this.extractOptions.locale, - this.extractOptions.outFile); - - this.config = webpackMerge([this.config, extractI18nConfig]); - } - return this.config; - } -} diff --git a/packages/@angular/cli/package.json b/packages/@angular/cli/package.json deleted file mode 100644 index 9de573893fa1..000000000000 --- a/packages/@angular/cli/package.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "name": "@angular/cli", - "version": "1.6.0-beta.2", - "description": "CLI tool for Angular", - "main": "lib/cli/index.js", - "trackingCode": "UA-8594346-19", - "bin": { - "ng": "./bin/ng" - }, - "keywords": [ - "angular", - "angular-cli", - "Angular CLI" - ], - "repository": { - "type": "git", - "url": "https://github.com/angular/angular-cli.git" - }, - "engines": { - "node": ">= 6.9.0", - "npm": ">= 3.0.0" - }, - "author": "Angular Authors", - "license": "MIT", - "bugs": { - "url": "https://github.com/angular/angular-cli/issues" - }, - "homepage": "https://github.com/angular/angular-cli", - "dependencies": { - "@angular-devkit/build-optimizer": "~0.0.31", - "@angular-devkit/schematics": "~0.0.34", - "@ngtools/json-schema": "1.1.0", - "@ngtools/webpack": "1.9.0-beta.2", - "@schematics/angular": "~0.1.5", - "autoprefixer": "^6.5.3", - "chalk": "~2.2.0", - "circular-dependency-plugin": "^3.0.0", - "common-tags": "^1.3.1", - "copy-webpack-plugin": "^4.1.1", - "core-object": "^3.1.0", - "css-loader": "^0.28.1", - "cssnano": "^3.10.0", - "denodeify": "^1.2.1", - "ember-cli-string-utils": "^1.0.0", - "exports-loader": "^0.6.3", - "extract-text-webpack-plugin": "3.0.0", - "file-loader": "^1.1.5", - "fs-extra": "^4.0.0", - "glob": "^7.0.3", - "html-webpack-plugin": "^2.29.0", - "karma-source-map-support": "^1.2.0", - "less": "^2.7.2", - "less-loader": "^4.0.5", - "license-webpack-plugin": "^1.0.0", - "lodash": "^4.11.1", - "memory-fs": "^0.4.1", - "minimatch": "^3.0.4", - "node-modules-path": "^1.0.0", - "nopt": "^4.0.1", - "opn": "~5.1.0", - "portfinder": "~1.0.12", - "postcss-custom-properties": "^6.1.0", - "postcss-loader": "^2.0.8", - "postcss-url": "^7.1.2", - "raw-loader": "^0.5.1", - "resolve": "^1.1.7", - "rxjs": "^5.5.2", - "sass-loader": "^6.0.3", - "semver": "^5.1.0", - "silent-error": "^1.0.0", - "source-map-loader": "^0.2.0", - "source-map-support": "^0.4.1", - "istanbul-instrumenter-loader": "^2.0.0", - "style-loader": "^0.13.1", - "stylus": "^0.54.5", - "stylus-loader": "^3.0.1", - "uglifyjs-webpack-plugin": "1.0.0", - "url-loader": "^0.6.2", - "webpack": "~3.8.1", - "webpack-concat-plugin": "1.4.0", - "webpack-dev-middleware": "~1.12.0", - "webpack-dev-server": "~2.9.3", - "webpack-merge": "^4.1.0", - "webpack-sources": "^1.0.0", - "webpack-subresource-integrity": "^1.0.1", - "zone.js": "^0.8.14" - }, - "optionalDependencies": { - "node-sass": "^4.3.0" - } -} diff --git a/packages/@angular/cli/plugins/glob-copy-webpack-plugin.ts b/packages/@angular/cli/plugins/glob-copy-webpack-plugin.ts deleted file mode 100644 index 28c67b917e3f..000000000000 --- a/packages/@angular/cli/plugins/glob-copy-webpack-plugin.ts +++ /dev/null @@ -1,93 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as glob from 'glob'; -import * as denodeify from 'denodeify'; -import { AssetPattern } from '../models/webpack-configs/utils'; -import { isDirectory } from '../utilities/is-directory'; - -const flattenDeep = require('lodash/flattenDeep'); -const globPromise = denodeify(glob); -const statPromise = denodeify(fs.stat); - -interface Asset { - originPath: string; - destinationPath: string; - relativePath: string; -} - -export interface GlobCopyWebpackPluginOptions { - patterns: (string | AssetPattern)[]; - globOptions: any; -} - -// Adds an asset to the compilation assets; -function addAsset(compilation: any, asset: Asset) { - const realPath = path.resolve(asset.originPath, asset.relativePath); - // Make sure that asset keys use forward slashes, otherwise webpack dev server - const servedPath = path.join(asset.destinationPath, asset.relativePath).replace(/\\/g, '/'); - - // Don't re-add existing assets. - if (compilation.assets[servedPath]) { - return Promise.resolve(); - } - - // Read file and add it to assets; - return statPromise(realPath) - .then((stat: any) => compilation.assets[servedPath] = { - size: () => stat.size, - source: () => fs.readFileSync(realPath) - }); -} - -export class GlobCopyWebpackPlugin { - constructor(private options: GlobCopyWebpackPluginOptions) { } - - apply(compiler: any): void { - let { patterns, globOptions } = this.options; - const defaultCwd = globOptions.cwd || compiler.options.context; - - // Force nodir option, since we can't add dirs to assets. - globOptions.nodir = true; - - // Process patterns. - patterns = patterns.map(pattern => { - // Convert all string patterns to Pattern type. - pattern = typeof pattern === 'string' ? { glob: pattern } : pattern; - // Add defaults - // Input is always resolved relative to the defaultCwd (appRoot) - pattern.input = path.resolve(defaultCwd, pattern.input || ''); - pattern.output = pattern.output || ''; - pattern.glob = pattern.glob || ''; - // Convert dir patterns to globs. - if (isDirectory(path.resolve(pattern.input, pattern.glob))) { - pattern.glob = pattern.glob + '/**/*'; - } - return pattern; - }); - - compiler.plugin('emit', (compilation: any, cb: any) => { - // Create an array of promises for each pattern glob - const globs = patterns.map((pattern: AssetPattern) => new Promise((resolve, reject) => - // Individual patterns can override cwd - globPromise(pattern.glob, Object.assign({}, globOptions, { cwd: pattern.input })) - // Map the results onto an Asset - .then((globResults: string[]) => globResults.map(res => ({ - originPath: pattern.input, - destinationPath: pattern.output, - relativePath: res - }))) - .then((asset: Asset) => resolve(asset)) - .catch(reject) - )); - - // Wait for all globs. - Promise.all(globs) - // Flatten results. - .then(assets => flattenDeep(assets)) - // Add each asset to the compilation. - .then(assets => - Promise.all(assets.map((asset: Asset) => addAsset(compilation, asset)))) - .then(() => cb()); - }); - } -} diff --git a/packages/@angular/cli/plugins/insert-concat-assets-webpack-plugin.ts b/packages/@angular/cli/plugins/insert-concat-assets-webpack-plugin.ts deleted file mode 100644 index 039c0afafd00..000000000000 --- a/packages/@angular/cli/plugins/insert-concat-assets-webpack-plugin.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Add assets from `ConcatPlugin` to index.html. - - -export class InsertConcatAssetsWebpackPlugin { - // Priority list of where to insert asset. - private insertAfter = [ - /polyfills(\.[0-9a-f]{20})?\.bundle\.js/, - /inline(\.[0-9a-f]{20})?\.bundle\.js/, - ]; - - constructor(private entryNames: string[]) { } - - apply(compiler: any): void { - compiler.plugin('compilation', (compilation: any) => { - compilation.plugin('html-webpack-plugin-before-html-generation', - (htmlPluginData: any, callback: any) => { - - const fileNames = this.entryNames.map((entryName) => { - const fileName = htmlPluginData.assets.webpackConcat - && htmlPluginData.assets.webpackConcat[entryName]; - - if (!fileName) { - // Something went wrong and the asset was not correctly added. - throw new Error(`Cannot find file for ${entryName} script.`); - } - - if (htmlPluginData.assets.publicPath) { - if (htmlPluginData.assets.publicPath.endsWith('/')) { - return htmlPluginData.assets.publicPath + fileName; - } - return htmlPluginData.assets.publicPath + '/' + fileName; - } - return fileName; - }); - - let insertAt = 0; - - // TODO: try to figure out if there are duplicate bundle names when adding and throw - for (let el of this.insertAfter) { - const jsIdx = htmlPluginData.assets.js.findIndex((js: string) => js.match(el)); - if (jsIdx !== -1) { - insertAt = jsIdx + 1; - break; - } - } - - htmlPluginData.assets.js.splice(insertAt, 0, ...fileNames); - callback(null, htmlPluginData); - }); - }); - } -} diff --git a/packages/@angular/cli/plugins/karma-context.html b/packages/@angular/cli/plugins/karma-context.html deleted file mode 100644 index 1c8f49c653f5..000000000000 --- a/packages/@angular/cli/plugins/karma-context.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - - - - - - - - - - - - %SCRIPTS% - - - - - - - diff --git a/packages/@angular/cli/plugins/karma-debug.html b/packages/@angular/cli/plugins/karma-debug.html deleted file mode 100644 index 649d59817e04..000000000000 --- a/packages/@angular/cli/plugins/karma-debug.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - -%X_UA_COMPATIBLE% - Karma DEBUG RUNNER - - - - - - - - - - - - - - %SCRIPTS% - - - - - - - diff --git a/packages/@angular/cli/plugins/karma-webpack-throw-error.ts b/packages/@angular/cli/plugins/karma-webpack-throw-error.ts deleted file mode 100644 index 601e1ec4c79f..000000000000 --- a/packages/@angular/cli/plugins/karma-webpack-throw-error.ts +++ /dev/null @@ -1,14 +0,0 @@ -// Force Webpack to throw compilation errors. Useful with karma-webpack when in single-run mode. -// Workaround for https://github.com/webpack-contrib/karma-webpack/issues/66 - -export class KarmaWebpackThrowError { - constructor() { } - - apply(compiler: any): void { - compiler.plugin('done', (stats: any) => { - if (stats.compilation.errors.length > 0) { - throw new Error(stats.compilation.errors.map((err: any) => err.message || err)); - } - }); - } -} diff --git a/packages/@angular/cli/plugins/karma.ts b/packages/@angular/cli/plugins/karma.ts deleted file mode 100644 index ad893a5fadb5..000000000000 --- a/packages/@angular/cli/plugins/karma.ts +++ /dev/null @@ -1,270 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs'; -import * as glob from 'glob'; -import * as webpack from 'webpack'; -const webpackDevMiddleware = require('webpack-dev-middleware'); - -import { AssetPattern } from '../models/webpack-configs/utils'; -import { isDirectory } from '../utilities/is-directory'; -import { WebpackTestConfig, WebpackTestOptions } from '../models/webpack-test-config'; -import { KarmaWebpackThrowError } from './karma-webpack-throw-error'; - -/** - * Enumerate needed (but not require/imported) dependencies from this file - * to let the dependency validator know they are used. - * - * require('source-map-support') - * require('karma-source-map-support') - */ - - -const getAppFromConfig = require('../utilities/app-utils').getAppFromConfig; - -let blocked: any[] = []; -let isBlocked = false; - -// Add files to the Karma files array. -function addKarmaFiles(files: any[], newFiles: any[], prepend = false) { - const defaults = { - included: true, - served: true, - watched: true - }; - - const processedFiles = newFiles - // Remove globs that do not match any files, otherwise Karma will show a warning for these. - .filter(file => glob.sync(file.pattern, { nodir: true }).length != 0) - // Fill in pattern properties with defaults. - .map(file => ({ ...defaults, ...file })); - - // It's important to not replace the array, because - // karma already has a reference to the existing array. - if (prepend) { - files.unshift(...processedFiles); - } else { - files.push(...processedFiles); - } -} - -const init: any = (config: any, emitter: any, customFileHandlers: any) => { - const appConfig = getAppFromConfig(config.angularCli.app); - const appRoot = path.join(config.basePath, appConfig.root); - const testConfig: WebpackTestOptions = Object.assign({ - environment: 'dev', - codeCoverage: false, - sourcemaps: true, - progress: true, - preserveSymlinks: false, - }, config.angularCli); - - if (testConfig.sourcemaps) { - // Add a reporter that fixes sourcemap urls. - config.reporters.unshift('@angular/cli'); - - // Code taken from https://github.com/tschaub/karma-source-map-support. - // We can't use it directly because we need to add it conditionally in this file, and karma - // frameworks cannot be added dynamically. - const smsPath = path.dirname(require.resolve('source-map-support')); - const ksmsPath = path.dirname(require.resolve('karma-source-map-support')); - - addKarmaFiles(config.files, [ - { pattern: path.join(smsPath, 'browser-source-map-support.js'), watched: false }, - { pattern: path.join(ksmsPath, 'client.js'), watched: false } - ], true); - } - - // Add assets. This logic is mimics the one present in GlobCopyWebpackPlugin. - if (appConfig.assets) { - config.proxies = config.proxies || {}; - appConfig.assets.forEach((pattern: AssetPattern) => { - // Convert all string patterns to Pattern type. - pattern = typeof pattern === 'string' ? { glob: pattern } : pattern; - // Add defaults. - // Input is always resolved relative to the appRoot. - pattern.input = path.resolve(appRoot, pattern.input || ''); - pattern.output = pattern.output || ''; - pattern.glob = pattern.glob || ''; - - // Build karma file pattern. - const assetPath = path.join(pattern.input, pattern.glob); - const filePattern = isDirectory(assetPath) ? assetPath + '/**' : assetPath; - addKarmaFiles(config.files, [{ pattern: filePattern, included: false }]); - - // The `files` entry serves the file from `/base/{asset.input}/{asset.glob}`. - // We need to add a URL rewrite that exposes the asset as `/{asset.output}/{asset.glob}`. - let relativePath: string, proxyPath: string; - if (fs.existsSync(assetPath)) { - relativePath = path.relative(config.basePath, assetPath); - proxyPath = path.join(pattern.output, pattern.glob); - } else { - // For globs (paths that don't exist), proxy pattern.output to pattern.input. - relativePath = path.relative(config.basePath, pattern.input); - proxyPath = path.join(pattern.output); - - } - // Proxy paths must have only forward slashes. - proxyPath = proxyPath.replace(/\\/g, '/'); - config.proxies['/' + proxyPath] = '/base/' + relativePath; - }); - } - - // Add webpack config. - const webpackConfig = new WebpackTestConfig(testConfig, appConfig).buildConfig(); - const webpackMiddlewareConfig = { - noInfo: true, // Hide webpack output because its noisy. - watchOptions: { poll: testConfig.poll }, - publicPath: '/_karma_webpack_/', - stats: { // Also prevent chunk and module display output, cleaner look. Only emit errors. - assets: false, - colors: true, - version: false, - hash: false, - timings: false, - chunks: false, - chunkModules: false - } - }; - - // If Karma is being ran in single run mode, throw errors. - if (config.singleRun) { - webpackConfig.plugins.push(new KarmaWebpackThrowError()); - } - - // Use existing config if any. - config.webpack = Object.assign(webpackConfig, config.webpack); - config.webpackMiddleware = Object.assign(webpackMiddlewareConfig, config.webpackMiddleware); - - // Remove the @angular/cli test file if present, for backwards compatibility. - const testFilePath = path.join(appRoot, appConfig.test); - config.files.forEach((file: any, index: number) => { - if (path.normalize(file.pattern) === testFilePath) { - config.files.splice(index, 1); - } - }); - - // When using code-coverage, auto-add coverage-istanbul. - config.reporters = config.reporters || []; - if (testConfig.codeCoverage && config.reporters.indexOf('coverage-istanbul') === -1) { - config.reporters.push('coverage-istanbul'); - } - - // Our custom context and debug files list the webpack bundles directly instead of using - // the karma files array. - config.customContextFile = `${__dirname}/karma-context.html`; - config.customDebugFile = `${__dirname}/karma-debug.html`; - - // Add the request blocker. - config.beforeMiddleware = config.beforeMiddleware || []; - config.beforeMiddleware.push('angularCliBlocker'); - - // Delete global styles entry, we don't want to load them. - delete webpackConfig.entry.styles; - - // The webpack tier owns the watch behavior so we want to force it in the config. - webpackConfig.watch = true; - // Files need to be served from a custom path for Karma. - webpackConfig.output.path = '/_karma_webpack_/'; - webpackConfig.output.publicPath = '/_karma_webpack_/'; - - let compiler: any; - try { - compiler = webpack(webpackConfig); - } catch (e) { - console.error(e.stack || e); - if (e.details) { - console.error(e.details); - } - throw e; - } - - ['invalid', 'watch-run', 'run'].forEach(function (name) { - compiler.plugin(name, function (_: any, callback: () => void) { - isBlocked = true; - - if (typeof callback === 'function') { - callback(); - } - }); - }); - - compiler.plugin('done', (stats: any) => { - // Don't refresh karma when there are webpack errors. - if (stats.compilation.errors.length === 0) { - emitter.refreshFiles(); - isBlocked = false; - blocked.forEach((cb) => cb()); - blocked = []; - } - }); - - const middleware = new webpackDevMiddleware(compiler, webpackMiddlewareConfig); - - // Forward requests to webpack server. - customFileHandlers.push({ - urlRegex: /^\/_karma_webpack_\/.*/, - handler: function handler(req: any, res: any) { - middleware(req, res, function () { - // Ensure script and style bundles are served. - // They are mentioned in the custom karma context page and we don't want them to 404. - const alwaysServe = [ - '/_karma_webpack_/inline.bundle.js', - '/_karma_webpack_/polyfills.bundle.js', - '/_karma_webpack_/scripts.bundle.js', - '/_karma_webpack_/vendor.bundle.js', - ]; - if (alwaysServe.indexOf(req.url) != -1) { - res.statusCode = 200; - res.end(); - } else { - res.statusCode = 404; - res.end('Not found'); - } - }); - } - }); - - emitter.on('exit', (done: any) => { - middleware.close(); - done(); - }); -}; - -init.$inject = ['config', 'emitter', 'customFileHandlers']; - -// Dummy preprocessor, just to keep karma from showing a warning. -const preprocessor: any = () => (content: any, _file: string, done: any) => done(null, content); -preprocessor.$inject = []; - -// Block requests until the Webpack compilation is done. -function requestBlocker() { - return function (_request: any, _response: any, next: () => void) { - if (isBlocked) { - blocked.push(next); - } else { - next(); - } - }; -} - -// Strip the server address and webpack scheme (webpack://) from error log. -const initSourcemapReporter: any = function (baseReporterDecorator: any) { - baseReporterDecorator(this); - const urlRegexp = /\(http:\/\/localhost:\d+\/_karma_webpack_\/webpack:\//gi; - - this.onSpecComplete = function (_browser: any, result: any) { - if (!result.success && result.log.length > 0) { - result.log.forEach((log: string, idx: number) => { - result.log[idx] = log.replace(urlRegexp, ''); - }); - } - }; -}; - -initSourcemapReporter.$inject = ['baseReporterDecorator']; - -module.exports = Object.assign({ - 'framework:@angular/cli': ['factory', init], - 'preprocessor:@angular/cli': ['factory', preprocessor], - 'reporter:@angular/cli': ['type', initSourcemapReporter], - 'middleware:angularCliBlocker': ['factory', requestBlocker] -}); diff --git a/packages/@angular/cli/plugins/named-lazy-chunks-webpack-plugin.ts b/packages/@angular/cli/plugins/named-lazy-chunks-webpack-plugin.ts deleted file mode 100644 index 13cb9e4b0c1c..000000000000 --- a/packages/@angular/cli/plugins/named-lazy-chunks-webpack-plugin.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as webpack from 'webpack'; -import { basename } from 'path'; -const AsyncDependenciesBlock = require('webpack/lib/AsyncDependenciesBlock'); -const ContextElementDependency = require('webpack/lib/dependencies/ContextElementDependency'); -const ImportDependency = require('webpack/lib/dependencies/ImportDependency'); - -// This just extends webpack.NamedChunksPlugin to prevent name collisions. -export class NamedLazyChunksWebpackPlugin extends webpack.NamedChunksPlugin { - constructor() { - // Append a dot and number if the name already exists. - const nameMap = new Map(); - function getUniqueName(baseName: string, request: string) { - let name = baseName; - let num = 0; - while (nameMap.has(name) && nameMap.get(name) !== request) { - name = `${baseName}.${num++}`; - } - nameMap.set(name, request); - return name; - } - - const nameResolver = (chunk: any) => { - // Entry chunks have a name already, use it. - if (chunk.name) { - return chunk.name; - } - - // Try to figure out if it's a lazy loaded route or import(). - if (chunk.blocks - && chunk.blocks.length > 0 - && chunk.blocks[0] instanceof AsyncDependenciesBlock - && chunk.blocks[0].dependencies.length === 1 - && (chunk.blocks[0].dependencies[0] instanceof ContextElementDependency - || chunk.blocks[0].dependencies[0] instanceof ImportDependency) - ) { - // Create chunkname from file request, stripping ngfactory and extension. - const request = chunk.blocks[0].dependencies[0].request; - const chunkName = basename(request).replace(/(\.ngfactory)?\.(js|ts)$/, ''); - if (!chunkName || chunkName === '') { - // Bail out if something went wrong with the name. - return null; - } - return getUniqueName(chunkName, request); - } - - return null; - }; - - super(nameResolver); - } -} diff --git a/packages/@angular/cli/plugins/static-asset.ts b/packages/@angular/cli/plugins/static-asset.ts deleted file mode 100644 index 39a0fc1fe3bb..000000000000 --- a/packages/@angular/cli/plugins/static-asset.ts +++ /dev/null @@ -1,14 +0,0 @@ -export class StaticAssetPlugin { - - constructor(private name: string, private contents: string) {} - - apply(compiler: any): void { - compiler.plugin('emit', (compilation: any, cb: Function) => { - compilation.assets[this.name] = { - size: () => this.contents.length, - source: () => this.contents, - }; - cb(); - }); - } -} diff --git a/packages/@angular/cli/plugins/suppress-entry-chunks-webpack-plugin.ts b/packages/@angular/cli/plugins/suppress-entry-chunks-webpack-plugin.ts deleted file mode 100644 index 497e73b33320..000000000000 --- a/packages/@angular/cli/plugins/suppress-entry-chunks-webpack-plugin.ts +++ /dev/null @@ -1,52 +0,0 @@ -// Remove .js files from entry points consisting entirely of .css|scss|sass|less|styl. -// To be used together with ExtractTextPlugin. - -export class SuppressExtractedTextChunksWebpackPlugin { - constructor() { } - - apply(compiler: any): void { - compiler.plugin('compilation', function (compilation: any) { - // find which chunks have css only entry points - const cssOnlyChunks: string[] = []; - const entryPoints = compilation.options.entry; - // determine which entry points are composed entirely of css files - for (let entryPoint of Object.keys(entryPoints)) { - let entryFiles: string[]|string = entryPoints[entryPoint]; - // when type of entryFiles is not array, make it as an array - entryFiles = entryFiles instanceof Array ? entryFiles : [entryFiles]; - if (entryFiles.every((el: string) => - el.match(/\.(css|scss|sass|less|styl)$/) !== null)) { - cssOnlyChunks.push(entryPoint); - } - } - // Remove the js file for supressed chunks - compilation.plugin('after-seal', (callback: any) => { - compilation.chunks - .filter((chunk: any) => cssOnlyChunks.indexOf(chunk.name) !== -1) - .forEach((chunk: any) => { - let newFiles: string[] = []; - chunk.files.forEach((file: string) => { - if (file.match(/\.js(\.map)?$/)) { - // remove js files - delete compilation.assets[file]; - } else { - newFiles.push(file); - } - }); - chunk.files = newFiles; - }); - callback(); - }); - // Remove scripts tags with a css file as source, because HtmlWebpackPlugin will use - // a css file as a script for chunks without js files. - compilation.plugin('html-webpack-plugin-alter-asset-tags', - (htmlPluginData: any, callback: any) => { - const filterFn = (tag: any) => - !(tag.tagName === 'script' && tag.attributes.src.match(/\.css$/)); - htmlPluginData.head = htmlPluginData.head.filter(filterFn); - htmlPluginData.body = htmlPluginData.body.filter(filterFn); - callback(null, htmlPluginData); - }); - }); - } -} diff --git a/packages/@angular/cli/plugins/webpack.ts b/packages/@angular/cli/plugins/webpack.ts deleted file mode 100644 index a51f71eff8d4..000000000000 --- a/packages/@angular/cli/plugins/webpack.ts +++ /dev/null @@ -1,6 +0,0 @@ -// Exports the webpack plugins we use internally. -export { BaseHrefWebpackPlugin } from '../lib/base-href-webpack/base-href-webpack-plugin'; -export { GlobCopyWebpackPlugin, GlobCopyWebpackPluginOptions } from './glob-copy-webpack-plugin'; -export { InsertConcatAssetsWebpackPlugin } from './insert-concat-assets-webpack-plugin'; -export { NamedLazyChunksWebpackPlugin } from './named-lazy-chunks-webpack-plugin'; -export { SuppressExtractedTextChunksWebpackPlugin } from './suppress-entry-chunks-webpack-plugin'; diff --git a/packages/@angular/cli/tasks/build.ts b/packages/@angular/cli/tasks/build.ts deleted file mode 100644 index 580de6845d3b..000000000000 --- a/packages/@angular/cli/tasks/build.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as webpack from 'webpack'; - -import { getAppFromConfig } from '../utilities/app-utils'; -import { BuildTaskOptions } from '../commands/build'; -import { NgCliWebpackConfig } from '../models/webpack-config'; -import { getWebpackStatsConfig } from '../models/webpack-configs/utils'; -import { CliConfig } from '../models/config'; -import { statsToString, statsWarningsToString, statsErrorsToString } from '../utilities/stats'; -import { augmentAppWithServiceWorker, usesServiceWorker } from '../utilities/service-worker'; - -const Task = require('../ember-cli/lib/models/task'); -const SilentError = require('silent-error'); - - -export default Task.extend({ - run: function (runTaskOptions: BuildTaskOptions) { - const config = CliConfig.fromProject().config; - - const app = getAppFromConfig(runTaskOptions.app); - - const outputPath = runTaskOptions.outputPath || app.outDir; - if (this.project.root === path.resolve(outputPath)) { - throw new SilentError('Output path MUST not be project root directory!'); - } - if (config.project && config.project.ejected) { - throw new SilentError('An ejected project cannot use the build command anymore.'); - } - if (! app.main) { - throw new SilentError(`An app without 'main' cannot use the build command.`); - } - if (runTaskOptions.deleteOutputPath) { - fs.removeSync(path.resolve(this.project.root, outputPath)); - } - - const webpackConfig = new NgCliWebpackConfig(runTaskOptions, app).buildConfig(); - const webpackCompiler = webpack(webpackConfig); - const statsConfig = getWebpackStatsConfig(runTaskOptions.verbose); - - return new Promise((resolve, reject) => { - const callback: webpack.compiler.CompilerCallback = (err, stats) => { - if (err) { - return reject(err); - } - - const json = stats.toJson('verbose'); - if (runTaskOptions.verbose) { - this.ui.writeLine(stats.toString(statsConfig)); - } else { - this.ui.writeLine(statsToString(json, statsConfig)); - } - - if (stats.hasWarnings()) { - this.ui.writeLine(statsWarningsToString(json, statsConfig)); - } - if (stats.hasErrors()) { - this.ui.writeError(statsErrorsToString(json, statsConfig)); - } - - if (runTaskOptions.watch) { - return; - } else if (runTaskOptions.statsJson) { - fs.writeFileSync( - path.resolve(this.project.root, outputPath, 'stats.json'), - JSON.stringify(stats.toJson(), null, 2) - ); - } - - if (stats.hasErrors()) { - reject(); - } else { - if (!!app.serviceWorker && runTaskOptions.target === 'production' && - usesServiceWorker(this.project.root) && runTaskOptions.serviceWorker !== false) { - const appRoot = path.resolve(this.project.root, app.root); - augmentAppWithServiceWorker(this.project.root, appRoot, path.resolve(outputPath), - runTaskOptions.baseHref || '/') - .then(() => resolve(), (err: any) => reject(err)); - } else { - resolve(); - } - } - }; - - if (runTaskOptions.watch) { - webpackCompiler.watch({ poll: runTaskOptions.poll }, callback); - } else { - webpackCompiler.run(callback); - } - }) - .catch((err: Error) => { - if (err) { - this.ui.writeError('\nAn error occured during the build:\n' + ((err && err.stack) || err)); - } - throw err; - }); - } -}); diff --git a/packages/@angular/cli/tasks/doc.ts b/packages/@angular/cli/tasks/doc.ts deleted file mode 100644 index 1ce1346e84fa..000000000000 --- a/packages/@angular/cli/tasks/doc.ts +++ /dev/null @@ -1,11 +0,0 @@ -const Task = require('../ember-cli/lib/models/task'); -const opn = require('opn'); - -export const DocTask: any = Task.extend({ - run: function(keyword: string, search: boolean) { - const searchUrl = search ? `https://www.google.com/search?q=site%3Aangular.io+${keyword}` : - `https://angular.io/api?query=${keyword}`; - - return opn(searchUrl, { wait: false }); - } -}); diff --git a/packages/@angular/cli/tasks/e2e.ts b/packages/@angular/cli/tasks/e2e.ts deleted file mode 100644 index 40228aafeb83..000000000000 --- a/packages/@angular/cli/tasks/e2e.ts +++ /dev/null @@ -1,96 +0,0 @@ -import * as url from 'url'; -import { stripIndents } from 'common-tags'; - -import { E2eTaskOptions } from '../commands/e2e'; -import { CliConfig } from '../models/config'; -import { requireProjectModule } from '../utilities/require-project-module'; -import { getAppFromConfig } from '../utilities/app-utils'; - -const Task = require('../ember-cli/lib/models/task'); -const SilentError = require('silent-error'); - - -export const E2eTask = Task.extend({ - run: function (e2eTaskOptions: E2eTaskOptions) { - const projectConfig = CliConfig.fromProject().config; - const projectRoot = this.project.root; - const protractorLauncher = requireProjectModule(projectRoot, 'protractor/built/launcher'); - const appConfig = getAppFromConfig(e2eTaskOptions.app); - - if (projectConfig.project && projectConfig.project.ejected) { - throw new SilentError('An ejected project cannot use the build command anymore.'); - } - if (appConfig.platform === 'server') { - throw new SilentError('ng test for platform server applications is coming soon!'); - } - - return new Promise(function () { - let promise = Promise.resolve(); - let additionalProtractorConfig: any = { - elementExplorer: e2eTaskOptions.elementExplorer - }; - - // use serve url as override for protractors baseUrl - if (e2eTaskOptions.serve && e2eTaskOptions.publicHost) { - let publicHost = e2eTaskOptions.publicHost; - if (!/^\w+:\/\//.test(publicHost)) { - publicHost = `${e2eTaskOptions.ssl ? 'https' : 'http'}://${publicHost}`; - } - const clientUrl = url.parse(publicHost); - e2eTaskOptions.publicHost = clientUrl.host; - additionalProtractorConfig.baseUrl = url.format(clientUrl); - } else if (e2eTaskOptions.serve) { - additionalProtractorConfig.baseUrl = url.format({ - protocol: e2eTaskOptions.ssl ? 'https' : 'http', - hostname: e2eTaskOptions.host, - port: e2eTaskOptions.port.toString() - }); - } else if (e2eTaskOptions.baseHref) { - additionalProtractorConfig.baseUrl = e2eTaskOptions.baseHref; - } else if (e2eTaskOptions.port) { - additionalProtractorConfig.baseUrl = url.format({ - protocol: e2eTaskOptions.ssl ? 'https' : 'http', - hostname: e2eTaskOptions.host, - port: e2eTaskOptions.port.toString() - }); - } - - if (e2eTaskOptions.specs.length !== 0) { - additionalProtractorConfig['specs'] = e2eTaskOptions.specs; - } - - if (e2eTaskOptions.webdriverUpdate) { - // The webdriver-manager update command can only be accessed via a deep import. - const webdriverDeepImport = 'webdriver-manager/built/lib/cmds/update'; - let webdriverUpdate: any; - - try { - // When using npm, webdriver is within protractor/node_modules. - webdriverUpdate = requireProjectModule(projectRoot, - `protractor/node_modules/${webdriverDeepImport}`); - } catch (e) { - try { - // When using yarn, webdriver is found as a root module. - webdriverUpdate = requireProjectModule(projectRoot, webdriverDeepImport); - } catch (e) { - throw new SilentError(stripIndents` - Cannot automatically find webdriver-manager to update. - Update webdriver-manager manually and run 'ng e2e --no-webdriver-update' instead. - `); - } - } - // run `webdriver-manager update --standalone false --gecko false --quiet` - // if you change this, update the command comment in prev line, and in `eject` task - promise = promise.then(() => webdriverUpdate.program.run({ - standalone: false, - gecko: false, - quiet: true - })); - } - - // Don't call resolve(), protractor will manage exiting the process itself - return promise.then(() => - protractorLauncher.init(e2eTaskOptions.config, additionalProtractorConfig)); - }); - } -}); diff --git a/packages/@angular/cli/tasks/eject.ts b/packages/@angular/cli/tasks/eject.ts deleted file mode 100644 index a782ac21e640..000000000000 --- a/packages/@angular/cli/tasks/eject.ts +++ /dev/null @@ -1,632 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as webpack from 'webpack'; -import chalk from 'chalk'; - -import { getAppFromConfig } from '../utilities/app-utils'; -import { EjectTaskOptions } from '../commands/eject'; -import { NgCliWebpackConfig } from '../models/webpack-config'; -import { CliConfig } from '../models/config'; -import { stripBom } from '../utilities/strip-bom'; -import { AotPlugin, AngularCompilerPlugin } from '@ngtools/webpack'; -import { PurifyPlugin } from '@angular-devkit/build-optimizer'; -import { LicenseWebpackPlugin } from 'license-webpack-plugin'; - -import denodeify = require('denodeify'); -import {oneLine, stripIndent} from 'common-tags'; - -const exists = (p: string) => Promise.resolve(fs.existsSync(p)); -const writeFile = (denodeify(fs.writeFile) as (...args: any[]) => Promise); -const angularCliPlugins = require('../plugins/webpack'); - - -const ExtractTextPlugin = require('extract-text-webpack-plugin'); -const HtmlWebpackPlugin = require('html-webpack-plugin'); -const SubresourceIntegrityPlugin = require('webpack-subresource-integrity'); -const SilentError = require('silent-error'); -const CircularDependencyPlugin = require('circular-dependency-plugin'); -const ConcatPlugin = require('webpack-concat-plugin'); -const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); -const Task = require('../ember-cli/lib/models/task'); - -const ProgressPlugin = require('webpack/lib/ProgressPlugin'); - - -export const pluginArgs = Symbol('plugin-args'); -export const postcssArgs = Symbol('postcss-args'); - -const yellow = chalk.yellow; -const pree2eNpmScript = `webdriver-manager update --standalone false --gecko false --quiet`; - - -class JsonWebpackSerializer { - public imports: {[name: string]: string[]} = {}; - public variableImports: {[name: string]: string} = { - 'fs': 'fs', - 'path': 'path', - }; - public variables: {[name: string]: string} = { - 'nodeModules': `path.join(process.cwd(), 'node_modules')`, - 'realNodeModules': `fs.realpathSync(nodeModules)`, - 'genDirNodeModules': - `path.join(process.cwd(), '${this._appRoot}', '$$_gendir', 'node_modules')`, - }; - private _postcssProcessed = false; - - - constructor(private _root: string, private _dist: string, private _appRoot: string) {} - - private _escape(str: string) { - return '\uFF01' + str + '\uFF01'; - } - - private _serializeRegExp(re: RegExp) { - return this._escape(re.toString()); - } - - private _serializeFunction(fn: Function) { - return this._escape(fn.toString()); - } - - private _relativePath(of: string, to: string) { - return this._escape(`path.join(${of}, ${JSON.stringify(to)})`); - } - - private _addImport(module: string, importName: string) { - if (!this.imports[module]) { - this.imports[module] = []; - } - if (this.imports[module].indexOf(importName) == -1) { - this.imports[module].push(importName); - } - } - - private _globCopyWebpackPluginSerialize(value: any): any { - let patterns = value.options.patterns; - let globOptions = value.options.globOptions; - return { - patterns, - globOptions: this._globReplacer(globOptions) - }; - } - - private _insertConcatAssetsWebpackPluginSerialize(value: any): any { - return value.entryNames; - } - - private _commonsChunkPluginSerialize(value: any): any { - let minChunks = value.minChunks; - switch (typeof minChunks) { - case 'function': - minChunks = this._serializeFunction(value.minChunks); - break; - } - - return { - name: value.chunkNames, - filename: value.filenameTemplate, - minChunks, - chunks: value.selectedChunks, - async: value.async, - minSize: value.minSize - }; - } - - private _extractTextPluginSerialize(value: any): any { - return { - filename: value.filename, - disable: value.options.disable - }; - } - - private _aotPluginSerialize(value: AotPlugin): any { - const tsConfigPath = path.relative(this._root, value.options.tsConfigPath); - const basePath = path.dirname(tsConfigPath); - return Object.assign({}, value.options, { - tsConfigPath, - mainPath: path.relative(basePath, value.options.mainPath), - hostReplacementPaths: Object.keys(value.options.hostReplacementPaths) - .reduce((acc: any, key: string) => { - const replacementPath = value.options.hostReplacementPaths[key]; - key = path.relative(basePath, key); - acc[key] = path.relative(basePath, replacementPath); - return acc; - }, {}), - exclude: Array.isArray(value.options.exclude) - ? value.options.exclude.map((p: any) => { - return p.startsWith('/') ? path.relative(basePath, p) : p; - }) - : value.options.exclude - }); - } - - private _htmlWebpackPlugin(value: any) { - const chunksSortMode = value.options.chunksSortMode; - this.variables['entryPoints'] = JSON.stringify(chunksSortMode.entryPoints); - return Object.assign({}, value.options, { - template: './' + path.relative(this._root, value.options.template), - filename: './' + path.relative(this._dist, value.options.filename), - chunksSortMode: this._serializeFunction(chunksSortMode) - }); - } - - _environmentPlugin(plugin: any) { - return plugin.defaultValues; - } - - private _licenseWebpackPlugin(plugin: any) { - return plugin.options; - } - - private _concatPlugin(plugin: any) { - const options = plugin.settings; - if (!options || !options.filesToConcat) { - return options; - } - - const filesToConcat = options.filesToConcat - .map((file: string) => path.relative(process.cwd(), file)); - - return { ...options, filesToConcat }; - } - - private _uglifyjsPlugin(plugin: any) { - return plugin.options; - } - - private _pluginsReplacer(plugins: any[]) { - return plugins.map(plugin => { - let args = plugin.options || undefined; - const serializer = (args: any) => JSON.stringify(args, (k, v) => this._replacer(k, v), 2); - - switch (plugin.constructor) { - case ProgressPlugin: - this.variableImports['webpack/lib/ProgressPlugin'] = 'ProgressPlugin'; - break; - case webpack.NoEmitOnErrorsPlugin: - this._addImport('webpack', 'NoEmitOnErrorsPlugin'); - break; - case webpack.NamedModulesPlugin: - this._addImport('webpack', 'NamedModulesPlugin'); - break; - case (webpack).HashedModuleIdsPlugin: - this._addImport('webpack', 'HashedModuleIdsPlugin'); - break; - case webpack.SourceMapDevToolPlugin: - this._addImport('webpack', 'SourceMapDevToolPlugin'); - break; - case webpack.optimize.UglifyJsPlugin: - this._addImport('webpack.optimize', 'UglifyJsPlugin'); - break; - case (webpack.optimize as any).ModuleConcatenationPlugin: - this._addImport('webpack.optimize', 'ModuleConcatenationPlugin'); - break; - case angularCliPlugins.BaseHrefWebpackPlugin: - case angularCliPlugins.NamedLazyChunksWebpackPlugin: - case angularCliPlugins.SuppressExtractedTextChunksWebpackPlugin: - this._addImport('@angular/cli/plugins/webpack', plugin.constructor.name); - break; - case angularCliPlugins.GlobCopyWebpackPlugin: - args = this._globCopyWebpackPluginSerialize(plugin); - this._addImport('@angular/cli/plugins/webpack', 'GlobCopyWebpackPlugin'); - break; - case angularCliPlugins.InsertConcatAssetsWebpackPlugin: - args = this._insertConcatAssetsWebpackPluginSerialize(plugin); - this._addImport('@angular/cli/plugins/webpack', 'InsertConcatAssetsWebpackPlugin'); - break; - case webpack.optimize.CommonsChunkPlugin: - args = this._commonsChunkPluginSerialize(plugin); - this._addImport('webpack.optimize', 'CommonsChunkPlugin'); - break; - case ExtractTextPlugin: - args = this._extractTextPluginSerialize(plugin); - this.variableImports['extract-text-webpack-plugin'] = 'ExtractTextPlugin'; - break; - case CircularDependencyPlugin: - this.variableImports['circular-dependency-plugin'] = 'CircularDependencyPlugin'; - break; - case AotPlugin: - args = this._aotPluginSerialize(plugin); - this._addImport('@ngtools/webpack', 'AotPlugin'); - break; - case PurifyPlugin: - this._addImport('@angular-devkit/build-optimizer', 'PurifyPlugin'); - break; - case AngularCompilerPlugin: - args = this._aotPluginSerialize(plugin); - this._addImport('@ngtools/webpack', 'AngularCompilerPlugin'); - break; - case HtmlWebpackPlugin: - args = this._htmlWebpackPlugin(plugin); - this.variableImports['html-webpack-plugin'] = 'HtmlWebpackPlugin'; - break; - case webpack.EnvironmentPlugin: - args = this._environmentPlugin(plugin); - this._addImport('webpack', 'EnvironmentPlugin'); - break; - case LicenseWebpackPlugin: - args = this._licenseWebpackPlugin(plugin); - this._addImport('license-webpack-plugin', 'LicenseWebpackPlugin'); - break; - case ConcatPlugin: - args = this._concatPlugin(plugin); - this.variableImports['webpack-concat-plugin'] = 'ConcatPlugin'; - break; - case UglifyJSPlugin: - args = this._uglifyjsPlugin(plugin); - this.variableImports['uglifyjs-webpack-plugin'] = 'UglifyJsPlugin'; - break; - case SubresourceIntegrityPlugin: - this.variableImports['webpack-subresource-integrity'] = 'SubresourceIntegrityPlugin'; - break; - - default: - if (plugin.constructor.name == 'AngularServiceWorkerPlugin') { - this._addImport('@angular/service-worker/build/webpack', plugin.constructor.name); - } else if (plugin['copyWebpackPluginPatterns']) { - // CopyWebpackPlugin doesn't have a constructor nor save args. - this.variableImports['copy-webpack-plugin'] = 'CopyWebpackPlugin'; - const patternOptions = plugin['copyWebpackPluginPatterns'].map((pattern: any) => { - if (!pattern.context) { - return pattern; - } - const context = path.relative(process.cwd(), pattern.context); - return { ...pattern, context }; - }); - const patternsSerialized = serializer(patternOptions); - const optionsSerialized = serializer(plugin['copyWebpackPluginOptions']) || 'undefined'; - return `\uFF02CopyWebpackPlugin(${patternsSerialized}, ${optionsSerialized})\uFF02`; - } - break; - } - - const argsSerialized = serializer(args) || ''; - return `\uFF02${plugin.constructor.name}(${argsSerialized})\uFF02`; - }); - } - - private _resolveReplacer(value: any) { - this.variableImports['rxjs/_esm5/path-mapping'] = 'rxPaths'; - return Object.assign({}, value, { - modules: value.modules.map((x: string) => './' + path.relative(this._root, x)), - alias: this._escape('rxPaths()') - }); - } - - private _outputReplacer(value: any) { - return Object.assign({}, value, { - path: this._relativePath('process.cwd()', path.relative(this._root, value.path)) - }); - } - - private _path(l: string) { - return l.split('!').map(x => { - return path.isAbsolute(x) ? './' + path.relative(this._root, x) : x; - }).join('!'); - } - - private _entryReplacer(value: any) { - const newValue = Object.assign({}, value); - for (const key of Object.keys(newValue)) { - newValue[key] = newValue[key].map((l: string) => this._path(l)); - } - return newValue; - } - - private _loaderReplacer(loader: any) { - if (typeof loader == 'string') { - if (loader.match(/\/node_modules\/extract-text-webpack-plugin\//)) { - return 'extract-text-webpack-plugin'; - } else if (loader.match(/@ngtools\/webpack\/src\/index.ts/)) { - // return '@ngtools/webpack'; - } - } else { - if (loader.loader) { - loader.loader = this._loaderReplacer(loader.loader); - } - if (loader.loader === 'postcss-loader' && !this._postcssProcessed) { - const args: any = loader.options.plugins[postcssArgs]; - - Object.keys(args.variableImports) - .forEach(key => this.variableImports[key] = args.variableImports[key]); - Object.keys(args.variables) - .forEach(key => this.variables[key] = JSON.stringify(args.variables[key])); - - this.variables['postcssPlugins'] = loader.options.plugins; - loader.options.plugins = this._escape('postcssPlugins'); - - this._postcssProcessed = true; - } - } - return loader; - } - - private _ruleReplacer(value: any) { - const replaceExcludeInclude = (v: any) => { - if (typeof v == 'object') { - if (v.constructor == RegExp) { - return this._serializeRegExp(v); - } - return v; - } else if (typeof v == 'string') { - if (v === path.join(this._root, 'node_modules')) { - return this._serializeRegExp(/(\\|\/)node_modules(\\|\/)/); - } - return this._relativePath('process.cwd()', path.relative(this._root, v)); - } else { - return v; - } - }; - - if (value[pluginArgs]) { - return { - include: Array.isArray(value.include) - ? value.include.map((x: any) => replaceExcludeInclude(x)) - : replaceExcludeInclude(value.include), - test: this._serializeRegExp(value.test), - loaders: this._escape( - `ExtractTextPlugin.extract(${JSON.stringify(value[pluginArgs], null, 2)})`) - }; - } - - if (value.loaders) { - value.loaders = value.loaders.map((loader: any) => this._loaderReplacer(loader)); - } - if (value.loader) { - value.loader = this._loaderReplacer(value.loader); - } - if (value.use) { - if (Array.isArray(value.use)) { - value.use = value.use.map((loader: any) => this._loaderReplacer(loader)); - } else { - value.use = this._loaderReplacer(value.loader); - } - } - - if (value.exclude) { - value.exclude = Array.isArray(value.exclude) - ? value.exclude.map((x: any) => replaceExcludeInclude(x)) - : replaceExcludeInclude(value.exclude); - } - if (value.include) { - value.include = Array.isArray(value.include) - ? value.include.map((x: any) => replaceExcludeInclude(x)) - : replaceExcludeInclude(value.include); - } - - return value; - } - - private _moduleReplacer(value: any) { - return Object.assign({}, value, { - rules: value.rules && value.rules.map((x: any) => this._ruleReplacer(x)) - }); - } - - private _globReplacer(value: any) { - return Object.assign({}, value, { - cwd: this._relativePath('process.cwd()', path.relative(this._root, value.cwd)) - }); - } - - private _replacer(_key: string, value: any) { - if (value === undefined) { - return value; - } - if (value === null) { - return null; - } - if (value.constructor === RegExp) { - return this._serializeRegExp(value); - } - - return value; - } - - serialize(config: any): string { - // config = Object.assign({}, config); - config['plugins'] = this._pluginsReplacer(config['plugins']); - // Routes using PathLocationStrategy break without this. - config['devServer'] = { - 'historyApiFallback': true - }; - config['resolve'] = this._resolveReplacer(config['resolve']); - config['resolveLoader'] = this._resolveReplacer(config['resolveLoader']); - config['entry'] = this._entryReplacer(config['entry']); - config['output'] = this._outputReplacer(config['output']); - config['module'] = this._moduleReplacer(config['module']); - config['context'] = undefined; - - return JSON.stringify(config, (k, v) => this._replacer(k, v), 2) - .replace(/"\uFF01(.*?)\uFF01"/g, (_, v) => { - return JSON.parse(`"${v}"`); - }) - .replace(/(\s*)(.*?)"\uFF02(.*?)\uFF02"(,?).*/g, (_, indent, key, value, comma) => { - const ctor = JSON.parse(`"${value}"`).split(/\n+/g).join(indent); - return `${indent}${key}new ${ctor}${comma}`; - }) - .replace(/"\uFF01(.*?)\uFF01"/g, (_, v) => { - return JSON.parse(`"${v}"`); - }); - } - - generateVariables(): string { - let variableOutput = ''; - Object.keys(this.variableImports) - .forEach((key: string) => { - const [module, name] = key.split(/\./); - variableOutput += `const ${this.variableImports[key]} = require` + `('${module}')`; - if (name) { - variableOutput += '.' + name; - } - variableOutput += ';\n'; - }); - variableOutput += '\n'; - - Object.keys(this.imports) - .forEach((key: string) => { - const [module, name] = key.split(/\./); - variableOutput += `const { ${this.imports[key].join(', ')} } = require` + `('${module}')`; - if (name) { - variableOutput += '.' + name; - } - variableOutput += ';\n'; - }); - variableOutput += '\n'; - - Object.keys(this.variables) - .forEach((key: string) => { - variableOutput += `const ${key} = ${this.variables[key]};\n`; - }); - variableOutput += '\n\n'; - - return variableOutput; - } -} - - -export default Task.extend({ - run: function (runTaskOptions: EjectTaskOptions) { - const project = this.project; - const cliConfig = CliConfig.fromProject(); - const config = cliConfig.config; - const appConfig = getAppFromConfig(runTaskOptions.app); - - const tsConfigPath = path.join(process.cwd(), appConfig.root, appConfig.tsconfig); - const outputPath = runTaskOptions.outputPath || appConfig.outDir; - const force = runTaskOptions.force; - - if (project.root === path.resolve(outputPath)) { - throw new SilentError ('Output path MUST not be project root directory!'); - } - if (appConfig.platform === 'server') { - throw new SilentError('ng eject for platform server applications is coming soon!'); - } - - const webpackConfig = new NgCliWebpackConfig(runTaskOptions, appConfig).buildConfig(); - const serializer = new JsonWebpackSerializer(process.cwd(), outputPath, appConfig.root); - const output = serializer.serialize(webpackConfig); - const webpackConfigStr = `${serializer.generateVariables()}\n\nmodule.exports = ${output};\n`; - - return Promise.resolve() - .then(() => exists('webpack.config.js')) - .then(webpackConfigExists => { - if (webpackConfigExists && !force) { - throw new SilentError('The webpack.config.js file already exists.'); - } - }) - // Read the package.json and update it to include npm scripts. We do this first so that if - // an error already exists - .then(() => stripBom(fs.readFileSync('package.json', 'utf-8'))) - .then((packageJson: string) => JSON.parse(packageJson)) - .then((packageJson: any) => { - const scripts = packageJson['scripts']; - if (scripts['build'] && scripts['build'] !== 'ng build' && !force) { - throw new SilentError(oneLine` - Your package.json scripts must not contain a build script as it will be overwritten. - `); - } - if (scripts['start'] && scripts['start'] !== 'ng serve' && !force) { - throw new SilentError(oneLine` - Your package.json scripts must not contain a start script as it will be overwritten. - `); - } - if (scripts['pree2e'] && scripts['pree2e'] !== pree2eNpmScript && !force) { - throw new SilentError(oneLine` - Your package.json scripts must not contain a pree2e script as it will be - overwritten. - `); - } - if (scripts['e2e'] && scripts['e2e'] !== 'ng e2e' && !force) { - throw new SilentError(oneLine` - Your package.json scripts must not contain a e2e script as it will be overwritten. - `); - } - if (scripts['test'] && scripts['test'] !== 'ng test' && !force) { - throw new SilentError(oneLine` - Your package.json scripts must not contain a test script as it will be overwritten. - `); - } - - packageJson['scripts']['build'] = 'webpack'; - packageJson['scripts']['start'] = 'webpack-dev-server --port=4200'; - packageJson['scripts']['test'] = 'karma start ./karma.conf.js'; - packageJson['scripts']['pree2e'] = pree2eNpmScript; - packageJson['scripts']['e2e'] = 'protractor ./protractor.conf.js'; - - // Add new dependencies based on our dependencies. - const ourPackageJson = require('../package.json'); - if (!packageJson['devDependencies']) { - packageJson['devDependencies'] = {}; - } - packageJson['devDependencies']['webpack-dev-server'] - = ourPackageJson['dependencies']['webpack-dev-server']; - - // Update all loaders from webpack, plus postcss plugins. - [ - 'webpack', - 'autoprefixer', - 'css-loader', - 'cssnano', - 'exports-loader', - 'file-loader', - 'html-webpack-plugin', - 'json-loader', - 'karma-sourcemap-loader', - 'less-loader', - 'postcss-loader', - 'postcss-url', - 'raw-loader', - 'sass-loader', - 'source-map-loader', - 'istanbul-instrumenter-loader', - 'style-loader', - 'stylus-loader', - 'url-loader', - 'circular-dependency-plugin', - 'webpack-concat-plugin', - 'copy-webpack-plugin', - 'uglifyjs-webpack-plugin', - ].forEach((packageName: string) => { - packageJson['devDependencies'][packageName] = ourPackageJson['dependencies'][packageName]; - }); - - return writeFile('package.json', JSON.stringify(packageJson, null, 2) + '\n'); - }) - .then(() => JSON.parse(stripBom(fs.readFileSync(tsConfigPath, 'utf-8')))) - .then((tsConfigJson: any) => { - if (!tsConfigJson.exclude || force) { - // Make sure we now include tests. Do not touch otherwise. - tsConfigJson.exclude = [ - 'test.ts', - '**/*.spec.ts' - ]; - } - return writeFile(tsConfigPath, JSON.stringify(tsConfigJson, null, 2) + '\n'); - }) - // Output the webpack.config.js. - .then(() => writeFile('webpack.config.js', webpackConfigStr)) - .then(() => { - // Update the CLI Config. - config.project.ejected = true; - cliConfig.save(); - }) - .then(() => { - console.log(yellow(stripIndent` - ========================================================================================== - Ejection was successful. - - To run your builds, you now need to do the following commands: - - "npm run build" to build. - - "npm test" to run unit tests. - - "npm start" to serve the app using webpack-dev-server. - - "npm run e2e" to run protractor. - - Running the equivalent CLI commands will result in an error. - - ========================================================================================== - Some packages were added. Please run "npm install". - `)); - }); - } -}); diff --git a/packages/@angular/cli/tasks/extract-i18n.ts b/packages/@angular/cli/tasks/extract-i18n.ts deleted file mode 100644 index 322ae2c70b7a..000000000000 --- a/packages/@angular/cli/tasks/extract-i18n.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { join } from 'path'; -import * as webpack from 'webpack'; -import { AngularCompilerPlugin } from '@ngtools/webpack'; -import { XI18nWebpackConfig } from '../models/webpack-xi18n-config'; -import { getAppFromConfig } from '../utilities/app-utils'; -import {getWebpackStatsConfig} from '../models/webpack-configs'; -import {statsErrorsToString, statsWarningsToString} from '../utilities/stats'; - -const Task = require('../ember-cli/lib/models/task'); -const MemoryFS = require('memory-fs'); - - -export const Extracti18nTask = Task.extend({ - run: function (runTaskOptions: any) { - const appConfig = getAppFromConfig(runTaskOptions.app); - const useExperimentalAngularCompiler = AngularCompilerPlugin.isSupported(); - - // We need to determine the outFile name so that AngularCompiler can retrieve it. - let outFile = runTaskOptions.outFile || getI18nOutfile(runTaskOptions.i18nFormat); - if (useExperimentalAngularCompiler && runTaskOptions.outputPath) { - // AngularCompilerPlugin doesn't support genDir so we have to adjust outFile instead. - outFile = join(runTaskOptions.outputPath, outFile); - } - - const config = new XI18nWebpackConfig({ - genDir: runTaskOptions.outputPath || appConfig.root, - buildDir: '.tmp', - i18nFormat: runTaskOptions.i18nFormat, - locale: runTaskOptions.locale, - outFile: outFile, - verbose: runTaskOptions.verbose, - progress: runTaskOptions.progress, - app: runTaskOptions.app, - aot: useExperimentalAngularCompiler, - }, appConfig).buildConfig(); - - const webpackCompiler = webpack(config); - webpackCompiler.outputFileSystem = new MemoryFS(); - const statsConfig = getWebpackStatsConfig(runTaskOptions.verbose); - - return new Promise((resolve, reject) => { - const callback: webpack.compiler.CompilerCallback = (err, stats) => { - if (err) { - return reject(err); - } - - const json = stats.toJson('verbose'); - if (stats.hasWarnings()) { - this.ui.writeLine(statsWarningsToString(json, statsConfig)); - } - if (stats.hasErrors()) { - reject(statsErrorsToString(json, statsConfig)); - } else { - resolve(); - } - }; - - webpackCompiler.run(callback); - }); - } -}); - -function getI18nOutfile(format: string) { - switch (format) { - case 'xmb': - return 'messages.xmb'; - case 'xlf': - case 'xlif': - case 'xliff': - case 'xlf2': - case 'xliff2': - return 'messages.xlf'; - default: - throw new Error(`Unsupported format "${format}"`); - } -} diff --git a/packages/@angular/cli/tasks/git-init.ts b/packages/@angular/cli/tasks/git-init.ts deleted file mode 100644 index beedffd63027..000000000000 --- a/packages/@angular/cli/tasks/git-init.ts +++ /dev/null @@ -1,73 +0,0 @@ -import { oneLine } from 'common-tags'; -import chalk from 'chalk'; -import denodeify = require('denodeify'); - -const exec: any = denodeify(require('child_process').exec); -const path = require('path'); -const pkg = require('../package.json'); -const fs = require('fs'); -const template = require('lodash/template'); -const Task = require('../ember-cli/lib/models/task'); - -const gitEnvironmentVariables = { - GIT_AUTHOR_NAME: process.env.GIT_AUTHOR_NAME || 'Angular CLI', - GIT_AUTHOR_EMAIL: process.env.GIT_AUTHOR_EMAIL || 'angular-cli@angular.io', - get GIT_COMMITTER_NAME() { - return this.GIT_AUTHOR_NAME; - }, - get GIT_COMMITTER_EMAIL() { - return this.GIT_AUTHOR_EMAIL; - } -}; - -module.exports = Task.extend({ - run: function (commandOptions: any) { - const ui = this.ui; - - if (commandOptions.skipGit) { - return Promise.resolve(); - } - - return exec('git --version') - .then(function () { - // check if we're inside a git repo - return exec('git rev-parse --is-inside-work-tree') - .then(function () { - return true; - }) - .catch(function() { - return false; - }); - }) - .then(function (insideGitRepo: boolean) { - if (insideGitRepo) { - ui.writeLine(oneLine` - Directory is already under version control. - Skipping initialization of git.`); - return; - } - return exec('git init') - .then(function () { - return exec('git add .'); - }) - .then(function () { - if (!commandOptions.skipCommit) { - const commitTemplate = fs.readFileSync( - path.join(__dirname, '../utilities/INITIAL_COMMIT_MESSAGE.txt')); - const commitMessage = template(commitTemplate)(pkg); - return exec( - 'git commit -m "' + commitMessage + '"', { env: gitEnvironmentVariables }); - } - }) - .then(function () { - ui.writeLine(chalk.green('Successfully initialized git.')); - }); - }) - .catch(function (/*error*/) { - // if git is not found or an error was thrown during the `git` - // init process just swallow any errors here - }); - } -}); - -module.exports.overrideCore = true; diff --git a/packages/@angular/cli/tasks/init.ts b/packages/@angular/cli/tasks/init.ts deleted file mode 100644 index edaf9b6b3e5b..000000000000 --- a/packages/@angular/cli/tasks/init.ts +++ /dev/null @@ -1,113 +0,0 @@ -import chalk from 'chalk'; -import LinkCli from '../tasks/link-cli'; -import NpmInstall from '../tasks/npm-install'; -import { validateProjectName } from '../utilities/validate-project-name'; -import {checkYarnOrCNPM} from '../utilities/check-package-manager'; -import {CliConfig} from '../models/config'; - -const Task = require('../ember-cli/lib/models/task'); -const SilentError = require('silent-error'); -const GitInit = require('../tasks/git-init'); -const packageJson = require('../package.json'); - - -export default Task.extend({ - - run: function (commandOptions: any, rawArgs: string[]) { - if (commandOptions.dryRun) { - commandOptions.skipInstall = true; - } - - // needs an explicit check in case it's just 'undefined' - // due to passing of options from 'new' and 'addon' - let gitInit: any; - if (commandOptions.skipGit === false) { - gitInit = new GitInit({ - ui: this.ui, - project: this.project - }); - } - - const packageManager = CliConfig.fromGlobal().get('packageManager'); - - let npmInstall: any; - if (!commandOptions.skipInstall) { - npmInstall = new NpmInstall({ - ui: this.ui, - project: this.project, - packageManager - }); - } - - let linkCli: any; - if (commandOptions.linkCli) { - linkCli = new LinkCli({ - ui: this.ui, - project: this.project, - packageManager - }); - } - - const project = this.project; - const packageName = commandOptions.name !== '.' && commandOptions.name || project.name(); - - if (commandOptions.style === undefined) { - commandOptions.style = CliConfig.fromGlobal().get('defaults.styleExt'); - } - - if (!packageName) { - const message = 'The `ng ' + this.name + '` command requires a ' + - 'package.json in current folder with name attribute or a specified name via arguments. ' + - 'For more details, use `ng help`.'; - - return Promise.reject(new SilentError(message)); - } - - validateProjectName(packageName); - - const SchematicRunTask = require('../tasks/schematic-run').default; - const schematicRunTask = new SchematicRunTask({ - ui: this.ui, - project: this.project - }); - - const cwd = this.project.root; - const schematicName = CliConfig.fromGlobal().get('defaults.schematics.newApp'); - commandOptions.version = packageJson.version; - - const runOptions = { - taskOptions: commandOptions, - workingDir: cwd, - emptyHost: true, - collectionName: commandOptions.collectionName, - schematicName - }; - - return schematicRunTask.run(runOptions) - .then(function () { - if (!commandOptions.dryRun) { - process.chdir(commandOptions.directory); - } - }) - .then(function () { - if (!commandOptions.skipInstall) { - return checkYarnOrCNPM().then(() => npmInstall.run()); - } - }) - .then(function () { - if (!commandOptions.dryRun && commandOptions.skipGit === false) { - return gitInit.run(commandOptions, rawArgs); - } - }) - .then(function () { - if (!commandOptions.dryRun && commandOptions.linkCli) { - return linkCli.run(); - } - }) - .then(() => { - if (!commandOptions.dryRun) { - this.ui.writeLine(chalk.green(`Project '${packageName}' successfully created.`)); - } - }); - } -}); diff --git a/packages/@angular/cli/tasks/link-cli.ts b/packages/@angular/cli/tasks/link-cli.ts deleted file mode 100644 index b45440dc9dd4..000000000000 --- a/packages/@angular/cli/tasks/link-cli.ts +++ /dev/null @@ -1,26 +0,0 @@ -const Task = require('../ember-cli/lib/models/task'); -import chalk from 'chalk'; -import {exec} from 'child_process'; - -export default Task.extend({ - run: function() { - const ui = this.ui; - - let packageManager = this.packageManager; - if (packageManager === 'default') { - packageManager = 'npm'; - } - - return new Promise(function(resolve, reject) { - exec(`${packageManager} link @angular/cli`, (err) => { - if (err) { - ui.writeLine(chalk.red(`Couldn't do '${packageManager} link @angular/cli'.`)); - reject(); - } else { - ui.writeLine(chalk.green('Successfully linked to @angular/cli.')); - resolve(); - } - }); - }); - } -}); diff --git a/packages/@angular/cli/tasks/lint.ts b/packages/@angular/cli/tasks/lint.ts deleted file mode 100644 index 576a2d49d035..000000000000 --- a/packages/@angular/cli/tasks/lint.ts +++ /dev/null @@ -1,210 +0,0 @@ -// We only use typescript for type information here. -// @ignoreDep typescript -import chalk from 'chalk'; -import * as fs from 'fs'; -import * as glob from 'glob'; -import { Minimatch } from 'minimatch'; -import * as path from 'path'; -import { satisfies } from 'semver'; -import * as ts from 'typescript'; -// @ignoreDep tslint - used only for type information -import * as tslint from 'tslint'; -import { requireProjectModule } from '../utilities/require-project-module'; -import { stripBom } from '../utilities/strip-bom'; - -const SilentError = require('silent-error'); -const Task = require('../ember-cli/lib/models/task'); - -export interface CliLintConfig { - files?: (string | string[]); - project?: string; - tslintConfig?: string; - exclude?: (string | string[]); -} - -export class LintTaskOptions { - fix: boolean; - force: boolean; - format? = 'prose'; - silent? = false; - typeCheck? = false; - configs: Array; -} - -export default Task.extend({ - run: function (options: LintTaskOptions) { - options = { ...new LintTaskOptions(), ...options }; - const ui = this.ui; - const projectRoot = this.project.root; - const lintConfigs = options.configs || []; - - if (lintConfigs.length === 0) { - if (!options.silent) { - ui.writeLine(chalk.yellow('No lint configuration(s) found.')); - } - return Promise.resolve(0); - } - - const projectTslint = requireProjectModule(projectRoot, 'tslint') as typeof tslint; - const Linter = projectTslint.Linter; - const Configuration = projectTslint.Configuration; - - const result = lintConfigs - .map((config) => { - let program: ts.Program; - if (config.project) { - program = Linter.createProgram(config.project); - } else if (options.typeCheck) { - if (!options.silent) { - ui.writeLine(chalk.yellow('A "project" must be specified to enable type checking.')); - } - } - const files = getFilesToLint(program, config, Linter); - const lintOptions = { - fix: options.fix, - formatter: options.format - }; - - // TSLint < 5.5 has a bug with fix and project used in combination. - // previous behavior of typeCheck option is maintained for those versions - if (satisfies(Linter.VERSION, '< 5.5') && !options.typeCheck) { - program = undefined; - } - - const linter = new Linter(lintOptions, program); - - let lastDirectory; - let configLoad; - for (const file of files) { - const contents = getFileContents(file, config, program); - - // Only check for a new tslint config if path changes - const currentDirectory = path.dirname(file); - if (currentDirectory !== lastDirectory) { - configLoad = Configuration.findConfiguration(config.tslintConfig, file); - lastDirectory = currentDirectory; - } - - linter.lint(file, contents, configLoad.results); - } - - return linter.getResult(); - }) - .reduce((total, current) => { - const failures = current.failures - .filter(cf => !total.failures.some(ef => ef.equals(cf))); - total.failures = total.failures.concat(...failures); - - if (current.fixes) { - total.fixes = (total.fixes || []).concat(...current.fixes); - } - - if (current.errorCount !== undefined) { - total.errorCount += current.errorCount; - } else { - // Handle pre-warning/error bifurcation - total.errorCount += failures.length; - } - - if (current.warningCount !== undefined) { - total.warningCount += current.warningCount; - } - - return total; - }, { - failures: [], - fixes: undefined, - errorCount: 0, - warningCount: 0, - }); - - if (!options.silent) { - const Formatter = projectTslint.findFormatter(options.format); - if (!Formatter) { - throw new SilentError(chalk.red(`Invalid lint format "${options.format}".`)); - } - const formatter = new Formatter(); - - const output = formatter.format(result.failures, result.fixes); - if (output) { - ui.writeLine(output); - } - } - - // print formatter output directly for non human-readable formats - if (['prose', 'verbose', 'stylish'].indexOf(options.format) == -1) { - options.silent = true; - } - - if (result.warningCount > 0 && !options.silent) { - ui.writeLine(chalk.yellow('Lint warnings found in the listed files.')); - } - - if (result.errorCount > 0 && !options.silent) { - ui.writeLine(chalk.red('Lint errors found in the listed files.')); - } - - if (result.warningCount === 0 && result.errorCount === 0 && !options.silent) { - ui.writeLine(chalk.green('All files pass linting.')); - } - - return options.force || result.errorCount === 0 ? Promise.resolve(0) : Promise.resolve(2); - } -}); - -function normalizeArrayOption(option: T | Array): Array { - return Array.isArray(option) ? option : [option]; -} - -function getFilesToLint( - program: ts.Program, - lintConfig: CliLintConfig, - linter: typeof tslint.Linter, -): string[] { - const providedFiles = lintConfig.files && normalizeArrayOption(lintConfig.files); - const ignore = lintConfig.exclude && normalizeArrayOption(lintConfig.exclude); - - if (providedFiles) { - return providedFiles - .map(file => glob.sync(file, { ignore, nodir: true })) - .reduce((prev, curr) => prev.concat(curr), []); - } - - if (!program) { - return []; - } - - let programFiles = linter.getFileNames(program); - - if (ignore && ignore.length > 0) { - const ignoreMatchers = ignore.map(pattern => new Minimatch(pattern)); - - programFiles = programFiles - .filter(file => !ignoreMatchers.some(matcher => matcher.match(file))); - } - - return programFiles; -} - -function getFileContents( - file: string, - config: CliLintConfig, - program?: ts.Program, -): string | undefined { - // The linter retrieves the SourceFile TS node directly if a program is used - if (program) { - if (program.getSourceFile(file) == undefined) { - const message = `File '${file}' is not part of the TypeScript project '${config.project}'.`; - throw new SilentError(chalk.red(message)); - } - - return undefined; - } - - // NOTE: The tslint CLI checks for and excludes MPEG transport streams; this does not. - try { - return stripBom(fs.readFileSync(file, 'utf-8')); - } catch (e) { - throw new SilentError(`Could not read file '${file}'.`); - } -} diff --git a/packages/@angular/cli/tasks/npm-install.ts b/packages/@angular/cli/tasks/npm-install.ts deleted file mode 100644 index 8c4085a86236..000000000000 --- a/packages/@angular/cli/tasks/npm-install.ts +++ /dev/null @@ -1,39 +0,0 @@ -const Task = require('../ember-cli/lib/models/task'); -import chalk from 'chalk'; -import { spawn } from 'child_process'; - - -export default Task.extend({ - run: function () { - const ui = this.ui; - let packageManager = this.packageManager; - if (packageManager === 'default') { - packageManager = 'npm'; - } - - ui.writeLine(chalk.green(`Installing packages for tooling via ${packageManager}.`)); - - const installArgs = ['install']; - if (packageManager === 'npm') { - installArgs.push('--quiet'); - } - const installOptions = { - stdio: 'inherit', - shell: true - }; - - return new Promise((resolve, reject) => { - spawn(packageManager, installArgs, installOptions) - .on('close', (code: number) => { - if (code === 0) { - ui.writeLine(chalk.green(`Installed packages for tooling via ${packageManager}.`)); - resolve(); - } else { - const message = 'Package install failed, see above.'; - ui.writeLine(chalk.red(message)); - reject(message); - } - }); - }); - } -}); diff --git a/packages/@angular/cli/tasks/schematic-get-help-output.ts b/packages/@angular/cli/tasks/schematic-get-help-output.ts deleted file mode 100644 index 5b3e2b2171f4..000000000000 --- a/packages/@angular/cli/tasks/schematic-get-help-output.ts +++ /dev/null @@ -1,69 +0,0 @@ -import chalk from 'chalk'; -const Task = require('../ember-cli/lib/models/task'); - -const { cyan, grey } = chalk; - -export interface SchematicGetHelpOptions { - collectionName: string; - schematicName: string; - nonSchematicOptions: any[]; -} - -export interface SchematicAvailableOptions { - name: string; - description: string; - aliases: string[]; - type: any; - schematicType: any; - schematicDefault: any; -} - -const hiddenOptions = [ - 'name', - 'path', - 'source-dir', - 'app-root' -]; - -export default Task.extend({ - run: function ({schematicName, collectionName, nonSchematicOptions}: SchematicGetHelpOptions): - Promise { - - const SchematicGetOptionsTask = require('./schematic-get-options').default; - const getOptionsTask = new SchematicGetOptionsTask({ - ui: this.ui, - project: this.project - }); - return Promise.all([getOptionsTask.run({ - schematicName: schematicName, - collectionName: collectionName, - }), nonSchematicOptions]) - .then(([availableOptions, nonSchematicOptions]: [SchematicAvailableOptions[], any[]]) => { - const output: string[] = []; - [...(nonSchematicOptions || []), ...availableOptions] - .filter(opt => hiddenOptions.indexOf(opt.name) === -1) - .forEach(opt => { - let text = cyan(` --${opt.name}`); - if (opt.schematicType) { - text += cyan(` (${opt.schematicType})`); - } - if (opt.schematicDefault) { - text += cyan(` (Default: ${opt.schematicDefault})`); - } - if (opt.description) { - text += ` ${opt.description}`; - } - output.push(text); - if (opt.aliases && opt.aliases.length > 0) { - const aliasText = opt.aliases.reduce( - (acc: string, curr: string) => { - return acc + ` -${curr}`; - }, - ''); - output.push(grey(` aliases: ${aliasText}`)); - } - }); - return output; - }); - } -}); diff --git a/packages/@angular/cli/tasks/schematic-get-options.ts b/packages/@angular/cli/tasks/schematic-get-options.ts deleted file mode 100644 index 77c300150b11..000000000000 --- a/packages/@angular/cli/tasks/schematic-get-options.ts +++ /dev/null @@ -1,75 +0,0 @@ -const Task = require('../ember-cli/lib/models/task'); -const stringUtils = require('ember-cli-string-utils'); -import { CliConfig } from '../models/config'; -import { getCollection, getSchematic } from '../utilities/schematics'; - -export interface SchematicGetOptions { - collectionName: string; - schematicName: string; -} - -export interface SchematicAvailableOptions { - name: string; - description: string; - aliases: string[]; - type: any; - schematicType: any; - schematicDefault: any; -} - -export default Task.extend({ - run: function (options: SchematicGetOptions): Promise { - const collectionName = options.collectionName || - CliConfig.getValue('defaults.schematics.collection'); - - const collection = getCollection(collectionName); - - const schematic = getSchematic(collection, options.schematicName); - - const properties = schematic.description.schemaJson.properties; - const keys = Object.keys(properties); - const availableOptions = keys - .map(key => ({...properties[key], ...{name: stringUtils.dasherize(key)}})) - .map(opt => { - let type; - const schematicType = opt.type; - switch (opt.type) { - case 'string': - type = String; - break; - case 'boolean': - type = Boolean; - break; - case 'integer': - case 'number': - type = Number; - break; - - // Ignore arrays / objects. - default: - return null; - } - let aliases: string[] = []; - if (opt.alias) { - aliases = [...aliases, opt.alias]; - } - if (opt.aliases) { - aliases = [...aliases, ...opt.aliases]; - } - - const schematicDefault = opt.default; - - return { - ...opt, - aliases, - type, - schematicType, - default: undefined, // do not carry over schematics defaults - schematicDefault - }; - }) - .filter(x => x); - - return Promise.resolve(availableOptions); - } -}); diff --git a/packages/@angular/cli/tasks/schematic-run.ts b/packages/@angular/cli/tasks/schematic-run.ts deleted file mode 100644 index f3cddcc7c49b..000000000000 --- a/packages/@angular/cli/tasks/schematic-run.ts +++ /dev/null @@ -1,226 +0,0 @@ -import { - DryRunEvent, - DryRunSink, - EmptyTree, - FileSystemSink, - FileSystemTree, - Schematic, - Tree -} from '@angular-devkit/schematics'; -import { FileSystemHost } from '@angular-devkit/schematics/tools'; -import { Observable } from 'rxjs/Observable'; -import * as path from 'path'; -import chalk from 'chalk'; -import { CliConfig } from '../models/config'; -import 'rxjs/add/operator/concatMap'; -import 'rxjs/add/operator/map'; -import { getCollection, getSchematic } from '../utilities/schematics'; - -const { green, red, yellow } = chalk; -const Task = require('../ember-cli/lib/models/task'); - -export interface SchematicRunOptions { - taskOptions: SchematicOptions; - workingDir: string; - emptyHost: boolean; - collectionName: string; - schematicName: string; -} - -export interface SchematicOptions { - dryRun: boolean; - force: boolean; - [key: string]: any; -} - -export interface SchematicOutput { - modifiedFiles: string[]; -} - -interface OutputLogging { - color: (msg: string) => string; - keyword: string; - message: string; -} - -export default Task.extend({ - run: function (options: SchematicRunOptions): Promise { - const { taskOptions, workingDir, emptyHost, collectionName, schematicName } = options; - - const ui = this.ui; - - const collection = getCollection(collectionName); - const schematic = getSchematic(collection, schematicName); - - const projectRoot = !!this.project ? this.project.root : workingDir; - - const preppedOptions = prepOptions(schematic, taskOptions); - const opts = { ...taskOptions, ...preppedOptions }; - - const tree = emptyHost ? new EmptyTree() : new FileSystemTree(new FileSystemHost(workingDir)); - const host = Observable.of(tree); - - const dryRunSink = new DryRunSink(workingDir, opts.force); - const fsSink = new FileSystemSink(workingDir, opts.force); - - let error = false; - const loggingQueue: OutputLogging[] = []; - const modifiedFiles: string[] = []; - - dryRunSink.reporter.subscribe((event: DryRunEvent) => { - const eventPath = event.path.startsWith('/') ? event.path.substr(1) : event.path; - switch (event.kind) { - case 'error': - const desc = event.description == 'alreadyExist' ? 'already exists' : 'does not exist.'; - ui.writeLine(`error! ${eventPath} ${desc}.`); - error = true; - break; - case 'update': - loggingQueue.push({ - color: yellow, - keyword: 'update', - message: `${eventPath} (${event.content.length} bytes)` - }); - modifiedFiles.push(event.path); - break; - case 'create': - loggingQueue.push({ - color: green, - keyword: 'create', - message: `${eventPath} (${event.content.length} bytes)` - }); - modifiedFiles.push(event.path); - break; - case 'delete': - loggingQueue.push({ - color: red, - keyword: 'remove', - message: `${eventPath}` - }); - break; - case 'rename': - const eventToPath = event.to.startsWith('/') ? event.to.substr(1) : event.to; - loggingQueue.push({ - color: yellow, - keyword: 'rename', - message: `${eventPath} => ${eventToPath}` - }); - modifiedFiles.push(event.to); - break; - } - }); - - return new Promise((resolve, reject) => { - schematic.call(opts, host) - .map((tree: Tree) => Tree.optimize(tree)) - .concatMap((tree: Tree) => { - return dryRunSink.commit(tree).ignoreElements().concat(Observable.of(tree)); - }) - .concatMap((tree: Tree) => { - if (!error) { - // Output the logging queue. - loggingQueue.forEach(log => ui.writeLine(` ${log.color(log.keyword)} ${log.message}`)); - } - - if (opts.dryRun || error) { - return Observable.of(tree); - } - return fsSink.commit(tree).ignoreElements().concat(Observable.of(tree)); - }) - .subscribe({ - error(err) { - ui.writeLine(red(`Error: ${err.message}`)); - reject(err.message); - }, - complete() { - if (opts.dryRun) { - ui.writeLine(yellow(`\nNOTE: Run with "dry run" no changes were made.`)); - } - resolve({modifiedFiles}); - } - }); - }) - .then((output: SchematicOutput) => { - const modifiedFiles = output.modifiedFiles; - const lintFix = taskOptions.lintFix !== undefined ? - taskOptions.lintFix : CliConfig.getValue('defaults.lintFix'); - - if (lintFix && modifiedFiles) { - const LintTask = require('./lint').default; - const lintTask = new LintTask({ - ui: this.ui, - project: this.project - }); - - return lintTask.run({ - fix: true, - force: true, - silent: true, - configs: [{ - files: modifiedFiles - .filter((file: string) => /.ts$/.test(file)) - .map((file: string) => path.join(projectRoot, file)) - }] - }); - } - }); - } -}); - -function prepOptions(schematic: Schematic<{}, {}>, options: SchematicOptions): SchematicOptions { - - const properties = (schematic.description).schemaJson.properties; - const keys = Object.keys(properties); - if (['component', 'c', 'directive', 'd'].indexOf(schematic.description.name) !== -1) { - options.prefix = (options.prefix === 'false' || options.prefix === '') - ? '' : options.prefix; - } - - let preppedOptions = { - ...options, - ...readDefaults(schematic.description.name, keys, options) - }; - preppedOptions = { - ...preppedOptions, - ...normalizeOptions(schematic.description.name, keys, options) - }; - - return preppedOptions; -} - -function readDefaults(schematicName: string, optionKeys: string[], options: any): any { - return optionKeys.reduce((acc: any, key) => { - acc[key] = options[key] !== undefined ? options[key] : readDefault(schematicName, key); - return acc; - }, {}); -} - -const viewEncapsulationMap: any = { - 'emulated': 'Emulated', - 'native': 'Native', - 'none': 'None' -}; - -const changeDetectionMap: any = { - 'default': 'Default', - 'onpush': 'OnPush' -}; - -function normalizeOptions(schematicName: string, optionKeys: string[], options: any): any { - return optionKeys.reduce((acc: any, key) => { - - if (schematicName === 'application' || schematicName === 'component') { - if (key === 'viewEncapsulation' && options[key]) { - acc[key] = viewEncapsulationMap[options[key].toLowerCase()]; - } else if (key === 'changeDetection' && options[key]) { - acc[key] = changeDetectionMap[options[key].toLowerCase()]; - } - } - return acc; - }, {}); -} - -function readDefault(schematicName: String, key: string) { - const jsonPath = `defaults.${schematicName}.${key}`; - return CliConfig.getValue(jsonPath); -} diff --git a/packages/@angular/cli/tasks/serve.ts b/packages/@angular/cli/tasks/serve.ts deleted file mode 100644 index 18274a5c92c5..000000000000 --- a/packages/@angular/cli/tasks/serve.ts +++ /dev/null @@ -1,305 +0,0 @@ -import * as fs from 'fs-extra'; -import * as path from 'path'; -import * as webpack from 'webpack'; -import * as url from 'url'; -import chalk from 'chalk'; -import { oneLine, stripIndents } from 'common-tags'; -import { getWebpackStatsConfig } from '../models/webpack-configs/utils'; -import { NgCliWebpackConfig } from '../models/webpack-config'; -import { ServeTaskOptions } from '../commands/serve'; -import { CliConfig } from '../models/config'; -import { getAppFromConfig } from '../utilities/app-utils'; -import { statsToString, statsWarningsToString, statsErrorsToString } from '../utilities/stats'; - -const WebpackDevServer = require('webpack-dev-server'); -const Task = require('../ember-cli/lib/models/task'); -const SilentError = require('silent-error'); -const opn = require('opn'); -const yellow = chalk.yellow; - -function findDefaultServePath(baseHref: string, deployUrl: string): string | null { - if (!baseHref && !deployUrl) { - return ''; - } - - if (/^(\w+:)?\/\//.test(baseHref) || /^(\w+:)?\/\//.test(deployUrl)) { - // If baseHref or deployUrl is absolute, unsupported by ng serve - return null; - } - - // normalize baseHref - // for ng serve the starting base is always `/` so a relative - // and root relative value are identical - const baseHrefParts = (baseHref || '') - .split('/') - .filter(part => part !== ''); - if (baseHref && !baseHref.endsWith('/')) { - baseHrefParts.pop(); - } - const normalizedBaseHref = baseHrefParts.length === 0 ? '/' : `/${baseHrefParts.join('/')}/`; - - if (deployUrl && deployUrl[0] === '/') { - if (baseHref && baseHref[0] === '/' && normalizedBaseHref !== deployUrl) { - // If baseHref and deployUrl are root relative and not equivalent, unsupported by ng serve - return null; - } - return deployUrl; - } - - // Join together baseHref and deployUrl - return `${normalizedBaseHref}${deployUrl || ''}`; -} - -export default Task.extend({ - run: function (serveTaskOptions: ServeTaskOptions, rebuildDoneCb: any) { - const ui = this.ui; - - let webpackCompiler: any; - const projectConfig = CliConfig.fromProject().config; - const appConfig = getAppFromConfig(serveTaskOptions.app); - - const outputPath = serveTaskOptions.outputPath || appConfig.outDir; - if (this.project.root === path.resolve(outputPath)) { - throw new SilentError('Output path MUST not be project root directory!'); - } - if (projectConfig.project && projectConfig.project.ejected) { - throw new SilentError('An ejected project cannot use the build command anymore.'); - } - if (appConfig.platform === 'server') { - throw new SilentError('ng serve for platform server applications is coming soon!'); - } - if (serveTaskOptions.deleteOutputPath) { - fs.removeSync(path.resolve(this.project.root, outputPath)); - } - - const serveDefaults = { - // default deployUrl to '' on serve to prevent the default from .angular-cli.json - deployUrl: '' - }; - - serveTaskOptions = Object.assign({}, serveDefaults, serveTaskOptions); - - let webpackConfig = new NgCliWebpackConfig(serveTaskOptions, appConfig).buildConfig(); - - const serverAddress = url.format({ - protocol: serveTaskOptions.ssl ? 'https' : 'http', - hostname: serveTaskOptions.host === '0.0.0.0' ? 'localhost' : serveTaskOptions.host, - port: serveTaskOptions.port.toString() - }); - - if (serveTaskOptions.disableHostCheck) { - ui.writeLine(oneLine` - ${yellow('WARNING')} Running a server with --disable-host-check is a security risk. - See https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a - for more information. - `); - } - - let clientAddress = `${serveTaskOptions.ssl ? 'https' : 'http'}://0.0.0.0:0`; - if (serveTaskOptions.publicHost) { - let publicHost = serveTaskOptions.publicHost; - if (!/^\w+:\/\//.test(publicHost)) { - publicHost = `${serveTaskOptions.ssl ? 'https' : 'http'}://${publicHost}`; - } - const clientUrl = url.parse(publicHost); - serveTaskOptions.publicHost = clientUrl.host; - clientAddress = url.format(clientUrl); - } - - if (serveTaskOptions.liveReload) { - // This allows for live reload of page when changes are made to repo. - // https://webpack.github.io/docs/webpack-dev-server.html#inline-mode - let entryPoints = [ - `webpack-dev-server/client?${clientAddress}` - ]; - if (serveTaskOptions.hmr) { - const webpackHmrLink = 'https://webpack.github.io/docs/hot-module-replacement.html'; - - ui.writeLine(oneLine` - ${yellow('NOTICE')} Hot Module Replacement (HMR) is enabled for the dev server. - `); - - const showWarning = CliConfig.fromGlobal().get('warnings.hmrWarning'); - if (showWarning) { - ui.writeLine(' The project will still live reload when HMR is enabled,'); - ui.writeLine(' but to take advantage of HMR additional application code is required'); - ui.writeLine(' (not included in an Angular CLI project by default).'); - ui.writeLine(` See ${chalk.blue(webpackHmrLink)}`); - ui.writeLine(' for information on working with HMR for Webpack.'); - ui.writeLine(oneLine` - ${yellow('To disable this warning use "ng set --global warnings.hmrWarning=false"')} - `); - } - entryPoints.push('webpack/hot/dev-server'); - webpackConfig.plugins.push(new webpack.HotModuleReplacementPlugin()); - if (serveTaskOptions.extractCss) { - ui.writeLine(oneLine` - ${yellow('NOTICE')} (HMR) does not allow for CSS hot reload when used - together with '--extract-css'. - `); - } - } - if (!webpackConfig.entry.main) { webpackConfig.entry.main = []; } - webpackConfig.entry.main.unshift(...entryPoints); - } else if (serveTaskOptions.hmr) { - ui.writeLine(yellow('Live reload is disabled. HMR option ignored.')); - } - - if (!serveTaskOptions.watch) { - // There's no option to turn off file watching in webpack-dev-server, but - // we can override the file watcher instead. - webpackConfig.plugins.unshift({ - apply: (compiler: any) => { - compiler.plugin('after-environment', () => { - compiler.watchFileSystem = { watch: () => { } }; - }); - } - }); - } - - webpackCompiler = webpack(webpackConfig); - - if (rebuildDoneCb) { - webpackCompiler.plugin('done', rebuildDoneCb); - } - - const statsConfig = getWebpackStatsConfig(serveTaskOptions.verbose); - - let proxyConfig = {}; - if (serveTaskOptions.proxyConfig) { - const proxyPath = path.resolve(this.project.root, serveTaskOptions.proxyConfig); - if (fs.existsSync(proxyPath)) { - proxyConfig = require(proxyPath); - } else { - const message = 'Proxy config file ' + proxyPath + ' does not exist.'; - return Promise.reject(new SilentError(message)); - } - } - - let sslKey: string = null; - let sslCert: string = null; - if (serveTaskOptions.ssl) { - const keyPath = path.resolve(this.project.root, serveTaskOptions.sslKey); - if (fs.existsSync(keyPath)) { - sslKey = fs.readFileSync(keyPath, 'utf-8'); - } - const certPath = path.resolve(this.project.root, serveTaskOptions.sslCert); - if (fs.existsSync(certPath)) { - sslCert = fs.readFileSync(certPath, 'utf-8'); - } - } - - let servePath = serveTaskOptions.servePath; - if (!servePath && servePath !== '') { - const defaultServePath = - findDefaultServePath(serveTaskOptions.baseHref, serveTaskOptions.deployUrl); - if (defaultServePath == null) { - ui.writeLine(oneLine` - ${chalk.yellow('WARNING')} --deploy-url and/or --base-href contain - unsupported values for ng serve. Default serve path of '/' used. - Use --serve-path to override. - `); - } - servePath = defaultServePath || ''; - } - if (servePath.endsWith('/')) { - servePath = servePath.substr(0, servePath.length - 1); - } - if (!servePath.startsWith('/')) { - servePath = `/${servePath}`; - } - const webpackDevServerConfiguration: IWebpackDevServerConfigurationOptions = { - headers: { 'Access-Control-Allow-Origin': '*' }, - historyApiFallback: { - index: `${servePath}/${appConfig.index}`, - disableDotRule: true, - htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'] - }, - stats: serveTaskOptions.verbose ? statsConfig : 'none', - inline: true, - proxy: proxyConfig, - compress: serveTaskOptions.target === 'production', - watchOptions: { - poll: serveTaskOptions.poll - }, - https: serveTaskOptions.ssl, - overlay: { - errors: serveTaskOptions.target === 'development', - warnings: false - }, - contentBase: false, - public: serveTaskOptions.publicHost, - disableHostCheck: serveTaskOptions.disableHostCheck, - publicPath: servePath - }; - - if (sslKey != null && sslCert != null) { - webpackDevServerConfiguration.key = sslKey; - webpackDevServerConfiguration.cert = sslCert; - } - - webpackDevServerConfiguration.hot = serveTaskOptions.hmr; - - if (serveTaskOptions.target === 'production') { - ui.writeLine(chalk.red(stripIndents` - **************************************************************************************** - This is a simple server for use in testing or debugging Angular applications locally. - It hasn't been reviewed for security issues. - - DON'T USE IT FOR PRODUCTION! - **************************************************************************************** - `)); - } - - ui.writeLine(chalk.green(oneLine` - ** - NG Live Development Server is listening on ${serveTaskOptions.host}:${serveTaskOptions.port}, - open your browser on ${serverAddress}${servePath} - ** - `)); - - const server = new WebpackDevServer(webpackCompiler, webpackDevServerConfiguration); - if (!serveTaskOptions.verbose) { - webpackCompiler.plugin('done', (stats: any) => { - const json = stats.toJson('verbose'); - this.ui.writeLine(statsToString(json, statsConfig)); - if (stats.hasWarnings()) { - this.ui.writeLine(statsWarningsToString(json, statsConfig)); - } - if (stats.hasErrors()) { - this.ui.writeError(statsErrorsToString(json, statsConfig)); - } - }); - } - - return new Promise((_resolve, reject) => { - const httpServer = server.listen( - serveTaskOptions.port, - serveTaskOptions.host, - (err: any, _stats: any) => { - if (err) { - return reject(err); - } - if (serveTaskOptions.open) { - opn(serverAddress + servePath); - } - }); - // Node 8 has a keepAliveTimeout bug which doesn't respect active connections. - // Connections will end after ~5 seconds (arbitrary), often not letting the full download - // of large pieces of content, such as a vendor javascript file. This results in browsers - // throwing a "net::ERR_CONTENT_LENGTH_MISMATCH" error. - // https://github.com/angular/angular-cli/issues/7197 - // https://github.com/nodejs/node/issues/13391 - // https://github.com/nodejs/node/commit/2cb6f2b281eb96a7abe16d58af6ebc9ce23d2e96 - if (/^v8.\d.\d+$/.test(process.version)) { - httpServer.keepAliveTimeout = 30000; // 30 seconds - } - }) - .catch((err: Error) => { - if (err) { - this.ui.writeError('\nAn error occured during the build:\n' + ((err && err.stack) || err)); - } - throw err; - }); - } -}); diff --git a/packages/@angular/cli/tasks/test.ts b/packages/@angular/cli/tasks/test.ts deleted file mode 100644 index d9e75985bfe2..000000000000 --- a/packages/@angular/cli/tasks/test.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as path from 'path'; - -import { TestOptions } from '../commands/test'; -import { CliConfig } from '../models/config'; -import { requireProjectModule } from '../utilities/require-project-module'; -import { getAppFromConfig } from '../utilities/app-utils'; - -const Task = require('../ember-cli/lib/models/task'); -const SilentError = require('silent-error'); - - -export default Task.extend({ - run: function (options: TestOptions) { - const projectConfig = CliConfig.fromProject().config; - const projectRoot = this.project.root; - const appConfig = getAppFromConfig(options.app); - - if (projectConfig.project && projectConfig.project.ejected) { - throw new SilentError('An ejected project cannot use the build command anymore.'); - } - if (appConfig.platform === 'server') { - throw new SilentError('ng test for platform server applications is coming soon!'); - } - if (! appConfig.main) { - throw new SilentError(`An app without 'main' cannot use the test command.`); - } - - return new Promise((resolve) => { - const karma = requireProjectModule(projectRoot, 'karma'); - const karmaConfig = path.join(projectRoot, options.config || - CliConfig.getValue('test.karma.config')); - - let karmaOptions: any = Object.assign({}, options); - - // Convert browsers from a string to an array - if (options.browsers) { - karmaOptions.browsers = options.browsers.split(','); - } - - karmaOptions.angularCli = { - codeCoverage: options.codeCoverage, - sourcemaps: options.sourcemaps, - progress: options.progress, - poll: options.poll, - environment: options.environment, - preserveSymlinks: options.preserveSymlinks, - forceTsCommonjs: options.forceTsCommonjs, - app: options.app - }; - - // Assign additional karmaConfig options to the local ngapp config - karmaOptions.configFile = karmaConfig; - - // :shipit: - const karmaServer = new karma.Server(karmaOptions, resolve); - karmaServer.start(); - }); - } -}); diff --git a/packages/@angular/cli/tsconfig.json b/packages/@angular/cli/tsconfig.json deleted file mode 100644 index ed8cad33e491..000000000000 --- a/packages/@angular/cli/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - - "compilerOptions": { - "outDir": "../../../dist/@angular/cli", - "rootDir": ".", - "baseUrl": "", - "paths": { - "@ngtools/json-schema": [ "../../../dist/@ngtools/json-schema/src" ], - "@ngtools/webpack": [ "../../../dist/@ngtools/webpack/src" ] - } - } -} diff --git a/packages/@angular/cli/upgrade/version.ts b/packages/@angular/cli/upgrade/version.ts deleted file mode 100644 index 0fcf5f226642..000000000000 --- a/packages/@angular/cli/upgrade/version.ts +++ /dev/null @@ -1,215 +0,0 @@ -import {SemVer, satisfies} from 'semver'; -import chalk from 'chalk'; -import {stripIndents, stripIndent} from 'common-tags'; -import {readFileSync, existsSync} from 'fs'; -import * as path from 'path'; - -import {CliConfig} from '../models/config'; -import {findUp} from '../utilities/find-up'; -import {requireProjectModule} from '../utilities/require-project-module'; - -const resolve = require('resolve'); - - -const { bold, red, yellow } = chalk; - -function _hasOldCliBuildFile() { - return existsSync(findUp('angular-cli-build.js', process.cwd())) - || existsSync(findUp('angular-cli-build.ts', process.cwd())) - || existsSync(findUp('ember-cli-build.js', process.cwd())) - || existsSync(findUp('angular-cli-build.js', __dirname)) - || existsSync(findUp('angular-cli-build.ts', __dirname)) - || existsSync(findUp('ember-cli-build.js', __dirname)); -} - - -export class Version { - private _semver: SemVer = null; - constructor(private _version: string = null) { - this._semver = _version && new SemVer(_version); - } - - isAlpha() { return this.qualifier == 'alpha'; } - isBeta() { return this.qualifier == 'beta'; } - isReleaseCandidate() { return this.qualifier == 'rc'; } - isKnown() { return this._version !== null; } - - isLocal() { return this.isKnown() && path.isAbsolute(this._version); } - isGreaterThanOrEqualTo(other: SemVer) { - return this._semver.compare(other) >= 0; - } - - get major() { return this._semver ? this._semver.major : 0; } - get minor() { return this._semver ? this._semver.minor : 0; } - get patch() { return this._semver ? this._semver.patch : 0; } - get qualifier() { return this._semver ? this._semver.prerelease[0] : ''; } - get extra() { return this._semver ? this._semver.prerelease[1] : ''; } - - toString() { return this._version; } - - static fromProject(): Version { - let packageJson: any = null; - - try { - const angularCliPath = resolve.sync('@angular/cli', { - basedir: process.cwd(), - packageFilter: (pkg: any, _pkgFile: string) => { - packageJson = pkg; - } - }); - if (angularCliPath && packageJson) { - try { - return new Version(packageJson.version); - } catch (e) { - return new Version(null); - } - } - } catch (e) { - // Fallback to reading config. - } - - - const configPath = CliConfig.configFilePath(); - - if (configPath === null) { - return new Version(null); - } - - const configJson = readFileSync(configPath, 'utf8'); - - try { - const json = JSON.parse(configJson); - return new Version(json.project); - } catch (e) { - return new Version(null); - } - } - - static assertAngularVersionIs2_3_1OrHigher(projectRoot: string) { - let pkgJson; - try { - pkgJson = requireProjectModule(projectRoot, '@angular/core/package.json'); - } catch (_) { - console.error(bold(red(stripIndents` - You seem to not be depending on "@angular/core". This is an error. - `))); - process.exit(2); - } - - // Just check @angular/core. - if (pkgJson && pkgJson['version']) { - const v = new Version(pkgJson['version']); - if (v.isLocal()) { - console.warn(yellow('Using a local version of angular. Proceeding with care...')); - } else { - // Check if major is not 0, so that we stay compatible with local compiled versions - // of angular. - if (!v.isGreaterThanOrEqualTo(new SemVer('2.3.1')) && v.major != 0) { - console.error(bold(red(stripIndents` - This version of CLI is only compatible with angular version 2.3.1 or better. Please - upgrade your angular version, e.g. by running: - - npm install @angular/core@latest - ` + '\n'))); - process.exit(3); - } - } - } else { - console.error(bold(red(stripIndents` - You seem to not be depending on "@angular/core". This is an error. - `))); - process.exit(2); - } - } - - static assertPostWebpackVersion() { - if (this.isPreWebpack()) { - console.error(bold(red('\n' + stripIndents` - It seems like you're using a project generated using an old version of the Angular CLI. - The latest CLI now uses webpack and has a lot of improvements including a simpler - workflow, a faster build, and smaller bundles. - - To get more info, including a step-by-step guide to upgrade the CLI, follow this link: - https://github.com/angular/angular-cli/wiki/Upgrading-from-Beta.10-to-Beta.14 - ` + '\n'))); - process.exit(1); - } else { - // Verify that there's no build file. - if (_hasOldCliBuildFile()) { - console.error(bold(yellow('\n' + stripIndents` - It seems like you're using the newest version of the Angular CLI that uses webpack. - This version does not require an angular-cli-build file, but your project has one. - It will be ignored. - ` + '\n'))); - } - } - } - - static assertTypescriptVersion(projectRoot: string) { - const config = CliConfig.fromProject() || CliConfig.fromGlobal(); - if (!config.get('warnings.typescriptMismatch')) { - return; - } - let compilerVersion: string, tsVersion: string; - try { - compilerVersion = requireProjectModule(projectRoot, '@angular/compiler-cli').VERSION.full; - tsVersion = requireProjectModule(projectRoot, 'typescript').version; - } catch (_) { - console.error(bold(red(stripIndents` - Versions of @angular/compiler-cli and typescript could not be determined. - The most common reason for this is a broken npm install. - - Please make sure your package.json contains both @angular/compiler-cli and typescript in - devDependencies, then delete node_modules and package-lock.json (if you have one) and - run npm install again. - `))); - process.exit(2); - } - - const versionCombos = [ - { compiler: '>=2.3.1 <3.0.0', typescript: '>=2.0.2 <2.3.0' }, - { compiler: '>=4.0.0 <5.0.0', typescript: '>=2.1.0 <2.4.0' }, - { compiler: '>=5.0.0 <6.0.0', typescript: '>=2.4.2 <2.5.0' } - ]; - - const currentCombo = versionCombos.find((combo) => satisfies(compilerVersion, combo.compiler)); - - if (currentCombo && !satisfies(tsVersion, currentCombo.typescript)) { - // First line of warning looks weird being split in two, disable tslint for it. - console.log((yellow('\n' + stripIndent` - @angular/compiler-cli@${compilerVersion} requires typescript@'${ - currentCombo.typescript}' but ${tsVersion} was found instead. - Using this version can result in undefined behaviour and difficult to debug problems. - - Please run the following command to install a compatible version of TypeScript. - - npm install typescript@'${currentCombo.typescript}' - - To disable this warning run "ng set warnings.typescriptMismatch=false". - ` + '\n'))); - } - } - - static isPreWebpack(): boolean { - // CliConfig is a bit stricter with the schema, so we need to be a little looser with it. - const version = Version.fromProject(); - - if (version && version.isKnown()) { - if (version.major == 0) { - return true; - } else if (version.minor != 0) { - return false; - } else if (version.isBeta() && !version.toString().match(/webpack/)) { - const betaVersion = version.extra; - - if (parseInt(betaVersion) < 12) { - return true; - } - } - } else { - return _hasOldCliBuildFile(); - } - - return false; - } -} diff --git a/packages/@angular/cli/utilities/app-utils.ts b/packages/@angular/cli/utilities/app-utils.ts deleted file mode 100644 index 4207874eb635..000000000000 --- a/packages/@angular/cli/utilities/app-utils.ts +++ /dev/null @@ -1,32 +0,0 @@ -const SilentError = require('silent-error'); - -import chalk from 'chalk'; -import { oneLine } from 'common-tags'; -import { CliConfig } from '../models/config'; - -export function getAppFromConfig(nameOrIndex?: String) { - const apps: any[] = CliConfig.getValue('apps'); - if (!apps) { - throw new SilentError(chalk.red('Unable to find any apps in `.angular-cli.json`.')); - } - - if (nameOrIndex) { - if (nameOrIndex.match(/^[0-9]+$/)) { - const index = parseInt(nameOrIndex.toString(), 10); - if (apps[index]) { - return apps[index]; - } - } else { - const filtered = apps.filter((currentApp: any) => currentApp.name === nameOrIndex); - if (filtered.length > 0) { - return filtered[0]; - } - } - } else { - return apps[0]; - } - throw new SilentError(chalk.red(oneLine` - Unable to find app with name or index. - Verify the configuration in \`.angular-cli.json\` - `)); -} diff --git a/packages/@angular/cli/utilities/check-package-manager.ts b/packages/@angular/cli/utilities/check-package-manager.ts deleted file mode 100644 index 5e6d4c7ffc10..000000000000 --- a/packages/@angular/cli/utilities/check-package-manager.ts +++ /dev/null @@ -1,45 +0,0 @@ -import chalk from 'chalk'; -import {exec} from 'child_process'; -import {CliConfig} from '../models/config'; -import denodeify = require('denodeify'); - -const execPromise = denodeify(exec); -const packageManager = CliConfig.fromGlobal().get('packageManager'); - - -export function checkYarnOrCNPM() { - - // Don't show messages if user has already changed the default. - if (packageManager !== 'default') { - return Promise.resolve(); - } - - return Promise - .all([checkYarn(), checkCNPM()]) - .then((data: Array) => { - const [isYarnInstalled, isCNPMInstalled] = data; - if (isYarnInstalled && isCNPMInstalled) { - console.log(chalk.yellow('You can `ng set --global packageManager=yarn` ' - + 'or `ng set --global packageManager=cnpm`.')); - } else if (isYarnInstalled) { - console.log(chalk.yellow('You can `ng set --global packageManager=yarn`.')); - } else if (isCNPMInstalled) { - console.log(chalk.yellow('You can `ng set --global packageManager=cnpm`.')); - } else { - if (packageManager !== 'default' && packageManager !== 'npm') { - console.log(chalk.yellow(`Seems that ${packageManager} is not installed.`)); - console.log(chalk.yellow('You can `ng set --global packageManager=npm`.')); - } - } - }); -} - -function checkYarn() { - return execPromise('yarn --version') - .then(() => true, () => false); -} - -function checkCNPM() { - return execPromise('cnpm --version') - .then(() => true, () => false); -} diff --git a/packages/@angular/cli/utilities/check-port.ts b/packages/@angular/cli/utilities/check-port.ts deleted file mode 100644 index 29fa55500481..000000000000 --- a/packages/@angular/cli/utilities/check-port.ts +++ /dev/null @@ -1,22 +0,0 @@ -import * as denodeify from 'denodeify'; - -const SilentError = require('silent-error'); -const PortFinder = require('portfinder'); -const getPort = denodeify<{host: string, port: number}, number>(PortFinder.getPort); - -export function checkPort(port: number, host: string, basePort = 49152): Promise { - PortFinder.basePort = basePort; - return getPort({ port, host }) - .then(foundPort => { - - // If the port isn't available and we weren't looking for any port, throw error. - if (port !== foundPort && port !== 0) { - throw new SilentError( - `Port ${port} is already in use. Use '--port' to specify a different port.` - ); - } - - // Otherwise, our found port is good. - return foundPort; - }); -} diff --git a/packages/@angular/cli/utilities/dynamic-path-parser.ts b/packages/@angular/cli/utilities/dynamic-path-parser.ts deleted file mode 100644 index b6795b928a09..000000000000 --- a/packages/@angular/cli/utilities/dynamic-path-parser.ts +++ /dev/null @@ -1,77 +0,0 @@ -import * as path from 'path'; -import * as process from 'process'; -import * as fs from 'fs-extra'; -const stringUtils = require('ember-cli-string-utils'); - -export interface DynamicPathOptions { - project: any; - entityName: string; - appConfig: any; - dryRun: boolean; -} - -export function dynamicPathParser(options: DynamicPathOptions) { - const projectRoot = options.project.root; - const sourceDir = options.appConfig.root.replace('/', path.sep); - - const p = options.appConfig.appRoot === undefined - ? 'app' - : options.appConfig.appRoot.replace('/', path.sep); - const appRoot = path.join(sourceDir, p); - const cwd = process.env.PWD; - - const rootPath = path.join(projectRoot, appRoot); - let outputPath = path.join(rootPath, options.entityName); - - if (options.entityName.indexOf(path.sep) === 0) { - outputPath = path.join(rootPath, options.entityName.substr(1)); - } else if (cwd.indexOf(rootPath) >= 0) { - outputPath = path.join(cwd, options.entityName); - } - - if (!fs.existsSync(outputPath)) { - // Verify the path exists on disk. - const parsedOutputPath = path.parse(outputPath); - const parts = parsedOutputPath.dir.split(path.sep).slice(1); - const newPath = parts.reduce((tempPath: string, part: string) => { - // if (tempPath === '') { - // return part; - // } - - const withoutPlus = path.join(tempPath, part); - const withPlus = path.join(tempPath, '+' + part); - if (fs.existsSync(withoutPlus)) { - return withoutPlus; - } else if (fs.existsSync(withPlus)) { - return withPlus; - } - - // Folder not found, create it, and return it - const dasherizedPart = stringUtils.dasherize(part); - const dasherizedDirName = path.join(tempPath, dasherizedPart); - if (!options.dryRun) { - fs.mkdirpSync(dasherizedDirName); - } - return dasherizedDirName; - - }, parsedOutputPath.root); - outputPath = path.join(newPath, parsedOutputPath.name); - } - - if (outputPath.indexOf(rootPath) < 0) { - throw `Invalid path: "${options.entityName}" cannot be ` + - `above the "${appRoot}" directory`; - } - - const adjustedPath = outputPath.replace(projectRoot, ''); - - const parsedPath = path.parse(adjustedPath); - - if (parsedPath.dir.indexOf(path.sep) === 0) { - parsedPath.dir = parsedPath.dir.substr(1); - } - - parsedPath.dir = parsedPath.dir === path.sep ? '' : parsedPath.dir; - - return { ...parsedPath, appRoot, sourceDir }; -} diff --git a/packages/@angular/cli/utilities/find-up.ts b/packages/@angular/cli/utilities/find-up.ts deleted file mode 100644 index bbf5ee0c6037..000000000000 --- a/packages/@angular/cli/utilities/find-up.ts +++ /dev/null @@ -1,30 +0,0 @@ -import * as path from 'path'; -import { existsSync } from 'fs'; - -export function findUp(names: string | string[], from: string, stopOnNodeModules = false) { - if (!Array.isArray(names)) { - names = [names]; - } - const root = path.parse(from).root; - - let currentDir = from; - while (currentDir && currentDir !== root) { - for (const name of names) { - const p = path.join(currentDir, name); - if (existsSync(p)) { - return p; - } - } - - if (stopOnNodeModules) { - const nodeModuleP = path.join(currentDir, 'node_modules'); - if (existsSync(nodeModuleP)) { - return null; - } - } - - currentDir = path.dirname(currentDir); - } - - return null; -} diff --git a/packages/@angular/cli/utilities/is-directory.ts b/packages/@angular/cli/utilities/is-directory.ts deleted file mode 100644 index f8a4b82b83fb..000000000000 --- a/packages/@angular/cli/utilities/is-directory.ts +++ /dev/null @@ -1,9 +0,0 @@ -import * as fs from 'fs'; - -export function isDirectory(path: string) { - try { - return fs.statSync(path).isDirectory(); - } catch (_) { - return false; - } -} diff --git a/packages/@angular/cli/utilities/override-options.ts b/packages/@angular/cli/utilities/override-options.ts deleted file mode 100644 index 4c027abc824c..000000000000 --- a/packages/@angular/cli/utilities/override-options.ts +++ /dev/null @@ -1,12 +0,0 @@ -const cloneDeep = require('lodash/cloneDeep'); - -export function overrideOptions(original: any[], overrides: any[]) { - let copy = cloneDeep(original); - overrides.forEach(override => { - const option = copy.find((opt: any) => opt.name == override.name); - if (option) { - Object.assign(option, override); - } - }); - return copy; -} diff --git a/packages/@angular/cli/utilities/package-chunk-sort.ts b/packages/@angular/cli/utilities/package-chunk-sort.ts deleted file mode 100644 index a7841aeb544c..000000000000 --- a/packages/@angular/cli/utilities/package-chunk-sort.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { ExtraEntry, extraEntryParser } from '../models/webpack-configs/utils'; - -// Sort chunks according to a predefined order: -// inline, polyfills, all styles, vendor, main -export function packageChunkSort(appConfig: any) { - let entryPoints = ['inline', 'polyfills', 'sw-register']; - - const pushExtraEntries = (extraEntry: ExtraEntry) => { - if (entryPoints.indexOf(extraEntry.entry) === -1) { - entryPoints.push(extraEntry.entry); - } - }; - - if (appConfig.styles) { - extraEntryParser(appConfig.styles, './', 'styles').forEach(pushExtraEntries); - } - - entryPoints.push(...['vendor', 'main']); - - function sort(left: any, right: any) { - let leftIndex = entryPoints.indexOf(left.names[0]); - let rightindex = entryPoints.indexOf(right.names[0]); - - if (leftIndex > rightindex) { - return 1; - } else if (leftIndex < rightindex) { - return -1; - } else { - return 0; - } - } - - // We need to list of entry points for the Ejected webpack config to work (we reuse the function - // defined above). - (sort as any).entryPoints = entryPoints; - return sort; -} diff --git a/packages/@angular/cli/utilities/read-tsconfig.ts b/packages/@angular/cli/utilities/read-tsconfig.ts deleted file mode 100644 index 0ee83f2d43e1..000000000000 --- a/packages/@angular/cli/utilities/read-tsconfig.ts +++ /dev/null @@ -1,11 +0,0 @@ -import * as path from 'path'; -import { requireProjectModule } from '../utilities/require-project-module'; - -export function readTsconfig(tsconfigPath: string) { - const projectTs = requireProjectModule(path.dirname(tsconfigPath), 'typescript'); - const configResult = projectTs.readConfigFile(tsconfigPath, projectTs.sys.readFile); - const tsConfig = projectTs.parseJsonConfigFileContent(configResult.config, projectTs.sys, - path.dirname(tsconfigPath), undefined, tsconfigPath); - return tsConfig; -} - diff --git a/packages/@angular/cli/utilities/require-project-module.ts b/packages/@angular/cli/utilities/require-project-module.ts deleted file mode 100644 index a655e99bad1c..000000000000 --- a/packages/@angular/cli/utilities/require-project-module.ts +++ /dev/null @@ -1,6 +0,0 @@ -const resolve = require('resolve'); - -// require dependencies within the target project -export function requireProjectModule(root: string, moduleName: string) { - return require(resolve.sync(moduleName, { basedir: root })); -} diff --git a/packages/@angular/cli/utilities/schematics.ts b/packages/@angular/cli/utilities/schematics.ts deleted file mode 100644 index f94067a8e42c..000000000000 --- a/packages/@angular/cli/utilities/schematics.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Refer to the angular shematics library to let the dependency validator - * know it is used.. - * - * require('@schematics/angular') - */ - -import { - Collection, - Engine, - Schematic, - SchematicEngine, -} from '@angular-devkit/schematics'; -import { - FileSystemCollectionDesc, - FileSystemSchematicDesc, - NodeModulesEngineHost -} from '@angular-devkit/schematics/tools'; -import { SchemaClassFactory } from '@ngtools/json-schema'; -import 'rxjs/add/operator/concatMap'; -import 'rxjs/add/operator/map'; - -const SilentError = require('silent-error'); - -const engineHost = new NodeModulesEngineHost(); -const engine: Engine - = new SchematicEngine(engineHost); - - -export function getEngineHost() { - return engineHost; -} -export function getEngine(): Engine { - return engine; -} - - -export function getCollection(collectionName: string): Collection { - const engineHost = getEngineHost(); - const engine = getEngine(); - - // Add support for schemaJson. - engineHost.registerOptionsTransform((schematic: FileSystemSchematicDesc, options: any) => { - if (schematic.schema) { - const SchemaMetaClass = SchemaClassFactory(schematic.schemaJson!); - const schemaClass = new SchemaMetaClass(options); - return schemaClass.$$root(); - } - return options; - }); - - const collection = engine.createCollection(collectionName); - - if (collection === null) { - throw new SilentError(`Invalid collection (${collectionName}).`); - } - return collection; -} - -export function getSchematic(collection: Collection, - schematicName: string): Schematic { - return collection.createSchematic(schematicName); -} diff --git a/packages/@angular/cli/utilities/service-worker/index.ts b/packages/@angular/cli/utilities/service-worker/index.ts deleted file mode 100644 index 8d8b93ac7f55..000000000000 --- a/packages/@angular/cli/utilities/service-worker/index.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Filesystem } from '@angular/service-worker/config'; -import { stripIndent } from 'common-tags'; -import * as crypto from 'crypto'; -import * as fs from 'fs'; -import * as path from 'path'; -import * as semver from 'semver'; - -export const NEW_SW_VERSION = '>= 5.0.0-rc.0'; - -class CliFilesystem implements Filesystem { - constructor(private base: string) {} - - list(_path: string): Promise { - return Promise.resolve(this.syncList(_path)); - } - - private syncList(_path: string): string[] { - const dir = this.canonical(_path); - const entries = fs.readdirSync(dir).map( - (entry: string) => ({entry, stats: fs.statSync(path.posix.join(dir, entry))})); - const files = entries.filter((entry: any) => !entry.stats.isDirectory()) - .map((entry: any) => path.posix.join(_path, entry.entry)); - - return entries.filter((entry: any) => entry.stats.isDirectory()) - .map((entry: any) => path.posix.join(_path, entry.entry)) - .reduce((list: string[], subdir: string) => list.concat(this.syncList(subdir)), files); - } - - read(_path: string): Promise { - const file = this.canonical(_path); - return Promise.resolve(fs.readFileSync(file).toString()); - } - - hash(_path: string): Promise { - const sha1 = crypto.createHash('sha1'); - const file = this.canonical(_path); - const contents: Buffer = fs.readFileSync(file); - sha1.update(contents); - return Promise.resolve(sha1.digest('hex')); - } - - write(_path: string, contents: string): Promise { - const file = this.canonical(_path); - fs.writeFileSync(file, contents); - return Promise.resolve(); - } - - private canonical(_path: string): string { return path.posix.join(this.base, _path); } -} - -export function usesServiceWorker(projectRoot: string): boolean { - const nodeModules = path.resolve(projectRoot, 'node_modules'); - const swModule = path.resolve(nodeModules, '@angular/service-worker'); - if (!fs.existsSync(swModule)) { - return false; - } - - const swPackageJson = fs.readFileSync(`${swModule}/package.json`).toString(); - const swVersion = JSON.parse(swPackageJson)['version']; - - return semver.satisfies(swVersion, NEW_SW_VERSION); -} - -export function augmentAppWithServiceWorker(projectRoot: string, appRoot: string, - outputPath: string, baseHref: string): Promise { - const nodeModules = path.resolve(projectRoot, 'node_modules'); - const swModule = path.resolve(nodeModules, '@angular/service-worker'); - - // Path to the worker script itself. - const workerPath = path.resolve(swModule, 'ngsw-worker.js'); - const configPath = path.resolve(appRoot, 'ngsw-config.json'); - - if (!fs.existsSync(configPath)) { - throw new Error(stripIndent`Expected to find an ngsw-config.json configuration file in the - application root. Either provide one or disable Service Worker - build support in angular-cli.json.`); - } - const config = fs.readFileSync(configPath, 'utf8'); - - const Generator = require('@angular/service-worker/config').Generator; - const gen = new Generator(new CliFilesystem(outputPath), baseHref); - return gen - .process(JSON.parse(config)) - .then((output: Object) => { - const manifest = JSON.stringify(output, null, 2); - fs.writeFileSync(path.resolve(outputPath, 'ngsw.json'), manifest); - // Copy worker script to dist directory. - const workerCode = fs.readFileSync(workerPath); - fs.writeFileSync(path.resolve(outputPath, 'ngsw-worker.js'), workerCode); - }); -} diff --git a/packages/@angular/cli/utilities/stats.ts b/packages/@angular/cli/utilities/stats.ts deleted file mode 100644 index be9001019aca..000000000000 --- a/packages/@angular/cli/utilities/stats.ts +++ /dev/null @@ -1,62 +0,0 @@ -import chalk from 'chalk'; -import { stripIndents } from 'common-tags'; - - -// Force basic color support on terminals with no color support. -// Chalk typings don't have the correct constructor parameters. -const chalkCtx = new (chalk.constructor as any)(chalk.supportsColor ? {} : { level: 1 }); -const { bold, green, red, reset, white, yellow } = chalkCtx; - -function _formatSize(size: number): string { - if (size <= 0) { - return '0 bytes'; - } - - const abbreviations = ['bytes', 'kB', 'MB', 'GB']; - const index = Math.floor(Math.log(size) / Math.log(1000)); - - return `${+(size / Math.pow(1000, index)).toPrecision(3)} ${abbreviations[index]}`; -} - - -export function statsToString(json: any, statsConfig: any) { - const colors = statsConfig.colors; - const rs = (x: string) => colors ? reset(x) : x; - const w = (x: string) => colors ? bold(white(x)) : x; - const g = (x: string) => colors ? bold(green(x)) : x; - const y = (x: string) => colors ? bold(yellow(x)) : x; - - return rs(stripIndents` - Date: ${w(new Date().toISOString())} - Hash: ${w(json.hash)} - Time: ${w('' + json.time)}ms - ${json.chunks.map((chunk: any) => { - const asset = json.assets.filter((x: any) => x.name == chunk.files[0])[0]; - const size = asset ? ` ${_formatSize(asset.size)}` : ''; - const files = chunk.files.join(', '); - const names = chunk.names ? ` (${chunk.names.join(', ')})` : ''; - const initial = y(chunk.entry ? '[entry]' : chunk.initial ? '[initial]' : ''); - const flags = ['rendered', 'recorded'] - .map(f => f && chunk[f] ? g(` [${f}]`) : '') - .join(''); - - return `chunk {${y(chunk.id)}} ${g(files)}${names}${size} ${initial}${flags}`; - }).join('\n')} - `); -} - -export function statsWarningsToString(json: any, statsConfig: any) { - const colors = statsConfig.colors; - const rs = (x: string) => colors ? reset(x) : x; - const y = (x: string) => colors ? bold(yellow(x)) : x; - - return rs('\n' + json.warnings.map((warning: any) => y(`WARNING in ${warning}`)).join('\n\n')); -} - -export function statsErrorsToString(json: any, statsConfig: any) { - const colors = statsConfig.colors; - const rs = (x: string) => colors ? reset(x) : x; - const r = (x: string) => colors ? bold(red(x)) : x; - - return rs('\n' + json.errors.map((error: any) => r(`ERROR in ${error}`)).join('\n')); -} diff --git a/packages/@angular/cli/utilities/strip-bom.ts b/packages/@angular/cli/utilities/strip-bom.ts deleted file mode 100644 index 480c743982c2..000000000000 --- a/packages/@angular/cli/utilities/strip-bom.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Strip BOM from file data. -// https://stackoverflow.com/questions/24356713 -export function stripBom(data: string) { - return data.replace(/^\uFEFF/, ''); -} diff --git a/packages/@angular/cli/utilities/validate-project-name.ts b/packages/@angular/cli/utilities/validate-project-name.ts deleted file mode 100644 index df7a0ef6e7cb..000000000000 --- a/packages/@angular/cli/utilities/validate-project-name.ts +++ /dev/null @@ -1,40 +0,0 @@ -import {oneLine, stripIndent} from 'common-tags'; - -const SilentError = require('silent-error'); - -const projectNameRegexp = /^[a-zA-Z][.0-9a-zA-Z]*(-[.0-9a-zA-Z]*)*$/; -const unsupportedProjectNames = ['test', 'ember', 'ember-cli', 'vendor', 'app']; - -function getRegExpFailPosition(str: string): number | null { - const parts = str.split('-'); - const matched: string[] = []; - - parts.forEach(part => { - if (part.match(projectNameRegexp)) { - matched.push(part); - } - }); - - const compare = matched.join('-'); - return (str !== compare) ? compare.length : null; -} - -export function validateProjectName(projectName: string) { - const errorIndex = getRegExpFailPosition(projectName); - if (errorIndex !== null) { - const firstMessage = oneLine` - Project name "${projectName}" is not valid. New project names must - start with a letter, and must contain only alphanumeric characters or dashes. - When adding a dash the segment after the dash must also start with a letter. - `; - const msg = stripIndent` - ${firstMessage} - ${projectName} - ${Array(errorIndex + 1).join(' ') + '^'} - `; - throw new SilentError(msg); - } else if (unsupportedProjectNames.indexOf(projectName) !== -1) { - throw new SilentError(`Project name "${projectName}" is not a supported name.`); - } - -} diff --git a/packages/@angular/cli/webpack-custom-typings.d.ts b/packages/@angular/cli/webpack-custom-typings.d.ts deleted file mode 100644 index b57841eb3c17..000000000000 --- a/packages/@angular/cli/webpack-custom-typings.d.ts +++ /dev/null @@ -1,10 +0,0 @@ -import * as webpack from 'webpack'; - -declare module 'webpack' { - export class NamedChunksPlugin { - constructor(nameResolver: (chunk: any) => string | null); - } - export class HashedModuleIdsPlugin { - constructor(); - } -} diff --git a/packages/@ngtools/json-schema/package.json b/packages/@ngtools/json-schema/package.json deleted file mode 100644 index 9a043af510b5..000000000000 --- a/packages/@ngtools/json-schema/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "@ngtools/json-schema", - "version": "1.1.0", - "description": "Schema validating and reading for configurations, similar to Angular CLI config.", - "main": "./src/index.js", - "typings": "src/index.d.ts", - "license": "MIT", - "keywords": [ - "angular", - "json", - "json-schema", - "schema", - "config" - ], - "repository": { - "type": "git", - "url": "https://github.com/angular/angular-cli.git" - }, - "author": "angular", - "bugs": { - "url": "https://github.com/angular/angular-cli/issues" - }, - "homepage": "https://github.com/angular/angular-cli/tree/master/packages/@ngtools/json-schema", - "engines": { - "node": ">= 4.1.0", - "npm": ">= 3.0.0" - }, - "dependencies": { - }, - "peerDependencies": { - } -} diff --git a/packages/@ngtools/json-schema/src/error.ts b/packages/@ngtools/json-schema/src/error.ts deleted file mode 100644 index 5863a5decd4e..000000000000 --- a/packages/@ngtools/json-schema/src/error.ts +++ /dev/null @@ -1,12 +0,0 @@ - -export class JsonSchemaErrorBase extends Error { - constructor(message?: string) { - super(); - - if (message) { - this.message = message; - } else { - this.message = (this.constructor).name; - } - } -} diff --git a/packages/@ngtools/json-schema/src/index.ts b/packages/@ngtools/json-schema/src/index.ts deleted file mode 100644 index 1021cae0c409..000000000000 --- a/packages/@ngtools/json-schema/src/index.ts +++ /dev/null @@ -1 +0,0 @@ -export {SchemaClass, SchemaClassFactory} from './schema-class-factory'; diff --git a/packages/@ngtools/json-schema/src/mimetypes.ts b/packages/@ngtools/json-schema/src/mimetypes.ts deleted file mode 100644 index 6c22ccb9fa81..000000000000 --- a/packages/@ngtools/json-schema/src/mimetypes.ts +++ /dev/null @@ -1,34 +0,0 @@ -import {JsonSchemaErrorBase} from './error'; -import {Serializer, WriterFn} from './serializer'; -import {JsonSerializer} from './serializers/json'; -import {DTsSerializer} from './serializers/dts'; - - -export class UnknownMimetype extends JsonSchemaErrorBase {} - - -export function createSerializerFromMimetype(mimetype: string, - writer: WriterFn, - ...opts: any[]): Serializer { - let Klass: { new (writer: WriterFn, ...args: any[]): Serializer } = null; - switch (mimetype) { - case 'application/json': Klass = JsonSerializer; break; - case 'text/json': Klass = JsonSerializer; break; - case 'text/x.typescript': Klass = DTsSerializer; break; - case 'text/x.dts': Klass = DTsSerializer; break; - - default: throw new UnknownMimetype(); - } - - return new Klass(writer, ...opts); - -} - - -declare module './serializer' { - namespace Serializer { - export let fromMimetype: typeof createSerializerFromMimetype; - } -} - -Serializer.fromMimetype = createSerializerFromMimetype; diff --git a/packages/@ngtools/json-schema/src/node.ts b/packages/@ngtools/json-schema/src/node.ts deleted file mode 100644 index 873ac6697503..000000000000 --- a/packages/@ngtools/json-schema/src/node.ts +++ /dev/null @@ -1,42 +0,0 @@ -import {Serializer} from './serializer'; - - -// A TypeScript Type. This can be used to do `new tsType(value)`. -// `null` implies any type; be careful. -export type TypeScriptType = typeof Number - | typeof Boolean - | typeof String - | typeof Object - | typeof Array - | null; - - -// The most generic interface for a schema node. This is used by the serializers. -export interface SchemaNode { - readonly name: string; - readonly type: string; - readonly tsType: TypeScriptType; - readonly defined: boolean; - readonly dirty: boolean; - readonly frozen: boolean; - readonly readOnly: boolean; - readonly defaultValue: any | null; - readonly required: boolean; - readonly parent: SchemaNode | null; - - // Schema related properties. - readonly description: string | null; - - // Object-only properties. `null` for everything else. - readonly children: { [key: string]: SchemaNode } | null; - - // Array-only properties. `null` for everything else. - readonly items: SchemaNode[] | null; - readonly itemPrototype: SchemaNode | null; - - // Mutable properties. - value: any; - - // Serialization. - serialize(serializer: Serializer): void; -} diff --git a/packages/@ngtools/json-schema/src/schema-class-factory.ts b/packages/@ngtools/json-schema/src/schema-class-factory.ts deleted file mode 100644 index f83bf95d2ca6..000000000000 --- a/packages/@ngtools/json-schema/src/schema-class-factory.ts +++ /dev/null @@ -1,203 +0,0 @@ -import {Serializer} from './serializer'; -import {RootSchemaTreeNode, SchemaTreeNode} from './schema-tree'; -import {JsonSchemaErrorBase} from './error'; - -import './mimetypes'; - -export class InvalidJsonPath extends JsonSchemaErrorBase {} - -// The schema tree node property of the SchemaClass. -const kSchemaNode = Symbol('schema-node'); -// The value property of the SchemaClass. -const kOriginalRoot = Symbol('schema-value'); - - -/** - * Splits a JSON path string into fragments. Fragments can be used to get the value referenced - * by the path. For example, a path of "a[3].foo.bar[2]" would give you a fragment array of - * ["a", 3, "foo", "bar", 2]. - * @param path The JSON string to parse. - * @returns {string[]} The fragments for the string. - * @private - */ -function _parseJsonPath(path: string): string[] { - const fragments = (path || '').split(/\./g); - const result: string[] = []; - - while (fragments.length > 0) { - const fragment = fragments.shift(); - - const match = fragment.match(/([^\[]+)((\[.*\])*)/); - if (!match) { - throw new InvalidJsonPath(); - } - - result.push(match[1]); - if (match[2]) { - const indices = match[2].slice(1, -1).split(']['); - result.push(...indices); - } - } - - return result.filter(fragment => !!fragment); -} - - -/** Get a SchemaTreeNode from the JSON path string. */ -function _getSchemaNodeForPath(rootMetaData: SchemaTreeNode, - path: string): SchemaTreeNode { - let fragments = _parseJsonPath(path); - // TODO: make this work with union (oneOf) schemas - return fragments.reduce((md: SchemaTreeNode, current: string) => { - if (md && md.children) { - return md.children[current]; - } else if (md && md.items) { - return md.items[parseInt(current, 10)]; - } else { - return md; - } - }, rootMetaData); -} - - -/** The interface the SchemaClassFactory returned class implements. */ -export interface SchemaClass extends Object { - $$root(): JsonType; - $$get(path: string): any; - $$set(path: string, value: any): void; - $$alias(source: string, destination: string): boolean; - $$dispose(): void; - - // Metadata of the schema. - $$typeOf(path: string): string; - $$defined(path: string): boolean; - $$delete(path: string): void; - - // Direct access to the schema. - $$schema(): RootSchemaTreeNode; - - $$serialize(mimetype?: string, ...args: any[]): string; -} - - -class SchemaClassBase implements SchemaClass { - constructor(schema: Object, value: T, ...fallbacks: T[]) { - (this as any)[kOriginalRoot] = value; - const forward = fallbacks.length > 0 - ? (new SchemaClassBase(schema, fallbacks.pop(), ...fallbacks).$$schema()) - : null; - (this as any)[kSchemaNode] = new RootSchemaTreeNode(this, { - forward, - value, - schema - }); - } - - $$root(): T { return this as any; } - $$schema(): RootSchemaTreeNode { return (this as any)[kSchemaNode] as RootSchemaTreeNode; } - $$originalRoot(): T { return (this as any)[kOriginalRoot] as T; } - - /** Sets the value of a destination if the value is currently undefined. */ - $$alias(source: string, destination: string) { - let sourceSchemaTreeNode = _getSchemaNodeForPath(this.$$schema(), source); - if (!sourceSchemaTreeNode) { - return false; - } - - const fragments = _parseJsonPath(destination); - const maybeValue = fragments.reduce((value: any, current: string) => { - return value && value[current]; - }, this.$$originalRoot()); - - if (maybeValue !== undefined) { - sourceSchemaTreeNode.set(maybeValue); - return true; - } - return false; - } - - /** Destroy all links between schemas to allow for GC. */ - $$dispose() { - this.$$schema().dispose(); - } - - /** Get a value from a JSON path. */ - $$get(path: string): any { - const node = _getSchemaNodeForPath(this.$$schema(), path); - return node ? node.get() : undefined; - } - - /** Set a value from a JSON path. */ - $$set(path: string, value: any): void { - const node = _getSchemaNodeForPath(this.$$schema(), path); - - if (node) { - node.set(value); - } else { - // This might be inside an object that can have additionalProperties, so - // a TreeNode would not exist. - const splitPath = _parseJsonPath(path); - if (!splitPath) { - return undefined; - } - const parent: any = splitPath - .slice(0, -1) - .reduce((parent: any, curr: string) => parent && parent[curr], this); - - if (parent) { - parent[splitPath[splitPath.length - 1]] = value; - } - } - } - - /** Get the Schema associated with a path. */ - $$typeOf(path: string): string { - const node = _getSchemaNodeForPath(this.$$schema(), path); - return node ? node.type : null; - } - - $$defined(path: string): boolean { - const node = _getSchemaNodeForPath(this.$$schema(), path); - return node ? node.defined : false; - } - - $$delete(path: string) { - const node = _getSchemaNodeForPath(this.$$schema(), path); - if (node) { - node.destroy(); - } - } - - /** Serialize into a string. */ - $$serialize(mimetype = 'application/json', ...options: any[]): string { - let str = ''; - const serializer = Serializer.fromMimetype(mimetype, (s) => str += s, ...options); - - serializer.start(); - this.$$schema().serialize(serializer); - serializer.end(); - - return str; - } -} -export interface SchemaClassFactoryReturn { - new (value: T, ...fallbacks: T[]): SchemaClass; -} - -/** - * Create a class from a JSON SCHEMA object. Instanciating that class with an object - * allows for extended behaviour. - * This is the base API to access the Configuration in the CLI. - * @param schema - * @returns {GeneratedSchemaClass} - * @constructor - */ -export function SchemaClassFactory(schema: Object): SchemaClassFactoryReturn { - class GeneratedSchemaClass extends SchemaClassBase { - constructor(value: T, ...fallbacks: T[]) { - super(schema, value, ...fallbacks); - } - } - - return GeneratedSchemaClass; -} diff --git a/packages/@ngtools/json-schema/src/schema-tree.spec.ts b/packages/@ngtools/json-schema/src/schema-tree.spec.ts deleted file mode 100644 index fb101763a42e..000000000000 --- a/packages/@ngtools/json-schema/src/schema-tree.spec.ts +++ /dev/null @@ -1,93 +0,0 @@ -import {readFileSync} from 'fs'; -import {join} from 'path'; - -import {RootSchemaTreeNode} from './schema-tree'; - - -describe('@ngtools/json-schema', () => { - - describe('OneOfSchemaTreeNode', () => { - const schemaJsonFilePath = join(__dirname, '../tests/schema1.json'); - const schemaJson = JSON.parse(readFileSync(schemaJsonFilePath, 'utf-8')); - const valueJsonFilePath = join(__dirname, '../tests/value1-1.json'); - const valueJson = JSON.parse(readFileSync(valueJsonFilePath, 'utf-8')); - - - it('works', () => { - const proto: any = Object.create(null); - // tslint:disable-next-line - new RootSchemaTreeNode(proto, { - value: valueJson, - schema: schemaJson - }); - - expect(proto.oneOfKey2 instanceof Array).toBe(true); - expect(proto.oneOfKey2.length).toBe(2); - - // Set it to a string, which is valid. - proto.oneOfKey2 = 'hello'; - expect(proto.oneOfKey2 instanceof Array).toBe(false); - }); - - it('returns undefined for values that are non-existent', () => { - const proto: any = Object.create(null); - const root = new RootSchemaTreeNode(proto, { value: valueJson, schema: schemaJson }); - - const value = root.children['objectKey1'].children['objectKey'].children['stringKey'].get(); - expect(value).toBe(undefined); - }); - }); - - - describe('EnumSchemaTreeNode', () => { - const schemaJsonFilePath = join(__dirname, '../tests/schema2.json'); - const schemaJson = JSON.parse(readFileSync(schemaJsonFilePath, 'utf-8')); - const valueJsonFilePath = join(__dirname, '../tests/value2-1.json'); - const valueJson = JSON.parse(readFileSync(valueJsonFilePath, 'utf-8')); - - - it('works', () => { - const proto: any = Object.create(null); - // tslint:disable-next-line - new RootSchemaTreeNode(proto, { - value: valueJson, - schema: schemaJson - }); - - expect(proto.a instanceof Array).toBe(true); - expect(proto.a).toEqual(['v1', 'v3']); - - // Set it to a string, which is valid. - proto.a[0] = 'v2'; - expect(proto.a).toEqual(['v2', 'v3']); - }); - - it('supports default values', () => { - const proto: any = Object.create(null); - const schema = new RootSchemaTreeNode(proto, { - value: valueJson, - schema: schemaJson - }); - - expect(schema.children['b'].get()).toEqual('default'); - }); - - - it('should throw error when setting invalid value', () => { - const proto: any = Object.create(null); - // tslint:disable-next-line - new RootSchemaTreeNode(proto, { - value: valueJson, - schema: schemaJson - }); - - try { - proto.a[0] = 'INVALID'; - } catch (error) { - expect(error.message).toBe('Invalid value can only be one of these: v1,v2,v3'); - } - }); - - }); - -}); diff --git a/packages/@ngtools/json-schema/src/schema-tree.ts b/packages/@ngtools/json-schema/src/schema-tree.ts deleted file mode 100644 index 674e31bb175d..000000000000 --- a/packages/@ngtools/json-schema/src/schema-tree.ts +++ /dev/null @@ -1,535 +0,0 @@ -import {JsonSchemaErrorBase} from './error'; -import {Serializer} from './serializer'; -import {SchemaNode, TypeScriptType} from './node'; - - -export class InvalidSchema extends JsonSchemaErrorBase {} -export class InvalidValueError extends JsonSchemaErrorBase {} -export class MissingImplementationError extends JsonSchemaErrorBase {} -export class SettingReadOnlyPropertyError extends JsonSchemaErrorBase {} -export class InvalidUpdateValue extends JsonSchemaErrorBase {} - -export interface Schema { - [key: string]: any; -} - - -/** This interface is defined to simplify the arguments passed in to the SchemaTreeNode. */ -export type TreeNodeConstructorArgument = { - parent?: SchemaTreeNode; - name?: string; - value: T; - forward?: SchemaTreeNode; - schema: Schema; -}; - - -/** - * Holds all the information, including the value, of a node in the schema tree. - */ -export abstract class SchemaTreeNode implements SchemaNode { - // Hierarchy objects - protected _parent: SchemaTreeNode; - - protected _defined = false; - protected _dirty = false; - - protected _schema: Schema; - protected _name: string; - - protected _value: T; - protected _forward: SchemaTreeNode; - - constructor(nodeMetaData: TreeNodeConstructorArgument) { - this._schema = nodeMetaData.schema; - this._name = nodeMetaData.name; - this._value = nodeMetaData.value; - this._forward = nodeMetaData.forward; - this._parent = nodeMetaData.parent; - } - dispose() { - this._parent = null; - this._schema = null; - this._value = null; - - if (this._forward) { - this._forward.dispose(); - } - this._forward = null; - } - - get defined() { return this._defined; } - get dirty() { return this._dirty; } - set dirty(v: boolean) { - if (v) { - this._defined = true; - this._dirty = true; - if (this._parent) { - this._parent.dirty = true; - } - } - } - - get value(): T { return this.get(); } - - abstract get type(): string; - abstract get tsType(): TypeScriptType; - abstract destroy(): void; - abstract get defaultValue(): any | null; - get name() { return this._name; } - get readOnly(): boolean { return this._schema['readOnly']; } - get frozen(): boolean { return true; } - get description() { - return 'description' in this._schema ? this._schema['description'] : null; - } - get required() { - if (!this._parent) { - return false; - } - return this._parent.isChildRequired(this.name); - } - - isChildRequired(_name: string) { return false; } - - get parent(): SchemaTreeNode { return this._parent; } - get children(): { [key: string]: SchemaTreeNode } | null { return null; } - get items(): SchemaTreeNode[] | null { return null; } - get itemPrototype(): SchemaTreeNode | null { return null; } - - abstract get(): T; - set(_v: T, _init = false, _force = false) { - if (!this.readOnly) { - throw new MissingImplementationError(); - } - throw new SettingReadOnlyPropertyError(); - } - isCompatible(_v: any) { return false; } - - abstract serialize(serializer: Serializer): void; - - protected static _defineProperty(proto: any, treeNode: SchemaTreeNode): void { - if (treeNode.readOnly) { - Object.defineProperty(proto, treeNode.name, { - enumerable: true, - get: () => treeNode.get() - }); - } else { - Object.defineProperty(proto, treeNode.name, { - enumerable: true, - get: () => treeNode.get(), - set: (v: T) => treeNode.set(v) - }); - } - } -} - - -/** Base Class used for Non-Leaves TreeNode. Meaning they can have children. */ -export abstract class NonLeafSchemaTreeNode extends SchemaTreeNode { - dispose() { - for (const key of Object.keys(this.children || {})) { - this.children[key].dispose(); - } - for (let item of this.items || []) { - item.dispose(); - } - super.dispose(); - } - - get() { - if (this.defined) { - return this._value; - } else { - return undefined; - } - } - - destroy() { - this._defined = false; - this._value = null; - } - - // Helper function to create a child based on its schema. - protected _createChildProperty(name: string, value: T, forward: SchemaTreeNode, - schema: Schema, define = true): SchemaTreeNode { - const type: string = - ('oneOf' in schema) ? 'oneOf' : - ('enum' in schema) ? 'enum' : schema['type']; - let Klass: { new (arg: TreeNodeConstructorArgument): SchemaTreeNode } = null; - - switch (type) { - case 'object': Klass = ObjectSchemaTreeNode; break; - case 'array': Klass = ArraySchemaTreeNode; break; - case 'string': Klass = StringSchemaTreeNode; break; - case 'boolean': Klass = BooleanSchemaTreeNode; break; - case 'number': Klass = NumberSchemaTreeNode; break; - case 'integer': Klass = IntegerSchemaTreeNode; break; - - case 'enum': Klass = EnumSchemaTreeNode; break; - case 'oneOf': Klass = OneOfSchemaTreeNode; break; - - default: - throw new InvalidSchema('Type ' + type + ' not understood by SchemaClassFactory.'); - } - - const metaData = new Klass({ parent: this, forward, value, schema, name }); - if (define) { - SchemaTreeNode._defineProperty(this._value, metaData); - } - return metaData; - } -} - - -export class OneOfSchemaTreeNode extends NonLeafSchemaTreeNode { - protected _typesPrototype: SchemaTreeNode[]; - protected _currentTypeHolder: SchemaTreeNode | null; - - constructor(metaData: TreeNodeConstructorArgument) { - super(metaData); - - let { value, forward, schema } = metaData; - this._typesPrototype = schema['oneOf'].map((schema: Object) => { - return this._createChildProperty('', '', forward, schema, false); - }); - - this._currentTypeHolder = null; - this._set(value, true, false); - } - - _set(v: any, init: boolean, force: boolean) { - if (!init && this.readOnly && !force) { - throw new SettingReadOnlyPropertyError(); - } - - // Find the first type prototype that is compatible with the - let proto: SchemaTreeNode = null; - for (let i = 0; i < this._typesPrototype.length; i++) { - const p = this._typesPrototype[i]; - if (p.isCompatible(v)) { - proto = p; - break; - } - } - if (proto == null) { - return; - } - - if (!init) { - this.dirty = true; - } - - this._currentTypeHolder = proto; - this._currentTypeHolder.set(v, false, true); - } - - set(v: any, _init = false, force = false) { - return this._set(v, false, force); - } - - get(): any { - return this._currentTypeHolder ? this._currentTypeHolder.get() : null; - } - get defaultValue(): any | null { - return null; - } - - get defined() { return this._currentTypeHolder ? this._currentTypeHolder.defined : false; } - get items() { return this._typesPrototype; } - get type() { return 'oneOf'; } - get tsType(): null { return null; } - - serialize(serializer: Serializer) { serializer.outputOneOf(this); } -} - - -/** A Schema Tree Node that represents an object. */ -export class ObjectSchemaTreeNode extends NonLeafSchemaTreeNode<{[key: string]: any}> { - // The map of all children metadata. - protected _children: { [key: string]: SchemaTreeNode }; - protected _frozen = false; - - constructor(metaData: TreeNodeConstructorArgument) { - super(metaData); - - this._set(metaData.value, true, false); - } - - _set(value: any, init: boolean, force: boolean) { - if (!init && this.readOnly && !force) { - throw new SettingReadOnlyPropertyError(); - } - - const schema = this._schema; - const forward = this._forward; - - this._defined = !!value; - this._children = Object.create(null); - this._value = Object.create(null); - this._dirty = this._dirty || !init; - - if (schema['properties']) { - for (const name of Object.keys(schema['properties'])) { - const propertySchema = schema['properties'][name]; - this._children[name] = this._createChildProperty( - name, - value ? value[name] : undefined, - forward ? (forward as ObjectSchemaTreeNode).children[name] : null, - propertySchema); - } - } else if (!schema['additionalProperties']) { - throw new InvalidSchema('Schema does not have a properties, but doesnt allow for ' - + 'additional properties.'); - } - - if (!schema['additionalProperties']) { - this._frozen = true; - Object.freeze(this._value); - Object.freeze(this._children); - } else if (value) { - // Set other properties which don't have a schema. - for (const key of Object.keys(value)) { - if (!this._children[key]) { - this._value[key] = value[key]; - } - } - } - } - - set(v: any, force = false) { - return this._set(v, false, force); - } - - get frozen(): boolean { return this._frozen; } - - get children(): { [key: string]: SchemaTreeNode } | null { return this._children; } - get type() { return 'object'; } - get tsType() { return Object; } - get defaultValue(): any | null { return null; } - - isCompatible(v: any) { return typeof v == 'object' && v !== null; } - isChildRequired(name: string) { - if (this._schema['required']) { - return this._schema['required'].indexOf(name) != -1; - } - return false; - } - - serialize(serializer: Serializer) { serializer.object(this); } -} - - -/** A Schema Tree Node that represents an array. */ -export class ArraySchemaTreeNode extends NonLeafSchemaTreeNode> { - // The map of all items metadata. - protected _items: SchemaTreeNode[]; - protected _itemPrototype: SchemaTreeNode; - - constructor(metaData: TreeNodeConstructorArgument>) { - super(metaData); - this._set(metaData.value, true, false); - - // Keep the item's schema as a schema node. This is important to keep type information. - this._itemPrototype = this._createChildProperty( - '', undefined, null, metaData.schema['items'], false); - } - - _set(value: any, init: boolean, _force: boolean) { - const schema = this._schema; - const forward = this._forward; - - this._value = Object.create(null); - this._dirty = this._dirty || !init; - - if (value) { - this._defined = true; - } else { - this._defined = false; - value = []; - } - this._items = []; - this._value = []; - - for (let index = 0; index < value.length; index++) { - this._items[index] = this._createChildProperty( - '' + index, - value && value[index], - forward && (forward as ArraySchemaTreeNode).items[index], - schema['items'] - ); - } - } - - set(v: any, init = false, force = false) { - return this._set(v, init, force); - } - - isCompatible(v: any) { return Array.isArray(v); } - get type() { return 'array'; } - get tsType() { return Array; } - get items(): SchemaTreeNode[] { return this._items; } - get itemPrototype(): SchemaTreeNode { return this._itemPrototype; } - get defaultValue(): any | null { return null; } - - serialize(serializer: Serializer) { serializer.array(this); } -} - - -/** - * The root class of the tree node. Receives a prototype that will be filled with the - * properties of the Schema root. - */ -export class RootSchemaTreeNode extends ObjectSchemaTreeNode { - constructor(proto: any, metaData: TreeNodeConstructorArgument) { - super(metaData); - - for (const key of Object.keys(this._children)) { - if (this._children[key]) { - SchemaTreeNode._defineProperty(proto, this._children[key]); - } - } - } -} - - -/** A leaf in the schema tree. Must contain a single primitive value. */ -export abstract class LeafSchemaTreeNode extends SchemaTreeNode { - protected _default: T; - - constructor(metaData: TreeNodeConstructorArgument) { - super(metaData); - this._defined = metaData.value !== undefined; - if ('default' in metaData.schema) { - this._default = this.convert(metaData.schema['default']); - } - } - - get() { - if (!this.defined && this._forward) { - return this._forward.get(); - } - if (!this.defined) { - return 'default' in this._schema ? this._default : undefined; - } - return this._value === undefined - ? undefined - : (this._value === null ? null : this.convert(this._value)); - } - set(v: T, init = false, force = false) { - if (this.readOnly && !force) { - throw new SettingReadOnlyPropertyError(); - } - - let convertedValue: T | null = this.convert(v); - if (convertedValue === null || convertedValue === undefined) { - if (this.required) { - throw new InvalidValueError(`Invalid value "${v}" on a required field.`); - } - } - - this.dirty = !init; - this._value = convertedValue; - } - - destroy() { - this._defined = false; - this._value = null; - } - - get defaultValue(): T { - return this.hasDefault ? this._default : null; - } - get hasDefault() { - return 'default' in this._schema; - } - - abstract convert(v: any): T; - abstract isCompatible(v: any): boolean; - - serialize(serializer: Serializer) { - serializer.outputValue(this); - } -} - - -/** Basic primitives for JSON Schema. */ -class StringSchemaTreeNode extends LeafSchemaTreeNode { - serialize(serializer: Serializer) { serializer.outputString(this); } - - isCompatible(v: any) { return typeof v == 'string' || v instanceof String; } - convert(v: any) { return v === undefined ? undefined : '' + v; } - get type() { return 'string'; } - get tsType() { return String; } -} - - -class EnumSchemaTreeNode extends LeafSchemaTreeNode { - constructor(metaData: TreeNodeConstructorArgument) { - super(metaData); - - if (!Array.isArray(metaData.schema['enum'])) { - throw new InvalidSchema(); - } - if (this.hasDefault && !this._isInEnum(this._default)) { - throw new InvalidSchema(); - } - this.set(metaData.value, true, true); - } - - protected _isInEnum(value: string) { - return this._schema['enum'].some((v: string) => v === value); - } - - get items() { return this._schema['enum']; } - - set(value: string, init = false, force = false) { - if (!(value === undefined || this._isInEnum(value))) { - throw new InvalidUpdateValue('Invalid value can only be one of these: ' + this.items); - } - super.set(value, init, force); - } - - isCompatible(v: any) { - return this._isInEnum(v); - } - convert(v: any) { - if (v === undefined) { - return undefined; - } - if (!this._isInEnum(v)) { - return undefined; - } - return v; - } - - get type() { - return this._schema['type'] || 'any'; - } - get tsType(): null { return null; } - serialize(serializer: Serializer) { serializer.outputEnum(this); } -} - - -class BooleanSchemaTreeNode extends LeafSchemaTreeNode { - serialize(serializer: Serializer) { serializer.outputBoolean(this); } - - isCompatible(v: any) { return typeof v == 'boolean' || v instanceof Boolean; } - convert(v: any) { return v === undefined ? undefined : !!v; } - get type() { return 'boolean'; } - get tsType() { return Boolean; } -} - - -class NumberSchemaTreeNode extends LeafSchemaTreeNode { - serialize(serializer: Serializer) { serializer.outputNumber(this); } - - isCompatible(v: any) { return typeof v == 'number' || v instanceof Number; } - convert(v: any) { return v === undefined ? undefined : +v; } - get type() { return 'number'; } - get tsType() { return Number; } -} - - -class IntegerSchemaTreeNode extends NumberSchemaTreeNode { - convert(v: any) { return v === undefined ? undefined : Math.floor(+v); } -} diff --git a/packages/@ngtools/json-schema/src/serializer.ts b/packages/@ngtools/json-schema/src/serializer.ts deleted file mode 100644 index 00b2370bc4e7..000000000000 --- a/packages/@ngtools/json-schema/src/serializer.ts +++ /dev/null @@ -1,27 +0,0 @@ -import {JsonSchemaErrorBase} from './error'; -import {SchemaNode} from './node'; -export class InvalidStateError extends JsonSchemaErrorBase {} - - -export interface WriterFn { - (str: string): void; -} - -export abstract class Serializer { - abstract start(): void; - abstract end(): void; - - abstract object(node: SchemaNode): void; - abstract property(node: SchemaNode): void; - abstract array(node: SchemaNode): void; - - abstract outputOneOf(node: SchemaNode): void; - abstract outputEnum(node: SchemaNode): void; - - abstract outputString(node: SchemaNode): void; - abstract outputNumber(node: SchemaNode): void; - abstract outputBoolean(node: SchemaNode): void; - - // Fallback when the value does not have metadata. - abstract outputValue(node: SchemaNode): void; -} diff --git a/packages/@ngtools/json-schema/src/serializers/dts.spec.ts b/packages/@ngtools/json-schema/src/serializers/dts.spec.ts deleted file mode 100644 index 69eb833e5242..000000000000 --- a/packages/@ngtools/json-schema/src/serializers/dts.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as ts from 'typescript'; - -import {DTsSerializer} from './dts'; -import {SchemaClassFactory} from '../schema-class-factory'; -import {RootSchemaTreeNode} from '../schema-tree'; - - -describe('DtsSerializer', () => { - for (const nb of [1, 2, 3]) { - it(`works (${nb})`, () => { - const schemaJsonFilePath = path.join(__dirname, `../../tests/serializer/schema${nb}.json`); - const schemaJson = JSON.parse(fs.readFileSync(schemaJsonFilePath, 'utf-8')); - const valueDTsFilePath = path.join(__dirname, `../../tests/serializer/value${nb}.d.ts`); - const valueDTs = fs.readFileSync(valueDTsFilePath, 'utf-8'); - const valueSourceFile = ts.createSourceFile('test.d.ts', valueDTs, ts.ScriptTarget.Latest); - - const schemaClass = new (SchemaClassFactory(schemaJson))({}); - const schema: RootSchemaTreeNode = schemaClass.$$schema(); - - let str = ''; - function writer(s: string) { - str += s; - } - - const serializer = new DTsSerializer(writer); - - serializer.start(); - schema.serialize(serializer); - serializer.end(); - - const sourceFile = ts.createSourceFile('test.d.ts', str, ts.ScriptTarget.Latest); - expect(sourceFile).toEqual(valueSourceFile); - }); - } -}); diff --git a/packages/@ngtools/json-schema/src/serializers/dts.ts b/packages/@ngtools/json-schema/src/serializers/dts.ts deleted file mode 100644 index 454a69f3e437..000000000000 --- a/packages/@ngtools/json-schema/src/serializers/dts.ts +++ /dev/null @@ -1,165 +0,0 @@ -import {SchemaNode} from '../node'; -import {Serializer, WriterFn, InvalidStateError} from '../serializer'; - - -interface DTsSerializerState { - empty?: boolean; - type?: string; - property?: boolean; -} - -export class DTsSerializer implements Serializer { - private _state: DTsSerializerState[] = []; - - constructor(private _writer: WriterFn, private interfaceName?: string, private _indentDelta = 4) { - if (interfaceName) { - _writer(`export interface ${interfaceName} `); - } else { - _writer('interface _ '); - } - } - - private _willOutputValue() { - if (this._state.length > 0) { - const top = this._top(); - top.empty = false; - - if (!top.property) { - this._indent(); - } - } - } - - private _top(): DTsSerializerState { - return this._state[this._state.length - 1] || {}; - } - - private _indent(): string { - if (this._indentDelta == 0) { - return; - } - - let str = '\n'; - let i = this._state.length * this._indentDelta; - while (i--) { - str += ' '; - } - this._writer(str); - } - - start() {} - end() { - if (this._indentDelta) { - this._writer('\n'); - } - if (!this.interfaceName) { - this._writer('export default _;\n'); - } - } - - object(node: SchemaNode) { - this._willOutputValue(); - - this._writer('{'); - - this._state.push({ empty: true, type: 'object' }); - for (const key of Object.keys(node.children)) { - this.property(node.children[key]); - } - - // Fallback to direct value output for additional properties. - if (!node.frozen) { - this._indent(); - this._writer('[name: string]: any;'); - } - this._state.pop(); - - if (!this._top().empty) { - this._indent(); - } - this._writer('}'); - } - - property(node: SchemaNode) { - this._willOutputValue(); - - if (node.description) { - this._writer('/**'); - this._indent(); - node.description.split('\n').forEach(line => { - this._writer(' * ' + line); - this._indent(); - }); - this._writer(' */'); - this._indent(); - } - - this._writer(node.name); - if (!node.required) { - this._writer('?'); - } - - this._writer(': '); - this._top().property = true; - node.serialize(this); - this._top().property = false; - this._writer(';'); - } - - array(node: SchemaNode) { - this._willOutputValue(); - - node.itemPrototype.serialize(this); - this._writer('[]'); - } - - outputOneOf(node: SchemaNode) { - this._willOutputValue(); - if (!node.items) { - throw new InvalidStateError(); - } - - this._writer('('); - for (let i = 0; i < node.items.length; i++) { - node.items[i].serialize(this); - if (i != node.items.length - 1) { - this._writer(' | '); - } - } - this._writer(')'); - } - - outputEnum(node: SchemaNode) { - this._willOutputValue(); - this._writer('('); - for (let i = 0; i < node.items.length; i++) { - this._writer(JSON.stringify(node.items[i])); - if (i != node.items.length - 1) { - this._writer(' | '); - } - } - this._writer(')'); - } - - outputValue(_node: SchemaNode) { - this._willOutputValue(); - this._writer('any'); - } - - outputString(_node: SchemaNode) { - this._willOutputValue(); - this._writer('string'); - } - outputNumber(_node: SchemaNode) { - this._willOutputValue(); - this._writer('number'); - } - outputInteger(_node: SchemaNode) { - this._willOutputValue(); - this._writer('number'); - } - outputBoolean(_node: SchemaNode) { - this._willOutputValue(); - this._writer('boolean'); - } -} diff --git a/packages/@ngtools/json-schema/src/serializers/json.spec.ts b/packages/@ngtools/json-schema/src/serializers/json.spec.ts deleted file mode 100644 index bf8465161a21..000000000000 --- a/packages/@ngtools/json-schema/src/serializers/json.spec.ts +++ /dev/null @@ -1,34 +0,0 @@ -import * as path from 'path'; -import * as fs from 'fs'; - -import {JsonSerializer} from './json'; -import {SchemaClassFactory} from '../schema-class-factory'; -import {RootSchemaTreeNode} from '../schema-tree'; - - -describe('JsonSerializer', () => { - for (const nb of [1, 2, 3]) { - it(`works (${nb})`, () => { - const schemaJsonFilePath = path.join(__dirname, `../../tests/serializer/schema${nb}.json`); - const schemaJson = JSON.parse(fs.readFileSync(schemaJsonFilePath, 'utf-8')); - const valueJsonFilePath = path.join(__dirname, `../../tests/serializer/value${nb}.json`); - const valueJson = JSON.parse(fs.readFileSync(valueJsonFilePath, 'utf-8')); - - const schemaClass = new (SchemaClassFactory(schemaJson))(valueJson); - const schema: RootSchemaTreeNode = schemaClass.$$schema(); - - let str = ''; - function writer(s: string) { - str += s; - } - - const serializer = new JsonSerializer(writer); - - serializer.start(); - schema.serialize(serializer); - serializer.end(); - - expect(JSON.stringify(JSON.parse(str))).toEqual(JSON.stringify(valueJson)); - }); - } -}); diff --git a/packages/@ngtools/json-schema/src/serializers/json.ts b/packages/@ngtools/json-schema/src/serializers/json.ts deleted file mode 100644 index 2422bb969114..000000000000 --- a/packages/@ngtools/json-schema/src/serializers/json.ts +++ /dev/null @@ -1,159 +0,0 @@ -import {SchemaNode} from '../node'; -import {Serializer, WriterFn} from '../serializer'; - - -interface JsonSerializerState { - empty?: boolean; - type?: string; - property?: boolean; -} - -export class JsonSerializer implements Serializer { - private _state: JsonSerializerState[] = []; - - constructor(private _writer: WriterFn, private _indentDelta = 2) {} - - private _willOutputValue() { - if (this._state.length > 0) { - const top = this._top(); - - const wasEmpty = top.empty; - top.empty = false; - - if (!wasEmpty && !top.property) { - this._writer(','); - } - if (!top.property) { - this._indent(); - } - } - } - - private _top(): JsonSerializerState { - return this._state[this._state.length - 1] || {}; - } - - private _indent(): string { - if (this._indentDelta == 0) { - return; - } - - let str = '\n'; - let i = this._state.length * this._indentDelta; - while (i--) { - str += ' '; - } - this._writer(str); - } - - start() {} - end() { - if (this._indentDelta) { - this._writer('\n'); - } - } - - object(node: SchemaNode) { - if (node.defined == false) { - return; - } - - this._willOutputValue(); - - this._writer('{'); - this._state.push({ empty: true, type: 'object' }); - - for (const key of Object.keys(node.children)) { - this.property(node.children[key]); - } - - // Fallback to direct value output for additional properties. - if (!node.frozen) { - for (const key of Object.keys(node.value)) { - if (key in node.children) { - continue; - } - - this._willOutputValue(); - this._writer(JSON.stringify(key)); - this._writer(': '); - this._writer(JSON.stringify(node.value[key])); - } - } - - this._state.pop(); - - if (!this._top().empty) { - this._indent(); - } - this._writer('}'); - } - - property(node: SchemaNode) { - if (node.defined == false) { - return; - } - - this._willOutputValue(); - - this._writer(JSON.stringify(node.name)); - this._writer(': '); - this._top().property = true; - node.serialize(this); - this._top().property = false; - } - - array(node: SchemaNode) { - if (node.defined == false) { - return; - } - - this._willOutputValue(); - - if (node.items.length === 0) { - this._writer('[]'); - return; - } - - this._writer('['); - this._state.push({ empty: true, type: 'array' }); - for (let i = 0; i < node.items.length; i++) { - node.items[i].serialize(this); - } - this._state.pop(); - - if (!this._top().empty) { - this._indent(); - } - this._writer(']'); - } - - outputOneOf(node: SchemaNode) { - this.outputValue(node); - } - outputEnum(node: SchemaNode) { - this.outputValue(node); - } - - outputValue(node: SchemaNode) { - this._willOutputValue(); - this._writer(JSON.stringify(node.value, null, this._indentDelta)); - } - - outputString(node: SchemaNode) { - this._willOutputValue(); - this._writer(JSON.stringify(node.value)); - } - outputNumber(node: SchemaNode) { - this._willOutputValue(); - this._writer(JSON.stringify(node.value)); - } - outputInteger(node: SchemaNode) { - this._willOutputValue(); - this._writer(JSON.stringify(node.value)); - } - outputBoolean(node: SchemaNode) { - this._willOutputValue(); - this._writer(JSON.stringify(node.value)); - } -} diff --git a/packages/@ngtools/json-schema/tests/schema1.json b/packages/@ngtools/json-schema/tests/schema1.json deleted file mode 100644 index 983feceb8bcd..000000000000 --- a/packages/@ngtools/json-schema/tests/schema1.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "JsonSchema", - "type": "object", - "properties": { - "requiredKey": { - "type": "number" - }, - "stringKeyDefault": { - "type": "string", - "default": "defaultValue" - }, - "stringKey": { - "type": "string" - }, - "booleanKey": { - "type": "boolean" - }, - "numberKey": { - "type": "number" - }, - "oneOfKey1": { - "oneOf": [ - { "type": "string" }, - { "type": "number" } - ] - }, - "oneOfKey2": { - "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "objectKey1": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - }, - "objectKey": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - } - }, - "objectKey2": { - "type": "object", - "properties": { - "stringKey": { - "type": "string", - "default": "default objectKey2.stringKey" - } - }, - "additionalProperties": true - }, - "arrayKey1": { - "type": "array", - "items": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - }, - "arrayKey2": { - "type": "array", - "items": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - } - }, - "required": ["requiredKey"] -} \ No newline at end of file diff --git a/packages/@ngtools/json-schema/tests/schema2.json b/packages/@ngtools/json-schema/tests/schema2.json deleted file mode 100644 index c9a8f1bcf755..000000000000 --- a/packages/@ngtools/json-schema/tests/schema2.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "JsonSchema", - "type": "object", - "properties": { - "a": { - "type": "array", - "items": { - "enum": [ "v1", "v2", "v3" ] - } - }, - "b": { - "enum": [ "default", "v1", "v2" ], - "default": "default" - } - } -} diff --git a/packages/@ngtools/json-schema/tests/serializer/schema1.json b/packages/@ngtools/json-schema/tests/serializer/schema1.json deleted file mode 100644 index 983feceb8bcd..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/schema1.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "JsonSchema", - "type": "object", - "properties": { - "requiredKey": { - "type": "number" - }, - "stringKeyDefault": { - "type": "string", - "default": "defaultValue" - }, - "stringKey": { - "type": "string" - }, - "booleanKey": { - "type": "boolean" - }, - "numberKey": { - "type": "number" - }, - "oneOfKey1": { - "oneOf": [ - { "type": "string" }, - { "type": "number" } - ] - }, - "oneOfKey2": { - "oneOf": [ - { "type": "string" }, - { "type": "array", "items": { "type": "string" } } - ] - }, - "objectKey1": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - }, - "objectKey": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - } - }, - "objectKey2": { - "type": "object", - "properties": { - "stringKey": { - "type": "string", - "default": "default objectKey2.stringKey" - } - }, - "additionalProperties": true - }, - "arrayKey1": { - "type": "array", - "items": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - }, - "arrayKey2": { - "type": "array", - "items": { - "type": "object", - "properties": { - "stringKey": { - "type": "string" - } - } - } - } - }, - "required": ["requiredKey"] -} \ No newline at end of file diff --git a/packages/@ngtools/json-schema/tests/serializer/schema2.json b/packages/@ngtools/json-schema/tests/serializer/schema2.json deleted file mode 100644 index 989f924b8ecf..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/schema2.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "JsonSchema", - "type": "object", - "properties": { - "a": { - "type": "array", - "items": { - "enum": [ "v1", "v2", "v3" ] - } - }, - "b": { - "type": "array", - "items": { - "enum": [ 0, 1, "string", true, null ] - } - } - } -} diff --git a/packages/@ngtools/json-schema/tests/serializer/schema3.json b/packages/@ngtools/json-schema/tests/serializer/schema3.json deleted file mode 100644 index cf863abc8506..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/schema3.json +++ /dev/null @@ -1,234 +0,0 @@ -{ - "$comment": "Please run `npm run build-config-interface` after changing this file. Thanks!", - "$schema": "http://json-schema.org/draft-04/schema#", - "id": "CliConfig", - "title": "Angular CLI Config Schema", - "type": "object", - "properties": { - "project": { - "description": "The global configuration of the project.", - "type": "object", - "properties": { - "version": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "additionalProperties": false - }, - "apps": { - "description": "Properties of the different applications in this project.", - "type": "array", - "items": { - "type": "object", - "properties": { - "root": { - "type": "string" - }, - "outDir": { - "type": "string", - "default": "dist/" - }, - "assets": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "default": [] - }, - "deployUrl": { - "type": "string" - }, - "index": { - "type": "string", - "default": "index.html" - }, - "main": { - "type": "string" - }, - "test": { - "type": "string" - }, - "tsconfig": { - "type": "string", - "default": "tsconfig.json" - }, - "prefix": { - "type": "string" - }, - "styles": { - "description": "Global styles to be included in the build.", - "type": "array", - "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "input": { - "type": "string" - } - }, - "additionalProperties": true - } - ] - }, - "additionalProperties": false - }, - "scripts": { - "description": "Global scripts to be included in the build.", - "type": "array", - "items": { - "oneOf": [ - { - "type": "string" - }, - { - "type": "object", - "properties": { - "input": { - "type": "string" - } - }, - "additionalProperties": true, - "required": ["input"] - } - ] - }, - "additionalProperties": false - }, - "environments": { - "description": "Name and corresponding file for environment config.", - "type": "object", - "additionalProperties": true - } - }, - "additionalProperties": false - }, - "additionalProperties": false - }, - "addons": { - "description": "Configuration reserved for installed third party addons.", - "type": "array", - "items": { - "type": "object", - "properties": {}, - "additionalProperties": true - } - }, - "packages": { - "description": "Configuration reserved for installed third party packages.", - "type": "array", - "items": { - "type": "object", - "properties": {}, - "additionalProperties": true - } - }, - "e2e": { - "type": "object", - "properties": { - "protractor": { - "type": "object", - "properties": { - "config": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "test": { - "type": "object", - "properties": { - "karma": { - "type": "object", - "properties": { - "config": { - "type": "string" - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false - }, - "defaults": { - "type": "object", - "properties": { - "styleExt": { - "type": "string" - }, - "prefixInterfaces": { - "type": "boolean" - }, - "poll": { - "type": "number" - }, - "viewEncapsulation": { - "type": "string" - }, - "changeDetection": { - "type": "string" - }, - "inline": { - "type": "object", - "properties": { - "style": { - "type": "boolean", - "default": false - }, - "template": { - "type": "boolean", - "default": false - } - } - }, - "spec": { - "type": "object", - "properties": { - "class": { - "type": "boolean", - "default": false - }, - "component": { - "type": "boolean", - "default": true - }, - "directive": { - "type": "boolean", - "default": true - }, - "module": { - "type": "boolean", - "default": false - }, - "pipe": { - "type": "boolean", - "default": true - }, - "service": { - "type": "boolean", - "default": true - } - } - } - }, - "additionalProperties": false - } - }, - "additionalProperties": false -} diff --git a/packages/@ngtools/json-schema/tests/serializer/value1.d.ts b/packages/@ngtools/json-schema/tests/serializer/value1.d.ts deleted file mode 100644 index f4ac4a1ff47e..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/value1.d.ts +++ /dev/null @@ -1,26 +0,0 @@ -interface _ { - requiredKey: number; - stringKeyDefault?: string; - stringKey?: string; - booleanKey?: boolean; - numberKey?: number; - oneOfKey1?: (string | number); - oneOfKey2?: (string | string[]); - objectKey1?: { - stringKey?: string; - objectKey?: { - stringKey?: string; - }; - }; - objectKey2?: { - stringKey?: string; - [name: string]: any; - }; - arrayKey1?: { - stringKey?: string; - }[]; - arrayKey2?: { - stringKey?: string; - }[]; -} -export default _; diff --git a/packages/@ngtools/json-schema/tests/serializer/value1.json b/packages/@ngtools/json-schema/tests/serializer/value1.json deleted file mode 100644 index 31f049534148..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/value1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "requiredKey": 1, - "arrayKey2": [ - { "stringKey": "value1" }, - { "stringKey": "value2" } - ] -} \ No newline at end of file diff --git a/packages/@ngtools/json-schema/tests/serializer/value2.d.ts b/packages/@ngtools/json-schema/tests/serializer/value2.d.ts deleted file mode 100644 index 81ffef785d80..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/value2.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -interface _ { - a?: ("v1" | "v2" | "v3")[]; - b?: (0 | 1 | "string" | true | null)[]; -} -export default _; diff --git a/packages/@ngtools/json-schema/tests/serializer/value2.json b/packages/@ngtools/json-schema/tests/serializer/value2.json deleted file mode 100644 index bb8bdf0300c6..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/value2.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "a": [ - "v2", - "v1", - "v2", - "v3" - ], - "b": [ - 1, - null, - "string", - true - ] -} diff --git a/packages/@ngtools/json-schema/tests/serializer/value3.d.ts b/packages/@ngtools/json-schema/tests/serializer/value3.d.ts deleted file mode 100644 index 150edbc203ee..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/value3.d.ts +++ /dev/null @@ -1,85 +0,0 @@ -interface _ { - /** - * The global configuration of the project. - */ - project?: { - version?: string; - name?: string; - }; - /** - * Properties of the different applications in this project. - */ - apps?: { - root?: string; - outDir?: string; - assets?: (string | string[]); - deployUrl?: string; - index?: string; - main?: string; - test?: string; - tsconfig?: string; - prefix?: string; - /** - * Global styles to be included in the build. - */ - styles?: (string | { - input?: string; - [name: string]: any; - })[]; - /** - * Global scripts to be included in the build. - */ - scripts?: (string | { - input: string; - [name: string]: any; - })[]; - /** - * Name and corresponding file for environment config. - */ - environments?: { - [name: string]: any; - }; - }[]; - /** - * Configuration reserved for installed third party addons. - */ - addons?: { - [name: string]: any; - }[]; - /** - * Configuration reserved for installed third party packages. - */ - packages?: { - [name: string]: any; - }[]; - e2e?: { - protractor?: { - config?: string; - }; - }; - test?: { - karma?: { - config?: string; - }; - }; - defaults?: { - styleExt?: string; - prefixInterfaces?: boolean; - poll?: number; - viewEncapsulation?: string; - changeDetection?: string; - inline?: { - style?: boolean; - template?: boolean; - }; - spec?: { - class?: boolean; - component?: boolean; - directive?: boolean; - module?: boolean; - pipe?: boolean; - service?: boolean; - }; - }; -} -export default _; diff --git a/packages/@ngtools/json-schema/tests/serializer/value3.json b/packages/@ngtools/json-schema/tests/serializer/value3.json deleted file mode 100644 index 1ab96e50648d..000000000000 --- a/packages/@ngtools/json-schema/tests/serializer/value3.json +++ /dev/null @@ -1,56 +0,0 @@ -{ - "project": { - "version": "<%= version %>", - "name": "<%= htmlComponentName %>" - }, - "apps": [ - { - "root": "<%= sourceDir %>", - "outDir": "dist", - "assets": [ - "assets", - "favicon.ico" - ], - "index": "index.html", - "main": "main.ts", - "test": "test.ts", - "tsconfig": "tsconfig.json", - "prefix": "<%= prefix %>", - "styles": [ - "styles.<%= styleExt %>" - ], - "scripts": [], - "environments": { - "source": "environments/environment.ts", - "dev": "environments/environment.ts", - "prod": "environments/environment.prod.ts" - } - } - ], - "e2e": { - "protractor": { - "config": "./protractor.conf.js" - } - }, - "test": { - "karma": { - "config": "./karma.conf.js" - } - }, - "defaults": { - "styleExt": "<%= styleExt %>", - "prefixInterfaces": false, - "inline": { - "style": false, - "template": false - }, - "spec": { - "class": false, - "component": true, - "directive": false, - "module": false, - "pipe": true, - "service": false - } - } -} diff --git a/packages/@ngtools/json-schema/tests/value1-1.json b/packages/@ngtools/json-schema/tests/value1-1.json deleted file mode 100644 index 4f2d08d38fb4..000000000000 --- a/packages/@ngtools/json-schema/tests/value1-1.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "requiredKey": 1, - "arrayKey2": [ - { "stringKey": "value1" }, - { "stringKey": "value2" } - ], - "oneOfKey2": [ "hello", "world" ] -} \ No newline at end of file diff --git a/packages/@ngtools/json-schema/tests/value1.json b/packages/@ngtools/json-schema/tests/value1.json deleted file mode 100644 index 31f049534148..000000000000 --- a/packages/@ngtools/json-schema/tests/value1.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "requiredKey": 1, - "arrayKey2": [ - { "stringKey": "value1" }, - { "stringKey": "value2" } - ] -} \ No newline at end of file diff --git a/packages/@ngtools/json-schema/tests/value2-1.json b/packages/@ngtools/json-schema/tests/value2-1.json deleted file mode 100644 index 0bd3cff6754c..000000000000 --- a/packages/@ngtools/json-schema/tests/value2-1.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "a": [ - "v1", - "v3" - ] -} diff --git a/packages/@ngtools/json-schema/tsconfig.json b/packages/@ngtools/json-schema/tsconfig.json deleted file mode 100644 index 775e35fdba6f..000000000000 --- a/packages/@ngtools/json-schema/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - - "compilerOptions": { - "outDir": "../../../dist/@ngtools/json-schema", - "rootDir": ".", - "baseUrl": "" - } -} diff --git a/packages/@ngtools/logger/package.json b/packages/@ngtools/logger/package.json deleted file mode 100644 index 638dc4596df4..000000000000 --- a/packages/@ngtools/logger/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "@ngtools/logger", - "version": "1.1.2", - "description": "", - "main": "./src/index.js", - "typings": "./src/index.d.ts", - "license": "MIT", - "keywords": [ - "reporter", - "logger", - "rxjs", - "typescript", - "log" - ], - "repository": { - "type": "git", - "url": "https://github.com/angular/angular-cli.git" - }, - "author": "angular", - "bugs": { - "url": "https://github.com/angular/angular-cli/issues" - }, - "homepage": "https://github.com/angular/angular-cli/tree/master/packages/@ngtools/logger", - "engines": { - "node": ">= 6.9.0", - "npm": ">= 3.0.0" - }, - "dependencies": { - "rxjs": "^5.0.1" - } -} diff --git a/packages/@ngtools/logger/src/console-logger-stack.spec.ts b/packages/@ngtools/logger/src/console-logger-stack.spec.ts deleted file mode 100644 index f408c44e8f70..000000000000 --- a/packages/@ngtools/logger/src/console-logger-stack.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import {LogEntry, Logger} from './logger'; -import {ConsoleLoggerStack} from './console-logger-stack'; -import {NullLogger} from './null-logger'; - - -describe('ConsoleLoggerStack', () => { - it('works', (done: DoneFn) => { - const logger = ConsoleLoggerStack.start('test'); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'hello', level: 'debug', name: 'test' }), - jasmine.objectContaining({ message: 'world', level: 'info', name: 'test' }), - ]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - (console as any).debug('hello'); - console.log('world'); - ConsoleLoggerStack.end(); - }); - - it('works as a stack', (done: DoneFn) => { - const oldConsoleLog = console.log; - const logger = ConsoleLoggerStack.start('test'); - expect(console.log).not.toBe(oldConsoleLog); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'red', level: 'info', name: 'test' }), - jasmine.objectContaining({ message: 'blue', level: 'info', name: 'test2' }), - jasmine.objectContaining({ message: 'yellow', level: 'info', name: 'test3' }), - jasmine.objectContaining({ message: 'green', level: 'info', name: 'test2' }), - ]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - console.log('red'); - ConsoleLoggerStack.push('test2'); - console.log('blue'); - ConsoleLoggerStack.push('test3'); - console.log('yellow'); - ConsoleLoggerStack.pop(); - console.log('green'); - ConsoleLoggerStack.end(); - expect(console.log).toBe(oldConsoleLog); - }); - - it('can push instances or classes', (done: DoneFn) => { - const oldConsoleLog = console.log; - const logger = new Logger('test'); - ConsoleLoggerStack.start(logger); - expect(console.log).not.toBe(oldConsoleLog); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'red', level: 'info', name: 'test' }), - jasmine.objectContaining({ message: 'green', level: 'info', name: 'test2' }), - ]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - console.log('red'); - ConsoleLoggerStack.push(new NullLogger(logger)); - console.log('blue'); - ConsoleLoggerStack.pop(); - ConsoleLoggerStack.push(new Logger('test2', logger)); - console.log('green'); - ConsoleLoggerStack.end(); - expect(console.log).toBe(oldConsoleLog); - }); -}); diff --git a/packages/@ngtools/logger/src/console-logger-stack.ts b/packages/@ngtools/logger/src/console-logger-stack.ts deleted file mode 100644 index 1814e864baa4..000000000000 --- a/packages/@ngtools/logger/src/console-logger-stack.ts +++ /dev/null @@ -1,123 +0,0 @@ -import {Logger} from './logger'; - -type ConsoleWriter = (message?: any, ...optionalParams: any[]) => void; - -let globalConsoleStack: Logger[] | null = null; -let originalConsoleDebug: ConsoleWriter; -let originalConsoleLog: ConsoleWriter; -let originalConsoleWarn: ConsoleWriter; -let originalConsoleError: ConsoleWriter; - - -function _push(logger: Logger): Logger { - if (!globalConsoleStack) { - throw new Error('ConsoleLoggerStack must be started before pushing a logger.'); - } - - if (globalConsoleStack.length == 0) { - originalConsoleDebug = (console as any).debug; // Some environment (node) don't have debug. - originalConsoleLog = console.log; - originalConsoleWarn = console.warn; - originalConsoleError = console.error; - - (console as any).debug = (msg: string, ...args: any[]) => { - const logger = ConsoleLoggerStack.top(); - if (logger) { - logger.debug(msg, { args }); - } - }; - console.log = (msg: string, ...args: any[]) => { - const logger = ConsoleLoggerStack.top(); - if (logger) { - logger.info(msg, { args }); - } - }; - console.warn = (msg: string, ...args: any[]) => { - const logger = ConsoleLoggerStack.top(); - if (logger) { - logger.warn(msg, { args }); - } - }; - console.error = (msg: string, ...args: any[]) => { - const logger = ConsoleLoggerStack.top(); - if (logger) { - logger.error(msg, { args }); - } - }; - } - globalConsoleStack.push(logger); - - return logger; -} - -function _pop() { - if (!globalConsoleStack) { - return; - } - globalConsoleStack[globalConsoleStack.length - 1].complete(); - globalConsoleStack.pop(); - if (globalConsoleStack.length == 0) { - console.log = originalConsoleLog; - console.warn = originalConsoleWarn; - console.error = originalConsoleError; - (console as any).debug = originalConsoleDebug; // Some environment (node) don't have debug. - globalConsoleStack = null; - } -} - - -export type LoggerConstructor = { - new (...args: any[]): T; -}; - - -export class ConsoleLoggerStack { - static push(name: string): Logger; - static push(logger: Logger): Logger; - static push(loggerClass: LoggerConstructor, ...args: any[]): Logger; - static push(nameOrLogger: string | Logger | LoggerConstructor = '', - ...args: any[]): Logger { - if (typeof nameOrLogger == 'string') { - return _push(new Logger(nameOrLogger, this.top())); - } else if (nameOrLogger instanceof Logger) { - if (nameOrLogger.parent !== this.top()) { - throw new Error('Pushing a logger that is not a direct child of the top of the stack.'); - } - return _push(nameOrLogger); - } else { - return _push(new nameOrLogger(...args, this.top())); - } - } - static pop(): Logger | null { - _pop(); - return this.top(); - } - - static top(): Logger | null { - return globalConsoleStack && globalConsoleStack[globalConsoleStack.length - 1]; - } - - static start(name: string): Logger; - static start(logger: Logger): Logger; - static start(loggerClass: LoggerConstructor, ...args: any[]): Logger; - static start(nameOrLogger: string | Logger | LoggerConstructor = '', - ...args: any[]): Logger { - if (globalConsoleStack !== null) { - throw new Error('Cannot start a new console logger stack while one is already going.'); - } - - globalConsoleStack = []; - if (typeof nameOrLogger == 'string') { - return _push(new Logger(nameOrLogger, this.top())); - } else if (nameOrLogger instanceof Logger) { - return _push(nameOrLogger); - } else { - return _push(new nameOrLogger(...args, this.top())); - } - } - static end() { - while (globalConsoleStack !== null) { - this.pop(); - } - } -} diff --git a/packages/@ngtools/logger/src/indent.spec.ts b/packages/@ngtools/logger/src/indent.spec.ts deleted file mode 100644 index aae7a897c6eb..000000000000 --- a/packages/@ngtools/logger/src/indent.spec.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {LogEntry, Logger} from './logger'; -import {IndentLogger} from './indent'; - - -describe('IndentSpec', () => { - it('works', (done: DoneFn) => { - const logger = new IndentLogger('test'); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'test', level: 'info', name: 'test' }), - jasmine.objectContaining({ message: ' test2', level: 'info', name: 'test2' }), - jasmine.objectContaining({ message: ' test3', level: 'info', name: 'test3' }), - jasmine.objectContaining({ message: ' test4', level: 'info', name: 'test4' }), - jasmine.objectContaining({ message: 'test5', level: 'info', name: 'test' }), - ]); - }) - .then(() => done(), (err: any) => done.fail(err)); - const logger2 = new Logger('test2', logger); - const logger3 = new Logger('test3', logger2); - const logger4 = new Logger('test4', logger); - - logger.info('test'); - logger2.info('test2'); - logger3.info('test3'); - logger4.info('test4'); - logger.info('test5'); - - logger.complete(); - }); -}); diff --git a/packages/@ngtools/logger/src/indent.ts b/packages/@ngtools/logger/src/indent.ts deleted file mode 100644 index 98cdc21f77cb..000000000000 --- a/packages/@ngtools/logger/src/indent.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {Logger} from './logger'; - -import 'rxjs/add/operator/map'; - - -/** - * Keep an map of indentation => array of indentations based on the level. - * This is to optimize calculating the prefix based on the indentation itself. Since most logs - * come from similar levels, and with similar indentation strings, this will be shared by all - * loggers. Also, string concatenation is expensive so performing concats for every log entries - * is expensive; this alleviates it. - */ -const indentationMap: {[indentationType: string]: string[]} = {}; - - -export class IndentLogger extends Logger { - constructor(name: string, parent: Logger | null = null, indentation = ' ') { - super(name, parent); - - indentationMap[indentation] = indentationMap[indentation] || ['']; - const map = indentationMap[indentation]; - - this._observable = this._observable.map(entry => { - const l = entry.path.length; - if (l >= map.length) { - let current = map[map.length - 1]; - while (l >= map.length) { - current += indentation; - map.push(current); - } - } - - entry.message = map[l] + entry.message; - return entry; - }); - } -} diff --git a/packages/@ngtools/logger/src/index.ts b/packages/@ngtools/logger/src/index.ts deleted file mode 100644 index 2c16a440a527..000000000000 --- a/packages/@ngtools/logger/src/index.ts +++ /dev/null @@ -1,6 +0,0 @@ - -export * from './console-logger-stack'; -export * from './indent'; -export * from './logger'; -export * from './null-logger'; -export * from './transform-logger'; diff --git a/packages/@ngtools/logger/src/logger.spec.ts b/packages/@ngtools/logger/src/logger.spec.ts deleted file mode 100644 index 2cc9ed4bad72..000000000000 --- a/packages/@ngtools/logger/src/logger.spec.ts +++ /dev/null @@ -1,46 +0,0 @@ -import {Logger, JsonValue} from './logger'; -import 'rxjs/add/operator/toArray'; -import 'rxjs/add/operator/toPromise'; - - -describe('Logger', () => { - it('works', (done: DoneFn) => { - const logger = new Logger('test'); - logger - .toArray() - .toPromise() - .then((observed: JsonValue[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'hello', level: 'debug', name: 'test' }), - jasmine.objectContaining({ message: 'world', level: 'info', name: 'test' }), - ]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - logger.debug('hello'); - logger.info('world'); - logger.complete(); - }); - - it('works with children', (done: DoneFn) => { - const logger = new Logger('test'); - let hasCompleted = false; - logger - .toArray() - .toPromise() - .then((observed: JsonValue[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'hello', level: 'debug', name: 'child' }), - jasmine.objectContaining({ message: 'world', level: 'info', name: 'child' }), - ]); - expect(hasCompleted).toBe(true); - }) - .then(() => done(), (err: any) => done.fail(err)); - - const childLogger = new Logger('child', logger); - childLogger.subscribe(undefined, undefined, () => hasCompleted = true); - childLogger.debug('hello'); - childLogger.info('world'); - logger.complete(); - }); -}); diff --git a/packages/@ngtools/logger/src/logger.ts b/packages/@ngtools/logger/src/logger.ts deleted file mode 100644 index 716c3b3ff9dc..000000000000 --- a/packages/@ngtools/logger/src/logger.ts +++ /dev/null @@ -1,122 +0,0 @@ -import {Observable} from 'rxjs/Observable'; -import {Operator} from 'rxjs/Operator'; -import {PartialObserver} from 'rxjs/Observer'; -import {Subject} from 'rxjs/Subject'; -import {Subscription} from 'rxjs/Subscription'; - - -export type JsonValue = boolean | number | string | JsonObject | JsonArray; -export interface JsonObject { - [key: string]: JsonValue; -} -export interface JsonArray extends Array {} - -export interface LoggerMetadata extends JsonObject { - name: string; - path: string[]; -} -export interface LogEntry extends LoggerMetadata { - level: LogLevel; - message: string; - timestamp: number; -} - -export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; - - -export class Logger extends Observable { - protected readonly _subject: Subject = new Subject(); - protected _metadata: LoggerMetadata; - - private _obs: Observable; - private _subscription: Subscription | null; - - protected get _observable() { return this._obs; } - protected set _observable(v: Observable) { - if (this._subscription) { - this._subscription.unsubscribe(); - } - this._obs = v; - if (this.parent) { - this._subscription = this.subscribe((value: LogEntry) => { - if (this.parent) { - this.parent._subject.next(value); - } - }, (error: any) => { - if (this.parent) { - this.parent._subject.error(error); - } - }, () => { - if (this._subscription) { - this._subscription.unsubscribe(); - } - this._subscription = null; - }); - } - } - - constructor(public readonly name: string, public readonly parent: Logger | null = null) { - super(); - - let path: string[] = []; - let p = parent; - while (p) { - path.push(p.name); - p = p.parent; - } - this._metadata = { name, path }; - this._observable = this._subject.asObservable(); - if (this.parent) { - // When the parent completes, complete us as well. - this.parent._subject.subscribe(undefined, undefined, () => this.complete()); - } - } - - complete() { - this._subject.complete(); - } - - log(level: LogLevel, message: string, metadata: JsonObject = {}): void { - const entry: LogEntry = Object.assign({}, this._metadata, metadata, { - level, message, timestamp: +Date.now() - }); - this._subject.next(entry); - } - - debug(message: string, metadata: JsonObject = {}) { - return this.log('debug', message, metadata); - } - info(message: string, metadata: JsonObject = {}) { - return this.log('info', message, metadata); - } - warn(message: string, metadata: JsonObject = {}) { - return this.log('warn', message, metadata); - } - error(message: string, metadata: JsonObject = {}) { - return this.log('error', message, metadata); - } - fatal(message: string, metadata: JsonObject = {}) { - return this.log('fatal', message, metadata); - } - - toString() { - return ``; - } - - lift(operator: Operator): Observable { - return this._observable.lift(operator); - } - - subscribe(): Subscription; - subscribe(observer: PartialObserver): Subscription; - subscribe(next?: (value: LogEntry) => void, error?: (error: any) => void, - complete?: () => void): Subscription; - subscribe(_observerOrNext?: PartialObserver | ((value: LogEntry) => void), - _error?: (error: any) => void, - _complete?: () => void): Subscription { - return this._observable.subscribe.apply(this._observable, arguments); - } - forEach(next: (value: LogEntry) => void, PromiseCtor?: typeof Promise): Promise { - return this._observable.forEach(next, PromiseCtor); - } -} diff --git a/packages/@ngtools/logger/src/null-logger.spec.ts b/packages/@ngtools/logger/src/null-logger.spec.ts deleted file mode 100644 index 3b66f4a39dfe..000000000000 --- a/packages/@ngtools/logger/src/null-logger.spec.ts +++ /dev/null @@ -1,37 +0,0 @@ -import {NullLogger} from './null-logger'; -import {LogEntry, Logger} from './logger'; - - -describe('NullLogger', () => { - it('works', (done: DoneFn) => { - const logger = new NullLogger(); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - logger.debug('hello'); - logger.info('world'); - logger.complete(); - }); - - it('nullifies children', (done: DoneFn) => { - const logger = new Logger('test'); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - const nullLogger = new NullLogger(logger); - const child = new Logger('test', nullLogger); - child.debug('hello'); - child.info('world'); - logger.complete(); - }); -}); diff --git a/packages/@ngtools/logger/src/null-logger.ts b/packages/@ngtools/logger/src/null-logger.ts deleted file mode 100644 index e01b4229163e..000000000000 --- a/packages/@ngtools/logger/src/null-logger.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {Logger} from './logger'; - -import {Observable} from 'rxjs/Observable'; - -import 'rxjs/add/observable/empty'; - - -export class NullLogger extends Logger { - constructor(parent: Logger | null = null) { - super('', parent); - this._observable = Observable.empty(); - } -} diff --git a/packages/@ngtools/logger/src/transform-logger.spec.ts b/packages/@ngtools/logger/src/transform-logger.spec.ts deleted file mode 100644 index f0cf572e7023..000000000000 --- a/packages/@ngtools/logger/src/transform-logger.spec.ts +++ /dev/null @@ -1,32 +0,0 @@ -import {TransformLogger} from './transform-logger'; -import {LogEntry} from './logger'; - -import 'rxjs/add/operator/filter'; -import 'rxjs/add/operator/map'; - - -describe('TransformLogger', () => { - it('works', (done: DoneFn) => { - const logger = new TransformLogger('test', stream => { - return stream - .filter(entry => entry.message != 'hello') - .map(entry => { - entry.message += '1'; - return entry; - }); - }); - logger - .toArray() - .toPromise() - .then((observed: LogEntry[]) => { - expect(observed).toEqual([ - jasmine.objectContaining({ message: 'world1', level: 'info', name: 'test' }), - ]); - }) - .then(() => done(), (err: any) => done.fail(err)); - - logger.debug('hello'); - logger.info('world'); - logger.complete(); - }); -}); diff --git a/packages/@ngtools/logger/src/transform-logger.ts b/packages/@ngtools/logger/src/transform-logger.ts deleted file mode 100644 index e4d0a1fb7fcc..000000000000 --- a/packages/@ngtools/logger/src/transform-logger.ts +++ /dev/null @@ -1,13 +0,0 @@ -import {Observable} from 'rxjs/Observable'; - -import {Logger, LogEntry} from './logger'; - - -export class TransformLogger extends Logger { - constructor(name: string, - transform: (stream: Observable) => Observable, - parent: Logger | null = null) { - super(name, parent); - this._observable = transform(this._observable); - } -} diff --git a/packages/@ngtools/logger/tsconfig.json b/packages/@ngtools/logger/tsconfig.json deleted file mode 100644 index 7019e572b507..000000000000 --- a/packages/@ngtools/logger/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - - "compilerOptions": { - "outDir": "../../../dist/@ngtools/logger", - "rootDir": ".", - "baseUrl": "" - } -} diff --git a/packages/@ngtools/webpack/README.md b/packages/@ngtools/webpack/README.md deleted file mode 100644 index fc3fc2529462..000000000000 --- a/packages/@ngtools/webpack/README.md +++ /dev/null @@ -1,84 +0,0 @@ -# Angular Ahead-of-Time Webpack Plugin - -Webpack plugin that AoT compiles your Angular components and modules. - -## Usage - -In your webpack config, add the following plugin and loader. - -Angular version 5 and up, use `AngularCompilerPlugin`: - -```typescript -import {AngularCompilerPlugin} from '@ngtools/webpack' - -exports = { /* ... */ - module: { - rules: [ - { - test: /(?:\.ngfactory\.js|\.ngstyle\.js|\.ts)$/, - loader: '@ngtools/webpack' - } - ] - }, - - plugins: [ - new AngularCompilerPlugin({ - tsConfigPath: 'path/to/tsconfig.json', - entryModule: 'path/to/app.module#AppModule', - sourceMap: true - }) - ] -} -``` - -Angular version 2 and 4, use `AotPlugin`: - -```typescript -import {AotPlugin} from '@ngtools/webpack' - -exports = { /* ... */ - module: { - rules: [ - { - test: /\.ts$/, - loader: '@ngtools/webpack' - } - ] - }, - - plugins: [ - new AotPlugin({ - tsConfigPath: 'path/to/tsconfig.json', - entryModule: 'path/to/app.module#AppModule', - sourceMap: true - }) - ] -} -``` - -The loader works with webpack plugin to compile your TypeScript. It's important to include both, and to not include any other TypeScript compiler loader. - -## Options - -* `tsConfigPath`. The path to the `tsconfig.json` file. This is required. In your `tsconfig.json`, you can pass options to the Angular Compiler with `angularCompilerOptions`. -* `basePath`. Optional. The root to use by the compiler to resolve file paths. By default, use the `tsConfigPath` root. -* `entryModule`. Optional if specified in `angularCompilerOptions`. The path and classname of the main application module. This follows the format `path/to/file#ClassName`. -* `mainPath`. Optional if `entryModule` is specified. The `main.ts` file containing the bootstrap code. The plugin will use AST to determine the `entryModule`. -* `skipCodeGeneration`. Optional, defaults to false. Disable code generation and do not refactor the code to bootstrap. This replaces `templateUrl: "string"` with `template: require("string")` (and similar for styles) to allow for webpack to properly link the resources. Only available in `AotPlugin`. -* `typeChecking`. Optional, defaults to true. Enable type checking through your application. This will slow down compilation, but show syntactic and semantic errors in webpack. Only available in `AotPlugin`. -* `exclude`. Optional. Extra files to exclude from TypeScript compilation. Not supported with `AngularCompilerPlugin`. -* `sourceMap`. Optional. Include sourcemaps. -* `compilerOptions`. Optional. Override options in `tsconfig.json`. - -## Features -The benefits and ability of using [`@ngtools/webpack`](https://www.npmjs.com/~ngtools) standalone from the Angular CLI as presented in [Stephen Fluin's Angular CLI talk](https://youtu.be/uBRK6cTr4Vk?t=6m45s) at Angular Connect 2016: - -* Compiles SCSS/LESS -* TypeScript transpilation -* Bundles JavaScript, CSS -* Asset optimization -* Virtual filesystem for assets - * For serving local assets and compile versions. -* Live-reload via websockets -* Code splitting - * Recognizing the use of `loadChildren` in the router, and bundling those modules separately so that any dependencies of those modules are not going to be loaded as part of your main bundle. These separate bundles will be pulled out of the critical path of your application, making your total application bundle much smaller and loading it much more performant. diff --git a/packages/@ngtools/webpack/package.json b/packages/@ngtools/webpack/package.json deleted file mode 100644 index 3b7d315e8138..000000000000 --- a/packages/@ngtools/webpack/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "@ngtools/webpack", - "version": "1.9.0-beta.2", - "description": "Webpack plugin that AoT compiles your Angular components and modules.", - "main": "./src/index.js", - "typings": "src/index.d.ts", - "license": "MIT", - "keywords": [ - "angular", - "webpack", - "plugin", - "aot" - ], - "repository": { - "type": "git", - "url": "https://github.com/angular/angular-cli.git" - }, - "author": "angular", - "bugs": { - "url": "https://github.com/angular/angular-cli/issues" - }, - "homepage": "https://github.com/angular/angular-cli/tree/master/packages/@ngtools/webpack", - "engines": { - "node": ">= 4.1.0", - "npm": ">= 3.0.0" - }, - "dependencies": { - "tree-kill": "^1.0.0", - "chalk": "~2.2.0", - "loader-utils": "^1.0.2", - "enhanced-resolve": "^3.1.0", - "magic-string": "^0.22.3", - "semver": "^5.3.0", - "source-map": "^0.5.6" - }, - "peerDependencies": { - "webpack": "^2.2.0 || ^3.0.0" - } -} diff --git a/packages/@ngtools/webpack/src/angular_compiler_plugin.ts b/packages/@ngtools/webpack/src/angular_compiler_plugin.ts deleted file mode 100644 index f0c8342791d6..000000000000 --- a/packages/@ngtools/webpack/src/angular_compiler_plugin.ts +++ /dev/null @@ -1,990 +0,0 @@ -// @ignoreDep typescript -import * as fs from 'fs'; -import { fork, ForkOptions, ChildProcess } from 'child_process'; -import * as path from 'path'; -import * as ts from 'typescript'; - -const ContextElementDependency = require('webpack/lib/dependencies/ContextElementDependency'); -const treeKill = require('tree-kill'); - -import { WebpackResourceLoader } from './resource_loader'; -import { WebpackCompilerHost } from './compiler_host'; -import { Tapable } from './webpack'; -import { PathsPlugin } from './paths-plugin'; -import { findLazyRoutes, LazyRouteMap } from './lazy_routes'; -import { - VirtualFileSystemDecorator, - VirtualWatchFileSystemDecorator -} from './virtual_file_system_decorator'; -import { resolveEntryModuleFromMain } from './entry_resolver'; -import { - replaceBootstrap, - exportNgFactory, - exportLazyModuleMap, - removeDecorators, - registerLocaleData, - findResources, - replaceResources, -} from './transformers'; -import { time, timeEnd } from './benchmark'; -import { InitMessage, UpdateMessage } from './type_checker'; -import { gatherDiagnostics, hasErrors } from './gather_diagnostics'; -import { - CompilerCliIsSupported, - __NGTOOLS_PRIVATE_API_2, - VERSION, - DEFAULT_ERROR_CODE, - UNKNOWN_ERROR_CODE, - SOURCE, - Program, - CompilerOptions, - CompilerHost, - Diagnostics, - EmitFlags, - LazyRoute, - createProgram, - createCompilerHost, - formatDiagnostics, - readConfiguration, -} from './ngtools_api'; -import { collectDeepNodes } from './transformers/ast_helpers'; - - -/** - * Option Constants - */ -export interface AngularCompilerPluginOptions { - sourceMap?: boolean; - tsConfigPath: string; - basePath?: string; - entryModule?: string; - mainPath?: string; - skipCodeGeneration?: boolean; - hostReplacementPaths?: { [path: string]: string }; - // TODO: remove singleFileIncludes for 2.0, this is just to support old projects that did not - // include 'polyfills.ts' in `tsconfig.spec.json'. - singleFileIncludes?: string[]; - i18nInFile?: string; - i18nInFormat?: string; - i18nOutFile?: string; - i18nOutFormat?: string; - locale?: string; - missingTranslation?: string; - platform?: PLATFORM; - - // Use tsconfig to include path globs. - compilerOptions?: ts.CompilerOptions; -} - -export enum PLATFORM { - Browser, - Server -} - -export class AngularCompilerPlugin implements Tapable { - private _options: AngularCompilerPluginOptions; - - // TS compilation. - private _compilerOptions: CompilerOptions; - private _rootNames: string[]; - private _singleFileIncludes: string[] = []; - private _program: (ts.Program | Program); - private _compilerHost: WebpackCompilerHost & CompilerHost; - private _moduleResolutionCache: ts.ModuleResolutionCache; - private _resourceLoader: WebpackResourceLoader; - // Contains `moduleImportPath#exportName` => `fullModulePath`. - private _lazyRoutes: LazyRouteMap = Object.create(null); - private _tsConfigPath: string; - private _entryModule: string; - private _mainPath: string | undefined; - private _basePath: string; - private _transformers: ts.TransformerFactory[] = []; - private _platform: PLATFORM; - private _JitMode = false; - private _emitSkipped = true; - - // Webpack plugin. - private _firstRun = true; - private _donePromise: Promise | null; - private _compiler: any = null; - private _compilation: any = null; - - // TypeChecker process. - private _forkTypeChecker = true; - private _typeCheckerProcess: ChildProcess; - - private get _ngCompilerSupportsNewApi() { - if (this._JitMode) { - return false; - } else { - return !!(this._program as Program).listLazyRoutes; - } - } - - constructor(options: AngularCompilerPluginOptions) { - CompilerCliIsSupported(); - this._options = Object.assign({}, options); - this._setupOptions(this._options); - } - - get options() { return this._options; } - get done() { return this._donePromise; } - get entryModule() { - if (!this._entryModule) { - return undefined; - } - const splitted = this._entryModule.split('#'); - const path = splitted[0]; - const className = splitted[1] || 'default'; - return { path, className }; - } - - static isSupported() { - return VERSION && parseInt(VERSION.major) >= 5; - } - - private _setupOptions(options: AngularCompilerPluginOptions) { - time('AngularCompilerPlugin._setupOptions'); - // Fill in the missing options. - if (!options.hasOwnProperty('tsConfigPath')) { - throw new Error('Must specify "tsConfigPath" in the configuration of @ngtools/webpack.'); - } - // TS represents paths internally with '/' and expects the tsconfig path to be in this format - this._tsConfigPath = options.tsConfigPath.replace(/\\/g, '/'); - - // Check the base path. - const maybeBasePath = path.resolve(process.cwd(), this._tsConfigPath); - let basePath = maybeBasePath; - if (fs.statSync(maybeBasePath).isFile()) { - basePath = path.dirname(basePath); - } - if (options.hasOwnProperty('basePath')) { - basePath = path.resolve(process.cwd(), options.basePath); - } - - if (options.singleFileIncludes !== undefined) { - this._singleFileIncludes.push(...options.singleFileIncludes); - } - - // Parse the tsconfig contents. - const config = readConfiguration(this._tsConfigPath); - if (config.errors && config.errors.length) { - throw new Error(formatDiagnostics(config.errors)); - } - - this._rootNames = config.rootNames.concat(...this._singleFileIncludes); - this._compilerOptions = config.options; - this._basePath = config.options.basePath; - - // Overwrite outDir so we can find generated files next to their .ts origin in compilerHost. - this._compilerOptions.outDir = ''; - - // Default plugin sourceMap to compiler options setting. - if (!options.hasOwnProperty('sourceMap')) { - options.sourceMap = this._compilerOptions.sourceMap || false; - } - - // Force the right sourcemap options. - if (options.sourceMap) { - this._compilerOptions.sourceMap = true; - this._compilerOptions.inlineSources = true; - this._compilerOptions.inlineSourceMap = false; - this._compilerOptions.mapRoot = undefined; - // We will set the source to the full path of the file in the loader, so we don't - // need sourceRoot here. - this._compilerOptions.sourceRoot = undefined; - } else { - this._compilerOptions.sourceMap = false; - this._compilerOptions.sourceRoot = undefined; - this._compilerOptions.inlineSources = undefined; - this._compilerOptions.inlineSourceMap = undefined; - this._compilerOptions.mapRoot = undefined; - this._compilerOptions.sourceRoot = undefined; - } - - // We want to allow emitting with errors so that imports can be added - // to the webpack dependency tree and rebuilds triggered by file edits. - this._compilerOptions.noEmitOnError = false; - - // Set JIT (no code generation) or AOT mode. - if (options.skipCodeGeneration !== undefined) { - this._JitMode = options.skipCodeGeneration; - } - - // Process i18n options. - if (options.i18nInFile !== undefined) { - this._compilerOptions.i18nInFile = options.i18nInFile; - } - if (options.i18nInFormat !== undefined) { - this._compilerOptions.i18nInFormat = options.i18nInFormat; - } - if (options.i18nOutFile !== undefined) { - this._compilerOptions.i18nOutFile = options.i18nOutFile; - } - if (options.i18nOutFormat !== undefined) { - this._compilerOptions.i18nOutFormat = options.i18nOutFormat; - } - if (options.locale !== undefined) { - this._compilerOptions.i18nInLocale = this._validateLocale(options.locale); - } - if (options.missingTranslation !== undefined) { - this._compilerOptions.i18nInMissingTranslations = - options.missingTranslation as 'error' | 'warning' | 'ignore'; - } - - // Create the webpack compiler host. - const webpackCompilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath); - webpackCompilerHost.enableCaching(); - - // Create and set a new WebpackResourceLoader. - this._resourceLoader = new WebpackResourceLoader(); - webpackCompilerHost.setResourceLoader(this._resourceLoader); - - // Use the WebpackCompilerHost with a resource loader to create an AngularCompilerHost. - this._compilerHost = createCompilerHost({ - options: this._compilerOptions, - tsHost: webpackCompilerHost - }) as CompilerHost & WebpackCompilerHost; - - // Override some files in the FileSystem with paths from the actual file system. - if (this._options.hostReplacementPaths) { - for (const filePath of Object.keys(this._options.hostReplacementPaths)) { - const replacementFilePath = this._options.hostReplacementPaths[filePath]; - const content = this._compilerHost.readFile(replacementFilePath); - this._compilerHost.writeFile(filePath, content, false); - } - } - - // Use an identity function as all our paths are absolute already. - this._moduleResolutionCache = ts.createModuleResolutionCache(this._basePath, x => x); - - // Resolve mainPath if provided. - if (options.mainPath) { - this._mainPath = this._compilerHost.resolve(options.mainPath); - } - - // Use entryModule if available in options, otherwise resolve it from mainPath after program - // creation. - if (this._options.entryModule) { - this._entryModule = this._options.entryModule; - } else if (this._compilerOptions.entryModule) { - this._entryModule = path.resolve(this._basePath, - this._compilerOptions.entryModule); - } - - // Set platform. - this._platform = options.platform || PLATFORM.Browser; - - // Make transformers. - this._makeTransformers(); - - timeEnd('AngularCompilerPlugin._setupOptions'); - } - - private _getTsProgram() { - return this._JitMode ? this._program as ts.Program : (this._program as Program).getTsProgram(); - } - - private _getChangedTsFiles() { - return this._compilerHost.getChangedFilePaths() - .filter(k => k.endsWith('.ts') && !k.endsWith('.d.ts')) - .filter(k => this._compilerHost.fileExists(k)); - } - - private _getChangedCompilationFiles() { - return this._compilerHost.getChangedFilePaths() - .filter(k => /\.(?:ts|html|css|scss|sass|less|styl)$/.test(k)); - } - - private _createOrUpdateProgram() { - return Promise.resolve() - .then(() => { - // Get the root files from the ts config. - // When a new root name (like a lazy route) is added, it won't be available from - // following imports on the existing files, so we need to get the new list of root files. - const config = readConfiguration(this._tsConfigPath); - this._rootNames = config.rootNames.concat(...this._singleFileIncludes); - - // Update the forked type checker with all changed compilation files. - // This includes templates, that also need to be reloaded on the type checker. - if (this._forkTypeChecker && !this._firstRun) { - this._updateForkedTypeChecker(this._rootNames, this._getChangedCompilationFiles()); - } - - if (this._JitMode) { - // Create the TypeScript program. - time('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram'); - this._program = ts.createProgram( - this._rootNames, - this._compilerOptions, - this._compilerHost, - this._program as ts.Program - ); - timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ts.createProgram'); - - return Promise.resolve(); - } else { - time('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram'); - // Create the Angular program. - this._program = createProgram({ - rootNames: this._rootNames, - options: this._compilerOptions, - host: this._compilerHost, - oldProgram: this._program as Program - }); - timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.createProgram'); - - time('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync'); - return this._program.loadNgStructureAsync() - .then(() => { - timeEnd('AngularCompilerPlugin._createOrUpdateProgram.ng.loadNgStructureAsync'); - }); - } - }) - .then(() => { - // If there's still no entryModule try to resolve from mainPath. - if (!this._entryModule && this._mainPath) { - time('AngularCompilerPlugin._make.resolveEntryModuleFromMain'); - this._entryModule = resolveEntryModuleFromMain( - this._mainPath, this._compilerHost, this._getTsProgram()); - timeEnd('AngularCompilerPlugin._make.resolveEntryModuleFromMain'); - } - }); - } - - private _getLazyRoutesFromNgtools() { - try { - time('AngularCompilerPlugin._getLazyRoutesFromNgtools'); - const result = __NGTOOLS_PRIVATE_API_2.listLazyRoutes({ - program: this._getTsProgram(), - host: this._compilerHost, - angularCompilerOptions: Object.assign({}, this._compilerOptions, { - // genDir seems to still be needed in @angular\compiler-cli\src\compiler_host.js:226. - genDir: '' - }), - entryModule: this._entryModule - }); - timeEnd('AngularCompilerPlugin._getLazyRoutesFromNgtools'); - return result; - } catch (err) { - // We silence the error that the @angular/router could not be found. In that case, there is - // basically no route supported by the app itself. - if (err.message.startsWith('Could not resolve module @angular/router')) { - return {}; - } else { - throw err; - } - } - } - - private _findLazyRoutesInAst(changedFilePaths: string[]): LazyRouteMap { - time('AngularCompilerPlugin._findLazyRoutesInAst'); - const result: LazyRouteMap = Object.create(null); - for (const filePath of changedFilePaths) { - const fileLazyRoutes = findLazyRoutes(filePath, this._compilerHost, undefined, - this._compilerOptions); - for (const routeKey of Object.keys(fileLazyRoutes)) { - const route = fileLazyRoutes[routeKey]; - result[routeKey] = route; - } - } - timeEnd('AngularCompilerPlugin._findLazyRoutesInAst'); - return result; - } - - private _listLazyRoutesFromProgram(): LazyRouteMap { - const ngProgram = this._program as Program; - if (!ngProgram.listLazyRoutes) { - throw new Error('_listLazyRoutesFromProgram was called with an old program.'); - } - - const lazyRoutes = ngProgram.listLazyRoutes(); - - return lazyRoutes.reduce( - (acc: LazyRouteMap, curr: LazyRoute) => { - const ref = curr.route; - if (ref in acc && acc[ref] !== curr.referencedModule.filePath) { - throw new Error( - + `Duplicated path in loadChildren detected: "${ref}" is used in 2 loadChildren, ` - + `but they point to different modules "(${acc[ref]} and ` - + `"${curr.referencedModule.filePath}"). Webpack cannot distinguish on context and ` - + 'would fail to load the proper one.' - ); - } - acc[ref] = curr.referencedModule.filePath; - return acc; - }, - {} as LazyRouteMap - ); - } - - // Process the lazy routes discovered, adding then to _lazyRoutes. - // TODO: find a way to remove lazy routes that don't exist anymore. - // This will require a registry of known references to a lazy route, removing it when no - // module references it anymore. - private _processLazyRoutes(discoveredLazyRoutes: { [route: string]: string; }) { - Object.keys(discoveredLazyRoutes) - .forEach(lazyRouteKey => { - const [lazyRouteModule, moduleName] = lazyRouteKey.split('#'); - - if (!lazyRouteModule || !moduleName) { - return; - } - - const lazyRouteTSFile = discoveredLazyRoutes[lazyRouteKey]; - let modulePath: string, moduleKey: string; - - if (this._JitMode) { - modulePath = lazyRouteTSFile; - moduleKey = lazyRouteKey; - } else { - modulePath = lazyRouteTSFile.replace(/(\.d)?\.ts$/, `.ngfactory.js`); - moduleKey = `${lazyRouteModule}.ngfactory#${moduleName}NgFactory`; - } - - if (moduleKey in this._lazyRoutes) { - if (this._lazyRoutes[moduleKey] !== modulePath) { - // Found a duplicate, this is an error. - this._compilation.warnings.push( - new Error(`Duplicated path in loadChildren detected during a rebuild. ` - + `We will take the latest version detected and override it to save rebuild time. ` - + `You should perform a full build to validate that your routes don't overlap.`) - ); - } - } else { - // Found a new route, add it to the map. - this._lazyRoutes[moduleKey] = modulePath; - } - }); - } - - private _createForkedTypeChecker() { - // Bootstrap type checker is using local CLI. - const g: any = global; - const typeCheckerFile: string = g['angularCliIsLocal'] - ? './type_checker_bootstrap.js' - : './type_checker.js'; - - const debugArgRegex = /--inspect(?:-brk|-port)?|--debug(?:-brk|-port)/; - - const execArgv = process.execArgv.filter((arg) => { - // Remove debug args. - // Workaround for https://github.com/nodejs/node/issues/9435 - return !debugArgRegex.test(arg); - }); - - const forkOptions: ForkOptions = { execArgv }; - - this._typeCheckerProcess = fork(path.resolve(__dirname, typeCheckerFile), [], forkOptions); - this._typeCheckerProcess.send(new InitMessage(this._compilerOptions, this._basePath, - this._JitMode, this._rootNames)); - - // Cleanup. - const killTypeCheckerProcess = () => { - treeKill(this._typeCheckerProcess.pid, 'SIGTERM'); - process.exit(); - }; - process.once('exit', killTypeCheckerProcess); - process.once('SIGINT', killTypeCheckerProcess); - process.once('uncaughtException', killTypeCheckerProcess); - } - - private _updateForkedTypeChecker(rootNames: string[], changedCompilationFiles: string[]) { - this._typeCheckerProcess.send(new UpdateMessage(rootNames, changedCompilationFiles)); - } - - - // Registration hook for webpack plugin. - apply(compiler: any) { - this._compiler = compiler; - - // Decorate inputFileSystem to serve contents of CompilerHost. - // Use decorated inputFileSystem in watchFileSystem. - compiler.plugin('environment', () => { - compiler.inputFileSystem = new VirtualFileSystemDecorator( - compiler.inputFileSystem, this._compilerHost); - compiler.watchFileSystem = new VirtualWatchFileSystemDecorator(compiler.inputFileSystem); - }); - - // Add lazy modules to the context module for @angular/core - compiler.plugin('context-module-factory', (cmf: any) => { - const angularCorePackagePath = require.resolve('@angular/core/package.json'); - const angularCorePackageJson = require(angularCorePackagePath); - const angularCoreModulePath = path.resolve(path.dirname(angularCorePackagePath), - angularCorePackageJson['module']); - // Pick the last part after the last node_modules instance. We do this to let people have - // a linked @angular/core or cli which would not be under the same path as the project - // being built. - const angularCoreModuleDir = path.dirname(angularCoreModulePath).split(/node_modules/).pop(); - - // Also support the es2015 in Angular versions that have it. - let angularCoreEs2015Dir: string | undefined; - if (angularCorePackageJson['es2015']) { - const angularCoreEs2015Path = path.resolve(path.dirname(angularCorePackagePath), - angularCorePackageJson['es2015']); - angularCoreEs2015Dir = path.dirname(angularCoreEs2015Path).split(/node_modules/).pop(); - } - - cmf.plugin('after-resolve', (result: any, callback: (err?: any, request?: any) => void) => { - if (!result) { - return callback(); - } - - // Alter only request from Angular. - if (!(angularCoreModuleDir && result.resource.endsWith(angularCoreModuleDir)) - && !(angularCoreEs2015Dir && result.resource.endsWith(angularCoreEs2015Dir))) { - return callback(null, result); - } - - this.done!.then(() => { - // This folder does not exist, but we need to give webpack a resource. - // TODO: check if we can't just leave it as is (angularCoreModuleDir). - result.resource = path.join(this._basePath, '$$_lazy_route_resource'); - result.dependencies.forEach((d: any) => d.critical = false); - result.resolveDependencies = (_fs: any, _resource: any, _recursive: any, - _regExp: RegExp, cb: any) => { - const dependencies = Object.keys(this._lazyRoutes) - .map((key) => { - const modulePath = this._lazyRoutes[key]; - const importPath = key.split('#')[0]; - if (modulePath !== null) { - return new ContextElementDependency(modulePath, importPath); - } else { - return null; - } - }) - .filter(x => !!x); - cb(null, dependencies); - }; - return callback(null, result); - }, () => callback(null)) - .catch(err => callback(err)); - }); - }); - - // Remake the plugin on each compilation. - compiler.plugin('make', (compilation: any, cb: any) => this._make(compilation, cb)); - compiler.plugin('invalid', () => this._firstRun = false); - compiler.plugin('after-emit', (compilation: any, cb: any) => { - compilation._ngToolsWebpackPluginInstance = null; - cb(); - }); - compiler.plugin('done', () => { - this._donePromise = null; - this._compilation = null; - }); - - // TODO: consider if it's better to remove this plugin and instead make it wait on the - // VirtualFileSystemDecorator. - compiler.plugin('after-resolvers', (compiler: any) => { - // Virtual file system. - // Wait for the plugin to be done when requesting `.ts` files directly (entry points), or - // when the issuer is a `.ts` or `.ngfactory.js` file. - compiler.resolvers.normal.plugin('before-resolve', (request: any, cb: () => void) => { - if (request.request.endsWith('.ts') - || (request.context.issuer && /\.ts|ngfactory\.js$/.test(request.context.issuer))) { - this.done!.then(() => cb(), () => cb()); - } else { - cb(); - } - }); - }); - - compiler.plugin('normal-module-factory', (nmf: any) => { - compiler.resolvers.normal.apply(new PathsPlugin({ - nmf, - tsConfigPath: this._tsConfigPath, - compilerOptions: this._compilerOptions, - compilerHost: this._compilerHost - })); - }); - } - - private _make(compilation: any, cb: (err?: any, request?: any) => void) { - time('AngularCompilerPlugin._make'); - this._compilation = compilation; - this._emitSkipped = true; - if (this._compilation._ngToolsWebpackPluginInstance) { - return cb(new Error('An @ngtools/webpack plugin already exist for this compilation.')); - } - - // Set a private variable for this plugin instance. - this._compilation._ngToolsWebpackPluginInstance = this; - - // Update the resource loader with the new webpack compilation. - this._resourceLoader.update(compilation); - - // Create a new process for the type checker on the second build if there isn't one yet. - if (this._forkTypeChecker && !this._firstRun && !this._typeCheckerProcess) { - this._createForkedTypeChecker(); - } - - this._donePromise = Promise.resolve() - .then(() => this._update()) - .then(() => { - timeEnd('AngularCompilerPlugin._make'); - cb(); - }, (err: any) => { - compilation.errors.push(err.stack); - timeEnd('AngularCompilerPlugin._make'); - cb(); - }); - } - - private _makeTransformers() { - - const isAppPath = (fileName: string) => - !fileName.endsWith('.ngfactory.ts') && !fileName.endsWith('.ngstyle.ts'); - const isMainPath = (fileName: string) => fileName === this._mainPath; - const getEntryModule = () => this.entryModule; - const getLazyRoutes = () => this._lazyRoutes; - const getTypeChecker = () => this._getTsProgram().getTypeChecker(); - - if (this._JitMode) { - // Replace resources in JIT. - this._transformers.push(replaceResources(isAppPath)); - } else { - // Remove unneeded angular decorators. - this._transformers.push(removeDecorators(isAppPath, getTypeChecker)); - } - - if (this._platform === PLATFORM.Browser) { - // If we have a locale, auto import the locale data file. - // This transform must go before replaceBootstrap because it looks for the entry module - // import, which will be replaced. - if (this._compilerOptions.i18nInLocale) { - this._transformers.push(registerLocaleData(isAppPath, getEntryModule, - this._compilerOptions.i18nInLocale)); - } - - if (!this._JitMode) { - // Replace bootstrap in browser AOT. - this._transformers.push(replaceBootstrap(isAppPath, getEntryModule, getTypeChecker)); - } - } else if (this._platform === PLATFORM.Server) { - this._transformers.push(exportLazyModuleMap(isMainPath, getLazyRoutes)); - if (!this._JitMode) { - this._transformers.push(exportNgFactory(isMainPath, getEntryModule)); - } - } - } - - private _update() { - time('AngularCompilerPlugin._update'); - // We only want to update on TS and template changes, but all kinds of files are on this - // list, like package.json and .ngsummary.json files. - let changedFiles = this._getChangedCompilationFiles(); - - // If nothing we care about changed and it isn't the first run, don't do anything. - if (changedFiles.length === 0 && !this._firstRun) { - return Promise.resolve(); - } - - return Promise.resolve() - // Make a new program and load the Angular structure. - .then(() => this._createOrUpdateProgram()) - .then(() => { - if (this.entryModule) { - // Try to find lazy routes if we have an entry module. - // We need to run the `listLazyRoutes` the first time because it also navigates libraries - // and other things that we might miss using the (faster) findLazyRoutesInAst. - // Lazy routes modules will be read with compilerHost and added to the changed files. - const changedTsFiles = this._getChangedTsFiles(); - if (this._ngCompilerSupportsNewApi) { - this._processLazyRoutes(this._listLazyRoutesFromProgram()); - } else if (this._firstRun) { - this._processLazyRoutes(this._getLazyRoutesFromNgtools()); - } else if (changedTsFiles.length > 0) { - this._processLazyRoutes(this._findLazyRoutesInAst(changedTsFiles)); - } - } - }) - .then(() => { - // Emit and report errors. - - // We now have the final list of changed TS files. - // Go through each changed file and add transforms as needed. - const sourceFiles = this._getChangedTsFiles() - .map((fileName) => this._getTsProgram().getSourceFile(fileName)) - // At this point we shouldn't need to filter out undefined files, because any ts file - // that changed should be emitted. - // But due to hostReplacementPaths there can be files (the environment files) - // that changed but aren't part of the compilation, specially on `ng test`. - // So we ignore missing source files files here. - // hostReplacementPaths needs to be fixed anyway to take care of the following issue. - // https://github.com/angular/angular-cli/issues/7305#issuecomment-332150230 - .filter((x) => !!x); - - // Emit files. - time('AngularCompilerPlugin._update._emit'); - const { emitResult, diagnostics } = this._emit(sourceFiles); - timeEnd('AngularCompilerPlugin._update._emit'); - - // Report diagnostics. - const errors = diagnostics - .filter((diag) => diag.category === ts.DiagnosticCategory.Error); - const warnings = diagnostics - .filter((diag) => diag.category === ts.DiagnosticCategory.Warning); - - if (errors.length > 0) { - const message = formatDiagnostics(errors); - this._compilation.errors.push(message); - } - - if (warnings.length > 0) { - const message = formatDiagnostics(warnings); - this._compilation.warnings.push(message); - } - - this._emitSkipped = !emitResult || emitResult.emitSkipped; - - // Reset changed files on successful compilation. - if (!this._emitSkipped && this._compilation.errors.length === 0) { - this._compilerHost.resetChangedFileTracker(); - } - timeEnd('AngularCompilerPlugin._update'); - }); - } - - writeI18nOutFile() { - function _recursiveMkDir(p: string): Promise { - if (fs.existsSync(p)) { - return Promise.resolve(); - } else { - return _recursiveMkDir(path.dirname(p)) - .then(() => fs.mkdirSync(p)); - } - } - - // Write the extracted messages to disk. - const i18nOutFilePath = path.resolve(this._basePath, this._compilerOptions.i18nOutFile); - const i18nOutFileContent = this._compilerHost.readFile(i18nOutFilePath); - if (i18nOutFileContent) { - _recursiveMkDir(path.dirname(i18nOutFilePath)) - .then(() => fs.writeFileSync(i18nOutFilePath, i18nOutFileContent)); - } - } - - getCompiledFile(fileName: string) { - const outputFile = fileName.replace(/.ts$/, '.js'); - let outputText: string; - let sourceMap: string; - let errorDependencies: string[] = []; - - if (this._emitSkipped) { - if (this._compilerHost.fileExists(outputFile, false)) { - // If the compilation didn't emit files this time, try to return the cached files from the - // last compilation and let the compilation errors show what's wrong. - outputText = this._compilerHost.readFile(outputFile); - sourceMap = this._compilerHost.readFile(outputFile + '.map'); - } else { - // There's nothing we can serve. Return an empty string to prevent lenghty webpack errors, - // add the rebuild warning if it's not there yet. - // We also need to all changed files as dependencies of this file, so that all of them - // will be watched and trigger a rebuild next time. - outputText = ''; - errorDependencies = this._getChangedCompilationFiles() - // These paths are used by the loader so we must denormalize them. - .map((p) => this._compilerHost.denormalizePath(p)); - } - } else { - // Check if the TS file exists. - if (fileName.endsWith('.ts') && !this._compilerHost.fileExists(fileName, false)) { - throw new Error(`${fileName} is not part of the compilation. ` - + `Please make sure it is in your tsconfig via the 'files' or 'include' property.`); - } - - // Check if the output file exists. - if (!this._compilerHost.fileExists(outputFile, false)) { - throw new Error(`${fileName} is not part of the compilation output. ` - + `Please check the other error messages for details.`); - } - - outputText = this._compilerHost.readFile(outputFile); - sourceMap = this._compilerHost.readFile(outputFile + '.map'); - } - return { outputText, sourceMap, errorDependencies }; - } - - getDependencies(fileName: string): string[] { - const resolvedFileName = this._compilerHost.resolve(fileName); - const sourceFile = this._compilerHost.getSourceFile(resolvedFileName, ts.ScriptTarget.Latest); - if (!sourceFile) { - return []; - } - - const options = this._compilerOptions; - const host = this._compilerHost; - const cache = this._moduleResolutionCache; - - const esImports = collectDeepNodes(sourceFile, - ts.SyntaxKind.ImportDeclaration) - .map(decl => { - const moduleName = (decl.moduleSpecifier as ts.StringLiteral).text; - const resolved = ts.resolveModuleName(moduleName, resolvedFileName, options, host, cache); - - if (resolved.resolvedModule) { - return resolved.resolvedModule.resolvedFileName; - } else { - return null; - } - }) - .filter(x => x); - - const resourceImports = findResources(sourceFile) - .map((resourceReplacement) => resourceReplacement.resourcePaths) - .reduce((prev, curr) => prev.concat(curr), []) - .map((resourcePath) => path.resolve(path.dirname(resolvedFileName), resourcePath)) - .reduce((prev, curr) => - prev.concat(...this.getResourceDependencies(curr)), []); - - // These paths are meant to be used by the loader so we must denormalize them. - return [...esImports, ...resourceImports].map((p) => this._compilerHost.denormalizePath(p)); - } - - getResourceDependencies(fileName: string): string[] { - return this._resourceLoader.getResourceDependencies(fileName); - } - - // This code mostly comes from `performCompilation` in `@angular/compiler-cli`. - // It skips the program creation because we need to use `loadNgStructureAsync()`, - // and uses CustomTransformers. - private _emit(sourceFiles: ts.SourceFile[]) { - time('AngularCompilerPlugin._emit'); - const program = this._program; - const allDiagnostics: Diagnostics = []; - - let emitResult: ts.EmitResult | undefined; - try { - if (this._JitMode) { - const tsProgram = program as ts.Program; - - if (this._firstRun) { - // Check parameter diagnostics. - time('AngularCompilerPlugin._emit.ts.getOptionsDiagnostics'); - allDiagnostics.push(...tsProgram.getOptionsDiagnostics()); - timeEnd('AngularCompilerPlugin._emit.ts.getOptionsDiagnostics'); - } - - if (this._firstRun || !this._forkTypeChecker) { - allDiagnostics.push(...gatherDiagnostics(this._program, this._JitMode, - 'AngularCompilerPlugin._emit.ts')); - } - - if (!hasErrors(allDiagnostics)) { - sourceFiles.forEach((sf) => { - const timeLabel = `AngularCompilerPlugin._emit.ts+${sf.fileName}+.emit`; - time(timeLabel); - emitResult = tsProgram.emit(sf, undefined, undefined, undefined, - { before: this._transformers } - ); - allDiagnostics.push(...emitResult.diagnostics); - timeEnd(timeLabel); - }); - } - } else { - const angularProgram = program as Program; - - // Check Angular structural diagnostics. - time('AngularCompilerPlugin._emit.ng.getNgStructuralDiagnostics'); - allDiagnostics.push(...angularProgram.getNgStructuralDiagnostics()); - timeEnd('AngularCompilerPlugin._emit.ng.getNgStructuralDiagnostics'); - - if (this._firstRun) { - // Check TypeScript parameter diagnostics. - time('AngularCompilerPlugin._emit.ng.getTsOptionDiagnostics'); - allDiagnostics.push(...angularProgram.getTsOptionDiagnostics()); - timeEnd('AngularCompilerPlugin._emit.ng.getTsOptionDiagnostics'); - - // Check Angular parameter diagnostics. - time('AngularCompilerPlugin._emit.ng.getNgOptionDiagnostics'); - allDiagnostics.push(...angularProgram.getNgOptionDiagnostics()); - timeEnd('AngularCompilerPlugin._emit.ng.getNgOptionDiagnostics'); - } - - if (this._firstRun || !this._forkTypeChecker) { - allDiagnostics.push(...gatherDiagnostics(this._program, this._JitMode, - 'AngularCompilerPlugin._emit.ng')); - } - - if (!hasErrors(allDiagnostics)) { - time('AngularCompilerPlugin._emit.ng.emit'); - const extractI18n = !!this._compilerOptions.i18nOutFile; - const emitFlags = extractI18n ? EmitFlags.I18nBundle : EmitFlags.Default; - emitResult = angularProgram.emit({ - emitFlags, customTransformers: { - beforeTs: this._transformers - } - }); - allDiagnostics.push(...emitResult.diagnostics); - if (extractI18n) { - this.writeI18nOutFile(); - } - timeEnd('AngularCompilerPlugin._emit.ng.emit'); - } - } - } catch (e) { - time('AngularCompilerPlugin._emit.catch'); - // This function is available in the import below, but this way we avoid the dependency. - // import { isSyntaxError } from '@angular/compiler'; - function isSyntaxError(error: Error): boolean { - return (error as any)['ngSyntaxError']; - } - - let errMsg: string; - let code: number; - if (isSyntaxError(e)) { - // don't report the stack for syntax errors as they are well known errors. - errMsg = e.message; - code = DEFAULT_ERROR_CODE; - } else { - errMsg = e.stack; - // It is not a syntax error we might have a program with unknown state, discard it. - this._program = undefined; - code = UNKNOWN_ERROR_CODE; - } - allDiagnostics.push( - { category: ts.DiagnosticCategory.Error, messageText: errMsg, code, source: SOURCE }); - timeEnd('AngularCompilerPlugin._emit.catch'); - } - timeEnd('AngularCompilerPlugin._emit'); - return { program, emitResult, diagnostics: allDiagnostics }; - } - - private _validateLocale(locale: string) { - // Get the path of the common module. - const commonPath = path.dirname(require.resolve('@angular/common/package.json')); - // Check if the locale file exists - if (!fs.existsSync(path.resolve(commonPath, 'locales', `${locale}.js`))) { - // Check for an alternative locale (if the locale id was badly formatted). - const locales = fs.readdirSync(path.resolve(commonPath, 'locales')) - .filter(file => file.endsWith('.js')) - .map(file => file.replace('.js', '')); - - let newLocale; - const normalizedLocale = locale.toLowerCase().replace(/_/g, '-'); - for (const l of locales) { - if (l.toLowerCase() === normalizedLocale) { - newLocale = l; - break; - } - } - - if (newLocale) { - locale = newLocale; - } else { - // Check for a parent locale - const parentLocale = normalizedLocale.split('-')[0]; - if (locales.indexOf(parentLocale) !== -1) { - locale = parentLocale; - } else { - throw new Error( - `Unable to load the locale data file "@angular/common/locales/${locale}", ` + - `please check that "${locale}" is a valid locale id.`); - } - } - } - - return locale; - } -} diff --git a/packages/@ngtools/webpack/src/benchmark.ts b/packages/@ngtools/webpack/src/benchmark.ts deleted file mode 100644 index 58fc7443061b..000000000000 --- a/packages/@ngtools/webpack/src/benchmark.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Internal benchmark reporting flag. -// Use with CLI --no-progress flag for best results. -// This should be false for commited code. -const _benchmark = false; - -export function time(label: string) { - if (_benchmark) { - console.time(label); - } -} - -export function timeEnd(label: string) { - if (_benchmark) { - console.timeEnd(label); - } -} diff --git a/packages/@ngtools/webpack/src/compiler_host.ts b/packages/@ngtools/webpack/src/compiler_host.ts deleted file mode 100644 index 33cc54fe46d6..000000000000 --- a/packages/@ngtools/webpack/src/compiler_host.ts +++ /dev/null @@ -1,322 +0,0 @@ -// @ignoreDep typescript -import * as ts from 'typescript'; -import {basename, dirname, join, sep} from 'path'; -import * as fs from 'fs'; -import {WebpackResourceLoader} from './resource_loader'; - - -export interface OnErrorFn { - (message: string): void; -} - - -const dev = Math.floor(Math.random() * 10000); - - -export class VirtualStats implements fs.Stats { - protected _ctime = new Date(); - protected _mtime = new Date(); - protected _atime = new Date(); - protected _btime = new Date(); - protected _dev = dev; - protected _ino = Math.floor(Math.random() * 100000); - protected _mode = parseInt('777', 8); // RWX for everyone. - protected _uid = process.env['UID'] || 0; - protected _gid = process.env['GID'] || 0; - - constructor(protected _path: string) {} - - isFile() { return false; } - isDirectory() { return false; } - isBlockDevice() { return false; } - isCharacterDevice() { return false; } - isSymbolicLink() { return false; } - isFIFO() { return false; } - isSocket() { return false; } - - get dev() { return this._dev; } - get ino() { return this._ino; } - get mode() { return this._mode; } - get nlink() { return 1; } // Default to 1 hard link. - get uid() { return this._uid; } - get gid() { return this._gid; } - get rdev() { return 0; } - get size() { return 0; } - get blksize() { return 512; } - get blocks() { return Math.ceil(this.size / this.blksize); } - get atime() { return this._atime; } - get mtime() { return this._mtime; } - get ctime() { return this._ctime; } - get birthtime() { return this._btime; } -} - -export class VirtualDirStats extends VirtualStats { - constructor(_fileName: string) { - super(_fileName); - } - - isDirectory() { return true; } - - get size() { return 1024; } -} - -export class VirtualFileStats extends VirtualStats { - private _sourceFile: ts.SourceFile | null; - constructor(_fileName: string, private _content: string) { - super(_fileName); - } - - get content() { return this._content; } - set content(v: string) { - this._content = v; - this._mtime = new Date(); - this._sourceFile = null; - } - setSourceFile(sourceFile: ts.SourceFile) { - this._sourceFile = sourceFile; - } - getSourceFile(languageVersion: ts.ScriptTarget, setParentNodes: boolean) { - if (!this._sourceFile) { - this._sourceFile = ts.createSourceFile( - this._path, - this._content, - languageVersion, - setParentNodes); - } - - return this._sourceFile; - } - - isFile() { return true; } - - get size() { return this._content.length; } -} - - -export class WebpackCompilerHost implements ts.CompilerHost { - private _delegate: ts.CompilerHost; - private _files: {[path: string]: VirtualFileStats | null} = Object.create(null); - private _directories: {[path: string]: VirtualDirStats | null} = Object.create(null); - private _cachedResources: {[path: string]: string | undefined} = Object.create(null); - - private _changedFiles: {[path: string]: boolean} = Object.create(null); - private _changedDirs: {[path: string]: boolean} = Object.create(null); - - private _basePath: string; - private _setParentNodes: boolean; - - private _cache = false; - private _resourceLoader?: WebpackResourceLoader | undefined; - - constructor(private _options: ts.CompilerOptions, basePath: string) { - this._setParentNodes = true; - this._delegate = ts.createCompilerHost(this._options, this._setParentNodes); - this._basePath = this._normalizePath(basePath); - } - - private _normalizePath(path: string) { - return path.replace(/\\/g, '/'); - } - - denormalizePath(path: string) { - return path.replace(/\//g, sep); - } - - resolve(path: string) { - path = this._normalizePath(path); - if (path[0] == '.') { - return this._normalizePath(join(this.getCurrentDirectory(), path)); - } else if (path[0] == '/' || path.match(/^\w:\//)) { - return path; - } else { - return this._normalizePath(join(this._basePath, path)); - } - } - - private _setFileContent(fileName: string, content: string) { - this._files[fileName] = new VirtualFileStats(fileName, content); - - let p = dirname(fileName); - while (p && !this._directories[p]) { - this._directories[p] = new VirtualDirStats(p); - this._changedDirs[p] = true; - p = dirname(p); - } - - this._changedFiles[fileName] = true; - } - - get dirty() { - return Object.keys(this._changedFiles).length > 0; - } - - enableCaching() { - this._cache = true; - } - - resetChangedFileTracker() { - this._changedFiles = Object.create(null); - this._changedDirs = Object.create(null); - } - - getChangedFilePaths(): string[] { - return Object.keys(this._changedFiles); - } - - getNgFactoryPaths(): string[] { - return Object.keys(this._files) - .filter(fileName => fileName.endsWith('.ngfactory.js') || fileName.endsWith('.ngstyle.js')) - // These paths are used by the virtual file system decorator so we must denormalize them. - .map((path) => this.denormalizePath(path)); - } - - invalidate(fileName: string): void { - fileName = this.resolve(fileName); - if (fileName in this._files) { - this._files[fileName] = null; - this._changedFiles[fileName] = true; - } - } - - fileExists(fileName: string, delegate = true): boolean { - fileName = this.resolve(fileName); - return this._files[fileName] != null || (delegate && this._delegate.fileExists(fileName)); - } - - readFile(fileName: string): string { - fileName = this.resolve(fileName); - - const stats = this._files[fileName]; - if (stats == null) { - const result = this._delegate.readFile(fileName); - if (result !== undefined && this._cache) { - this._setFileContent(fileName, result); - return result; - } else { - return result; - } - } - return stats.content; - } - - // Does not delegate, use with `fileExists/directoryExists()`. - stat(path: string): VirtualStats { - path = this.resolve(path); - return this._files[path] || this._directories[path]; - } - - directoryExists(directoryName: string, delegate = true): boolean { - directoryName = this.resolve(directoryName); - return (this._directories[directoryName] != null) - || (delegate - && this._delegate.directoryExists != undefined - && this._delegate.directoryExists(directoryName)); - } - - getFiles(path: string): string[] { - path = this.resolve(path); - return Object.keys(this._files) - .filter(fileName => dirname(fileName) == path) - .map(path => basename(path)); - } - - getDirectories(path: string): string[] { - path = this.resolve(path); - const subdirs = Object.keys(this._directories) - .filter(fileName => dirname(fileName) == path) - .map(path => basename(path)); - - let delegated: string[]; - try { - delegated = this._delegate.getDirectories(path); - } catch (e) { - delegated = []; - } - return delegated.concat(subdirs); - } - - getSourceFile(fileName: string, languageVersion: ts.ScriptTarget, _onError?: OnErrorFn) { - fileName = this.resolve(fileName); - - const stats = this._files[fileName]; - if (stats == null) { - const content = this.readFile(fileName); - - if (!this._cache) { - return ts.createSourceFile(fileName, content, languageVersion, this._setParentNodes); - } else if (!this._files[fileName]) { - // If cache is turned on and the file exists, the readFile call will have populated stats. - // Empty stats at this point mean the file doesn't exist at and so we should return - // undefined. - return undefined; - } - } - - return this._files[fileName]!.getSourceFile(languageVersion, this._setParentNodes); - } - - getCancellationToken() { - return this._delegate.getCancellationToken!(); - } - - getDefaultLibFileName(options: ts.CompilerOptions) { - return this._delegate.getDefaultLibFileName(options); - } - - // This is due to typescript CompilerHost interface being weird on writeFile. This shuts down - // typings in WebStorm. - get writeFile() { - return (fileName: string, data: string, _writeByteOrderMark: boolean, - _onError?: (message: string) => void, _sourceFiles?: ts.SourceFile[]): void => { - - fileName = this.resolve(fileName); - this._setFileContent(fileName, data); - }; - } - - getCurrentDirectory(): string { - return this._basePath !== null ? this._basePath : this._delegate.getCurrentDirectory(); - } - - getCanonicalFileName(fileName: string): string { - fileName = this.resolve(fileName); - return this._delegate.getCanonicalFileName(fileName); - } - - useCaseSensitiveFileNames(): boolean { - return this._delegate.useCaseSensitiveFileNames(); - } - - getNewLine(): string { - return this._delegate.getNewLine(); - } - - setResourceLoader(resourceLoader: WebpackResourceLoader) { - this._resourceLoader = resourceLoader; - } - - readResource(fileName: string) { - if (this._resourceLoader) { - // These paths are meant to be used by the loader so we must denormalize them. - const denormalizedFileName = this.denormalizePath(fileName); - const resourceDeps = this._resourceLoader.getResourceDependencies(denormalizedFileName); - - if (this._cachedResources[fileName] === undefined - || resourceDeps.some((dep) => this._changedFiles[this.resolve(dep)])) { - return this._resourceLoader.get(denormalizedFileName) - .then((resource) => { - // Add resource dependencies to the compiler host file list. - // This way we can check the changed files list to determine whether to use cache. - this._resourceLoader.getResourceDependencies(denormalizedFileName) - .forEach((dep) => this.readFile(dep)); - this._cachedResources[fileName] = resource; - return resource; - }); - } else { - return this._cachedResources[fileName]; - } - } else { - return this.readFile(fileName); - } - } -} diff --git a/packages/@ngtools/webpack/src/extract_i18n_plugin.ts b/packages/@ngtools/webpack/src/extract_i18n_plugin.ts deleted file mode 100644 index 2131a0836133..000000000000 --- a/packages/@ngtools/webpack/src/extract_i18n_plugin.ts +++ /dev/null @@ -1,192 +0,0 @@ -import * as ts from 'typescript'; -import * as path from 'path'; -import * as fs from 'fs'; - -import {__NGTOOLS_PRIVATE_API_2, VERSION} from './ngtools_api'; -import {Tapable} from './webpack'; -import {WebpackResourceLoader} from './resource_loader'; - -export interface ExtractI18nPluginOptions { - tsConfigPath: string; - basePath?: string; - genDir?: string; - i18nFormat?: string; - locale?: string; - outFile?: string; - exclude?: string[]; -} - -export class ExtractI18nPlugin implements Tapable { - private _resourceLoader: WebpackResourceLoader; - - private _donePromise: Promise | null; - private _compiler: any = null; - private _compilation: any = null; - - private _tsConfigPath: string; - private _basePath: string; - private _genDir: string; - private _rootFilePath: string[]; - private _compilerOptions: any = null; - private _angularCompilerOptions: any = null; - // private _compilerHost: WebpackCompilerHost; - private _compilerHost: ts.CompilerHost; - private _program: ts.Program; - - private _i18nFormat?: string; - private _locale?: string; - private _outFile?: string; - - constructor(options: ExtractI18nPluginOptions) { - this._setupOptions(options); - } - - private _setupOptions(options: ExtractI18nPluginOptions) { - if (!options.hasOwnProperty('tsConfigPath')) { - throw new Error('Must specify "tsConfigPath" in the configuration of @ngtools/webpack.'); - } - // TS represents paths internally with '/' and expects the tsconfig path to be in this format - this._tsConfigPath = options.tsConfigPath.replace(/\\/g, '/'); - - // Check the base path. - const maybeBasePath = path.resolve(process.cwd(), this._tsConfigPath); - let basePath = maybeBasePath; - if (fs.statSync(maybeBasePath).isFile()) { - basePath = path.dirname(basePath); - } - if (options.hasOwnProperty('basePath')) { - basePath = path.resolve(process.cwd(), options.basePath); - } - - let tsConfigJson: any = null; - try { - tsConfigJson = JSON.parse(fs.readFileSync(this._tsConfigPath, 'utf8')); - } catch (err) { - throw new Error(`An error happened while parsing ${this._tsConfigPath} JSON: ${err}.`); - } - const tsConfig = ts.parseJsonConfigFileContent( - tsConfigJson, ts.sys, basePath, undefined, this._tsConfigPath); - - let fileNames = tsConfig.fileNames; - if (options.hasOwnProperty('exclude')) { - let exclude: string[] = typeof options.exclude == 'string' - ? [options.exclude as string] : (options.exclude as string[]); - - exclude.forEach((pattern: string) => { - const basePathPattern = '(' + basePath.replace(/\\/g, '/') - .replace(/[\-\[\]\/{}()+?.\\^$|*]/g, '\\$&') + ')?'; - pattern = pattern - // Replace windows path separators with forward slashes. - .replace(/\\/g, '/') - // Escape characters that are used normally in regexes, except stars. - .replace(/[\-\[\]{}()+?.\\^$|]/g, '\\$&') - // Two stars replacement. - .replace(/\*\*/g, '(?:.*)') - // One star replacement. - .replace(/\*/g, '(?:[^/]*)') - // Escape characters from the basePath and make sure it's forward slashes. - .replace(/^/, basePathPattern); - - const re = new RegExp('^' + pattern + '$'); - fileNames = fileNames.filter(x => !x.replace(/\\/g, '/').match(re)); - }); - } else { - fileNames = fileNames.filter(fileName => !/\.spec\.ts$/.test(fileName)); - } - this._rootFilePath = fileNames; - - // By default messages will be generated in basePath - let genDir = basePath; - - if (options.hasOwnProperty('genDir')) { - genDir = path.resolve(process.cwd(), options.genDir); - } - - this._compilerOptions = tsConfig.options; - this._angularCompilerOptions = Object.assign( - // kept for compatibility with Angular this._make(compilation, cb)); - - compiler.plugin('after-emit', (compilation: any, cb: any) => { - this._donePromise = null; - this._compilation = null; - compilation._ngToolsWebpackXi18nPluginInstance = null; - cb(); - }); - } - - private _make(compilation: any, cb: (err?: any, request?: any) => void) { - this._compilation = compilation; - if (this._compilation._ngToolsWebpackXi18nPluginInstance) { - return cb(new Error('An @ngtools/webpack xi18n plugin already exist for ' + - 'this compilation.')); - } - if (!this._compilation._ngToolsWebpackPluginInstance) { - return cb(new Error('An @ngtools/webpack aot plugin does not exists ' + - 'for this compilation')); - } - - this._compilation._ngToolsWebpackXi18nPluginInstance = this; - - this._resourceLoader.update(compilation); - - this._donePromise = Promise.resolve() - .then(() => { - return __NGTOOLS_PRIVATE_API_2.extractI18n({ - basePath: this._basePath, - compilerOptions: this._compilerOptions, - program: this._program, - host: this._compilerHost, - angularCompilerOptions: this._angularCompilerOptions, - i18nFormat: this._i18nFormat || '', - locale: this._locale, - outFile: this._outFile, - - readResource: (path: string) => this._resourceLoader.get(path) - }); - }) - .then(() => cb(), (err: any) => { - this._compilation.errors.push(err); - cb(err); - }); - - } -} diff --git a/packages/@ngtools/webpack/src/gather_diagnostics.ts b/packages/@ngtools/webpack/src/gather_diagnostics.ts deleted file mode 100644 index a5dfa131064f..000000000000 --- a/packages/@ngtools/webpack/src/gather_diagnostics.ts +++ /dev/null @@ -1,83 +0,0 @@ -// @ignoreDep typescript -import * as ts from 'typescript'; - -import { time, timeEnd } from './benchmark'; -import { Program, Diagnostics } from './ngtools_api'; - - -export class CancellationToken implements ts.CancellationToken { - private _isCancelled = false; - - requestCancellation() { - this._isCancelled = true; - } - - isCancellationRequested() { - return this._isCancelled; - } - - throwIfCancellationRequested() { - if (this.isCancellationRequested()) { - throw new ts.OperationCanceledException(); - } - } -} - -export function hasErrors(diags: Diagnostics) { - return diags.some(d => d.category === ts.DiagnosticCategory.Error); -} - -export function gatherDiagnostics( - program: ts.Program | Program, - jitMode: boolean, - benchmarkLabel: string, - cancellationToken?: CancellationToken, -): Diagnostics { - const allDiagnostics: Diagnostics = []; - let checkOtherDiagnostics = true; - - function checkDiagnostics(diags: Diagnostics | undefined) { - if (diags) { - allDiagnostics.push(...diags); - return !hasErrors(diags); - } - return true; - } - - if (jitMode) { - const tsProgram = program as ts.Program; - // Check syntactic diagnostics. - time(`${benchmarkLabel}.gatherDiagnostics.ts.getSyntacticDiagnostics`); - checkOtherDiagnostics = checkOtherDiagnostics && - checkDiagnostics(tsProgram.getSyntacticDiagnostics(undefined, cancellationToken)); - timeEnd(`${benchmarkLabel}.gatherDiagnostics.ts.getSyntacticDiagnostics`); - - // Check semantic diagnostics. - time(`${benchmarkLabel}.gatherDiagnostics.ts.getSemanticDiagnostics`); - checkOtherDiagnostics = checkOtherDiagnostics && - checkDiagnostics(tsProgram.getSemanticDiagnostics(undefined, cancellationToken)); - timeEnd(`${benchmarkLabel}.gatherDiagnostics.ts.getSemanticDiagnostics`); - } else { - const angularProgram = program as Program; - - // Check TypeScript syntactic diagnostics. - time(`${benchmarkLabel}.gatherDiagnostics.ng.getTsSyntacticDiagnostics`); - checkOtherDiagnostics = checkOtherDiagnostics && - checkDiagnostics(angularProgram.getTsSyntacticDiagnostics(undefined, cancellationToken)); - timeEnd(`${benchmarkLabel}.gatherDiagnostics.ng.getTsSyntacticDiagnostics`); - - // Check TypeScript semantic and Angular structure diagnostics. - time(`${benchmarkLabel}.gatherDiagnostics.ng.getTsSemanticDiagnostics`); - checkOtherDiagnostics = checkOtherDiagnostics && - checkDiagnostics(angularProgram.getTsSemanticDiagnostics(undefined, cancellationToken)); - timeEnd(`${benchmarkLabel}.gatherDiagnostics.ng.getTsSemanticDiagnostics`); - - // Check Angular semantic diagnostics - time(`${benchmarkLabel}.gatherDiagnostics.ng.getNgSemanticDiagnostics`); - checkOtherDiagnostics = checkOtherDiagnostics && - checkDiagnostics(angularProgram.getNgSemanticDiagnostics(undefined, cancellationToken)); - timeEnd(`${benchmarkLabel}.gatherDiagnostics.ng.getNgSemanticDiagnostics`); - } - - return allDiagnostics; -} diff --git a/packages/@ngtools/webpack/src/index.ts b/packages/@ngtools/webpack/src/index.ts deleted file mode 100644 index 6292e36f96f8..000000000000 --- a/packages/@ngtools/webpack/src/index.ts +++ /dev/null @@ -1,22 +0,0 @@ -// @ignoreDep typescript -import { satisfies } from 'semver'; - -// Test if typescript is available. This is a hack. We should be using peerDependencies instead -// but can't until we split global and local packages. -// See https://github.com/angular/angular-cli/issues/8107#issuecomment-338185872 -try { - const version = require('typescript').version; - if (!satisfies(version, '^2.0.2')) { - throw new Error(); - } -} catch (e) { - throw new Error('Could not find local "typescript" package.' - + 'The "@ngtools/webpack" package requires a local "typescript@^2.0.2" package to be installed.' - + e); -} - -export * from './plugin'; -export * from './angular_compiler_plugin'; -export * from './extract_i18n_plugin'; -export { ngcLoader as default } from './loader'; -export { PathsPlugin } from './paths-plugin'; diff --git a/packages/@ngtools/webpack/src/lazy_routes.ts b/packages/@ngtools/webpack/src/lazy_routes.ts deleted file mode 100644 index 74491fd7e6be..000000000000 --- a/packages/@ngtools/webpack/src/lazy_routes.ts +++ /dev/null @@ -1,69 +0,0 @@ -import {dirname, join} from 'path'; -import * as ts from 'typescript'; - -import {TypeScriptFileRefactor} from './refactor'; - - -function _getContentOfKeyLiteral(_source: ts.SourceFile, node: ts.Node): string | null { - if (node.kind == ts.SyntaxKind.Identifier) { - return (node as ts.Identifier).text; - } else if (node.kind == ts.SyntaxKind.StringLiteral) { - return (node as ts.StringLiteral).text; - } else { - return null; - } -} - - -export interface LazyRouteMap { - [path: string]: string | null; -} - - -export function findLazyRoutes(filePath: string, - host: ts.CompilerHost, - program?: ts.Program, - compilerOptions?: ts.CompilerOptions): LazyRouteMap { - const refactor = new TypeScriptFileRefactor(filePath, host, program); - - return refactor - // Find all object literals in the file. - .findAstNodes(null, ts.SyntaxKind.ObjectLiteralExpression, true) - // Get all their property assignments. - .map((node: ts.ObjectLiteralExpression) => { - return refactor.findAstNodes(node, ts.SyntaxKind.PropertyAssignment, false); - }) - // Take all `loadChildren` elements. - .reduce((acc: ts.PropertyAssignment[], props: ts.PropertyAssignment[]) => { - return acc.concat(props.filter(literal => { - return _getContentOfKeyLiteral(refactor.sourceFile, literal.name) == 'loadChildren'; - })); - }, []) - // Get only string values. - .filter((node: ts.PropertyAssignment) => node.initializer.kind == ts.SyntaxKind.StringLiteral) - // Get the string value. - .map((node: ts.PropertyAssignment) => (node.initializer as ts.StringLiteral).text) - // Map those to either [path, absoluteModulePath], or [path, null] if the module pointing to - // does not exist. - .map((routePath: string) => { - const moduleName = routePath.split('#')[0]; - const compOptions = program ? program.getCompilerOptions() : compilerOptions; - const resolvedModuleName: ts.ResolvedModuleWithFailedLookupLocations = moduleName[0] == '.' - ? ({ - resolvedModule: { resolvedFileName: join(dirname(filePath), moduleName) + '.ts' } - } as any) - : ts.resolveModuleName(moduleName, filePath, compOptions, host); - if (resolvedModuleName.resolvedModule - && resolvedModuleName.resolvedModule.resolvedFileName - && host.fileExists(resolvedModuleName.resolvedModule.resolvedFileName)) { - return [routePath, resolvedModuleName.resolvedModule.resolvedFileName]; - } else { - return [routePath, null]; - } - }) - // Reduce to the LazyRouteMap map. - .reduce((acc: LazyRouteMap, [routePath, resolvedModuleName]: [string, string | null]) => { - acc[routePath] = resolvedModuleName; - return acc; - }, {}); -} diff --git a/packages/@ngtools/webpack/src/loader.spec.ts b/packages/@ngtools/webpack/src/loader.spec.ts deleted file mode 100644 index 5514dd342f7f..000000000000 --- a/packages/@ngtools/webpack/src/loader.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import * as ts from 'typescript'; -import {removeModuleIdOnlyForTesting} from './loader'; -import {WebpackCompilerHost} from './compiler_host'; -import {TypeScriptFileRefactor} from './refactor'; - -describe('@ngtools/webpack', () => { - describe('loader', () => { - describe('removeModuleId', () => { - it('should work', () => { - const host = new WebpackCompilerHost({}, ''); - host.writeFile('/file.ts', ` - export const obj = { moduleId: 123 }; - export const obj2 = { moduleId: 123, otherValue: 1 }; - export const obj3 = { otherValue: 1, moduleId: 123 }; - `, false); - host.writeFile('/file2.ts', ` - @SomeDecorator({ moduleId: 123 }) class CLS {} - @SomeDecorator({ moduleId: 123, otherValue1: 1 }) class CLS2 {} - @SomeDecorator({ otherValue2: 2, moduleId: 123, otherValue3: 3 }) class CLS3 {} - @SomeDecorator({ otherValue4: 4, moduleId: 123 }) class CLS4 {} - `, false); - - const program = ts.createProgram(['/file.ts', '/file2.ts'], {}, host); - - const refactor = new TypeScriptFileRefactor('/file.ts', host, program); - removeModuleIdOnlyForTesting(refactor); - expect(refactor.sourceText).not.toMatch(/obj = \{\s+};/); - expect(refactor.sourceText).not.toMatch(/\{\s*otherValue: 1\s*};/); - - const refactor2 = new TypeScriptFileRefactor('/file2.ts', host, program); - removeModuleIdOnlyForTesting(refactor2); - expect(refactor2.sourceText).toMatch(/\(\{\s+}\)/); - expect(refactor2.sourceText).toMatch(/\(\{\s*otherValue1: 1\s*}\)/); - expect(refactor2.sourceText).toMatch(/\(\{\s*otherValue2: 2\s*,\s*otherValue3: 3\s*}\)/); - expect(refactor2.sourceText).toMatch(/\(\{\s*otherValue4: 4\s*}\)/); - }); - - it('should work without a root name', () => { - const host = new WebpackCompilerHost({}, ''); - host.writeFile('/file.ts', ` - import './file2.ts'; - `, false); - host.writeFile('/file2.ts', ` - @SomeDecorator({ moduleId: 123 }) class CLS {} - @SomeDecorator({ moduleId: 123, otherValue1: 1 }) class CLS2 {} - @SomeDecorator({ otherValue2: 2, moduleId: 123, otherValue3: 3 }) class CLS3 {} - @SomeDecorator({ otherValue4: 4, moduleId: 123 }) class CLS4 {} - `, false); - - const program = ts.createProgram(['/file.ts'], {}, host); - const refactor = new TypeScriptFileRefactor('/file2.ts', host, program); - removeModuleIdOnlyForTesting(refactor); - expect(refactor.sourceText).toMatch(/\(\{\s+}\)/); - expect(refactor.sourceText).toMatch(/\(\{\s*otherValue1: 1\s*}\)/); - expect(refactor.sourceText).toMatch(/\(\{\s*otherValue2: 2\s*,\s*otherValue3: 3\s*}\)/); - expect(refactor.sourceText).toMatch(/\(\{\s*otherValue4: 4\s*}\)/); - }); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/loader.ts b/packages/@ngtools/webpack/src/loader.ts deleted file mode 100644 index 0bfc273c3fed..000000000000 --- a/packages/@ngtools/webpack/src/loader.ts +++ /dev/null @@ -1,755 +0,0 @@ -import * as path from 'path'; -import * as ts from 'typescript'; -import {AotPlugin} from './plugin'; -import {AngularCompilerPlugin} from './angular_compiler_plugin'; -import {TypeScriptFileRefactor} from './refactor'; -import {LoaderContext, ModuleReason} from './webpack'; -import {time, timeEnd} from './benchmark'; - -interface Platform { - name: string; - importLocation: string; -} - -const loaderUtils = require('loader-utils'); -const NormalModule = require('webpack/lib/NormalModule'); - -const sourceMappingUrlRe = /^\/\/# sourceMappingURL=[^\r\n]*/gm; - -// This is a map of changes which need to be made -const changeMap: {[key: string]: Platform} = { - platformBrowserDynamic: { - name: 'platformBrowser', - importLocation: '@angular/platform-browser' - }, - platformDynamicServer: { - name: 'platformServer', - importLocation: '@angular/platform-server' - } -}; - -function _getContentOfKeyLiteral(_source: ts.SourceFile, node?: ts.Node): string | null { - if (!node) { - return null; - } else if (node.kind == ts.SyntaxKind.Identifier) { - return (node as ts.Identifier).text; - } else if (node.kind == ts.SyntaxKind.StringLiteral) { - return (node as ts.StringLiteral).text; - } else { - return null; - } -} - - -function _angularImportsFromNode(node: ts.ImportDeclaration, _sourceFile: ts.SourceFile): string[] { - const ms = node.moduleSpecifier; - let modulePath: string | null = null; - switch (ms.kind) { - case ts.SyntaxKind.StringLiteral: - modulePath = (ms as ts.StringLiteral).text; - break; - default: - return []; - } - - if (!modulePath.startsWith('@angular/')) { - return []; - } - - if (node.importClause) { - if (node.importClause.name) { - // This is of the form `import Name from 'path'`. Ignore. - return []; - } else if (node.importClause.namedBindings) { - const nb = node.importClause.namedBindings; - if (nb.kind == ts.SyntaxKind.NamespaceImport) { - // This is of the form `import * as name from 'path'`. Return `name.`. - return [(nb as ts.NamespaceImport).name.text + '.']; - } else { - // This is of the form `import {a,b,c} from 'path'` - const namedImports = nb as ts.NamedImports; - - return namedImports.elements - .map((is: ts.ImportSpecifier) => is.propertyName ? is.propertyName.text : is.name.text); - } - } - } else { - // This is of the form `import 'path';`. Nothing to do. - return []; - } - return []; -} - - -function _ctorParameterFromTypeReference(paramNode: ts.ParameterDeclaration, - angularImports: string[], - refactor: TypeScriptFileRefactor) { - let typeName = 'undefined'; - - if (paramNode.type) { - switch (paramNode.type.kind) { - case ts.SyntaxKind.TypeReference: - const type = paramNode.type as ts.TypeReferenceNode; - if (type.typeName) { - typeName = type.typeName.getText(refactor.sourceFile); - } else { - typeName = type.getText(refactor.sourceFile); - } - break; - case ts.SyntaxKind.AnyKeyword: - typeName = 'undefined'; - break; - default: - typeName = 'null'; - } - } - - const decorators = refactor.findAstNodes(paramNode, ts.SyntaxKind.Decorator) as ts.Decorator[]; - const decoratorStr = decorators - .map(decorator => { - const call = - refactor.findFirstAstNode(decorator, ts.SyntaxKind.CallExpression) as ts.CallExpression; - - if (!call) { - return null; - } - - const fnName = call.expression.getText(refactor.sourceFile); - const args = call.arguments.map(x => x.getText(refactor.sourceFile)).join(', '); - if (angularImports.indexOf(fnName) === -1) { - return null; - } else { - return [fnName, args]; - } - }) - .filter(x => !!x) - .map(([name, args]: string[]) => { - if (args) { - return `{ type: ${name}, args: [${args}] }`; - } - return `{ type: ${name} }`; - }) - .join(', '); - - if (decorators.length > 0) { - return `{ type: ${typeName}, decorators: [${decoratorStr}] }`; - } - return `{ type: ${typeName} }`; -} - - -function _addCtorParameters(classNode: ts.ClassDeclaration, - angularImports: string[], - refactor: TypeScriptFileRefactor) { - // For every classes with constructors, output the ctorParameters function which contains a list - // of injectable types. - const ctor = ( - refactor.findFirstAstNode(classNode, ts.SyntaxKind.Constructor) as ts.ConstructorDeclaration); - if (!ctor) { - // A class can be missing a constructor, and that's _okay_. - return; - } - - const params = Array.from(ctor.parameters).map(paramNode => { - return _ctorParameterFromTypeReference(paramNode, angularImports, refactor); - }); - - const ctorParametersDecl = `static ctorParameters() { return [ ${params.join(', ')} ]; }`; - refactor.prependBefore(classNode.getLastToken(refactor.sourceFile), ctorParametersDecl); -} - - -function _removeDecorators(refactor: TypeScriptFileRefactor) { - const angularImports: string[] - = refactor.findAstNodes(refactor.sourceFile, ts.SyntaxKind.ImportDeclaration) - .map((node: ts.ImportDeclaration) => _angularImportsFromNode(node, refactor.sourceFile)) - .reduce((acc: string[], current: string[]) => acc.concat(current), []); - - // Find all decorators. - refactor.findAstNodes(refactor.sourceFile, ts.SyntaxKind.Decorator) - .forEach(node => { - // First, add decorators to classes to the classes array. - if (node.parent) { - const declarations = refactor.findAstNodes(node.parent, - ts.SyntaxKind.ClassDeclaration, false, 1); - if (declarations.length > 0) { - _addCtorParameters(declarations[0] as ts.ClassDeclaration, angularImports, refactor); - } - } - - refactor.findAstNodes(node, ts.SyntaxKind.CallExpression) - .filter((node: ts.CallExpression) => { - const fnName = node.expression.getText(refactor.sourceFile); - if (fnName.indexOf('.') != -1) { - // Since this is `a.b`, see if it's the same namespace as a namespace import. - return angularImports.indexOf(fnName.replace(/\..*$/, '') + '.') != -1; - } else { - return angularImports.indexOf(fnName) != -1; - } - }) - .forEach(() => refactor.removeNode(node)); - }); -} - - -function _getNgFactoryPath(plugin: AotPlugin, refactor: TypeScriptFileRefactor) { - // Calculate the base path. - const basePath = path.normalize(plugin.basePath); - const genDir = path.normalize(plugin.genDir); - const dirName = path.normalize(path.dirname(refactor.fileName)); - const entryModule = plugin.entryModule; - const entryModuleFileName = path.normalize(entryModule.path + '.ngfactory'); - const relativeEntryModulePath = path.relative(basePath, entryModuleFileName); - const fullEntryModulePath = path.resolve(genDir, relativeEntryModulePath); - const relativeNgFactoryPath = path.relative(dirName, fullEntryModulePath); - return './' + relativeNgFactoryPath.replace(/\\/g, '/'); -} - - -function _replacePlatform( - refactor: TypeScriptFileRefactor, bootstrapCall: ts.PropertyAccessExpression) { - const platforms = (refactor.findAstNodes(bootstrapCall, - ts.SyntaxKind.CallExpression, true) as ts.CallExpression[]) - .filter(call => { - return call.expression.kind == ts.SyntaxKind.Identifier; - }) - .filter(call => !!changeMap[(call.expression as ts.Identifier).text]); - - platforms.forEach(call => { - const platform = changeMap[(call.expression as ts.Identifier).text]; - - // Replace with mapped replacement - refactor.replaceNode(call.expression, platform.name); - - // Add the appropriate import - refactor.insertImport(platform.name, platform.importLocation); - }); -} - - -// TODO: remove platform server bootstrap replacement. -// It doesn't seem to be used anymore according to tests/e2e/tests/build/platform-server.ts and -// https://github.com/angular/angular-cli/wiki/stories-universal-rendering. -function _replaceBootstrapOrRender(refactor: TypeScriptFileRefactor, call: ts.CallExpression) { - // If neither bootstrapModule or renderModule can't be found, bail out early. - let replacementTarget: string | undefined; - let identifier: ts.Identifier | undefined; - if (call.getText().includes('bootstrapModule')) { - if (call.expression.kind != ts.SyntaxKind.PropertyAccessExpression) { - return; - } - - replacementTarget = 'bootstrapModule'; - const access = call.expression as ts.PropertyAccessExpression; - identifier = access.name; - _replacePlatform(refactor, access); - - } else if (call.getText().includes('renderModule')) { - if (call.expression.kind != ts.SyntaxKind.Identifier) { - return; - } - - replacementTarget = 'renderModule'; - identifier = call.expression as ts.Identifier; - refactor.insertImport('renderModuleFactory', '@angular/platform-server'); - } - - if (identifier && identifier.text === replacementTarget) { - refactor.replaceNode(identifier, replacementTarget + 'Factory'); - } -} - - -function _getCaller(node: ts.Node): ts.CallExpression | null { - while (node.parent) { - node = node.parent; - if (node.kind === ts.SyntaxKind.CallExpression) { - return node as ts.CallExpression; - } - } - return null; -} - - -function _replaceEntryModule(plugin: AotPlugin, refactor: TypeScriptFileRefactor) { - const modules = refactor.findAstNodes(refactor.sourceFile, ts.SyntaxKind.Identifier, true) - .filter(identifier => identifier.getText() === plugin.entryModule.className) - .filter(identifier => - identifier.parent && - (identifier.parent.kind === ts.SyntaxKind.CallExpression || - identifier.parent.kind === ts.SyntaxKind.PropertyAssignment)) - .filter(node => !!_getCaller(node)); - - if (modules.length == 0) { - return; - } - - const factoryClassName = plugin.entryModule.className + 'NgFactory'; - - refactor.insertImport(factoryClassName, _getNgFactoryPath(plugin, refactor)); - - modules - .forEach(reference => { - refactor.replaceNode(reference, factoryClassName); - const caller = _getCaller(reference); - if (caller) { - _replaceBootstrapOrRender(refactor, caller); - } - }); -} - - -function _refactorBootstrap(plugin: AotPlugin, refactor: TypeScriptFileRefactor) { - const genDir = path.normalize(plugin.genDir); - const dirName = path.normalize(path.dirname(refactor.fileName)); - - // Bail if in the generated directory - if (dirName.startsWith(genDir)) { - return; - } - - _replaceEntryModule(plugin, refactor); -} - -export function removeModuleIdOnlyForTesting(refactor: TypeScriptFileRefactor) { - _removeModuleId(refactor); -} - -function _removeModuleId(refactor: TypeScriptFileRefactor) { - const sourceFile = refactor.sourceFile; - - refactor.findAstNodes(sourceFile, ts.SyntaxKind.Decorator, true) - .reduce((acc, node) => { - return acc.concat(refactor.findAstNodes(node, ts.SyntaxKind.ObjectLiteralExpression, true)); - }, new Array()) - // Get all their property assignments. - .filter((node: ts.ObjectLiteralExpression) => { - return node.properties.some(prop => { - return prop.kind == ts.SyntaxKind.PropertyAssignment - && _getContentOfKeyLiteral(sourceFile, prop.name) == 'moduleId'; - }); - }) - .forEach((node: ts.ObjectLiteralExpression) => { - const moduleIdProp = node.properties.filter((prop: ts.ObjectLiteralElement, _idx: number) => { - return prop.kind == ts.SyntaxKind.PropertyAssignment - && _getContentOfKeyLiteral(sourceFile, prop.name) == 'moduleId'; - })[0]; - // Get the trailing comma. - const moduleIdCommaProp = moduleIdProp.parent - ? moduleIdProp.parent.getChildAt(1).getChildren()[1] : null; - refactor.removeNodes(moduleIdProp, moduleIdCommaProp); - }); -} - -function _getResourceRequest(element: ts.Expression, sourceFile: ts.SourceFile) { - if (element.kind == ts.SyntaxKind.StringLiteral) { - const url = (element as ts.StringLiteral).text; - // If the URL does not start with ./ or ../, prepends ./ to it. - return `'${/^\.?\.\//.test(url) ? '' : './'}${url}'`; - } else { - // if not string, just use expression directly - return element.getFullText(sourceFile); - } -} - -function _replaceResources(refactor: TypeScriptFileRefactor): void { - const sourceFile = refactor.sourceFile; - - _getResourceNodes(refactor) - // Get the full text of the initializer. - .forEach((node: ts.PropertyAssignment) => { - const key = _getContentOfKeyLiteral(sourceFile, node.name); - - if (key == 'templateUrl') { - refactor.replaceNode(node, - `template: require(${_getResourceRequest(node.initializer, sourceFile)})`); - } else if (key == 'styleUrls') { - const arr = ( - refactor.findAstNodes(node, ts.SyntaxKind.ArrayLiteralExpression, false)); - if (!arr || arr.length == 0 || arr[0].elements.length == 0) { - return; - } - - const initializer = arr[0].elements.map((element: ts.Expression) => { - return _getResourceRequest(element, sourceFile); - }); - refactor.replaceNode(node, `styles: [require(${initializer.join('), require(')})]`); - } - }); -} - - -function _getResourceNodes(refactor: TypeScriptFileRefactor) { - const { sourceFile } = refactor; - - // Find all object literals. - return refactor.findAstNodes(sourceFile, ts.SyntaxKind.ObjectLiteralExpression, true) - // Get all their property assignments. - .map(node => refactor.findAstNodes(node, ts.SyntaxKind.PropertyAssignment)) - // Flatten into a single array (from an array of array). - .reduce((prev, curr) => curr ? prev.concat(curr) : prev, []) - // Remove every property assignment that aren't 'loadChildren'. - .filter((node: ts.PropertyAssignment) => { - const key = _getContentOfKeyLiteral(sourceFile, node.name); - if (!key) { - // key is an expression, can't do anything. - return false; - } - return key == 'templateUrl' || key == 'styleUrls'; - }); -} - - -function _getResourcesUrls(refactor: TypeScriptFileRefactor): string[] { - return _getResourceNodes(refactor) - .reduce((acc: string[], node: ts.PropertyAssignment) => { - const key = _getContentOfKeyLiteral(refactor.sourceFile, node.name); - - if (key == 'templateUrl') { - const url = (node.initializer as ts.StringLiteral).text; - if (url) { - acc.push(url); - } - } else if (key == 'styleUrls') { - const arr = ( - refactor.findAstNodes(node, ts.SyntaxKind.ArrayLiteralExpression, false)); - if (!arr || arr.length == 0 || arr[0].elements.length == 0) { - return acc; - } - - arr[0].elements.forEach((element: ts.Expression) => { - if (element.kind == ts.SyntaxKind.StringLiteral) { - const url = (element as ts.StringLiteral).text; - if (url) { - acc.push(url); - } - } - }); - } - return acc; - }, []); -} - - -function _getImports(refactor: TypeScriptFileRefactor, - compilerOptions: ts.CompilerOptions, - host: ts.ModuleResolutionHost, - cache: ts.ModuleResolutionCache): string[] { - const containingFile = refactor.fileName; - - return refactor.findAstNodes(null, ts.SyntaxKind.ImportDeclaration, false) - .map((clause: ts.ImportDeclaration) => { - const moduleName = (clause.moduleSpecifier as ts.StringLiteral).text; - const resolved = ts.resolveModuleName( - moduleName, containingFile, compilerOptions, host, cache); - - if (resolved.resolvedModule) { - return resolved.resolvedModule.resolvedFileName; - } else { - return null; - } - }) - .filter(x => x); -} - - -/** - * Recursively calls diagnose on the plugins for all the reverse dependencies. - * @private - */ -function _diagnoseDeps(reasons: ModuleReason[], plugin: AotPlugin, checked: Set) { - reasons - .filter(reason => reason && reason.module && reason.module instanceof NormalModule) - .filter(reason => !checked.has(reason.module.resource)) - .forEach(reason => { - checked.add(reason.module.resource); - plugin.diagnose(reason.module.resource); - _diagnoseDeps(reason.module.reasons, plugin, checked); - }); -} - - -export function _getModuleExports(plugin: AotPlugin, - refactor: TypeScriptFileRefactor): ts.Identifier[] { - const exports = refactor - .findAstNodes(refactor.sourceFile, ts.SyntaxKind.ExportDeclaration, true); - - return exports - .filter(node => { - - const identifiers = refactor.findAstNodes(node, ts.SyntaxKind.Identifier, false) - .filter(node => node.getText() === plugin.entryModule.className); - - return identifiers.length > 0; - }) as ts.Identifier[]; -} - - -export function _replaceExport(plugin: AotPlugin, refactor: TypeScriptFileRefactor) { - if (!plugin.replaceExport) { - return; - } - _getModuleExports(plugin, refactor) - .forEach(node => { - const factoryPath = _getNgFactoryPath(plugin, refactor); - const factoryClassName = plugin.entryModule.className + 'NgFactory'; - const exportStatement = `export \{ ${factoryClassName} \} from '${factoryPath}'`; - refactor.appendAfter(node, exportStatement); - }); -} - - -export function _exportModuleMap(plugin: AotPlugin, refactor: TypeScriptFileRefactor) { - if (!plugin.replaceExport) { - return; - } - - const dirName = path.normalize(path.dirname(refactor.fileName)); - const classNameAppend = plugin.skipCodeGeneration ? '' : 'NgFactory'; - const modulePathAppend = plugin.skipCodeGeneration ? '' : '.ngfactory'; - - _getModuleExports(plugin, refactor) - .forEach(node => { - const modules = Object.keys(plugin.discoveredLazyRoutes) - .map((loadChildrenString) => { - let [lazyRouteKey, moduleName] = loadChildrenString.split('#'); - - if (!lazyRouteKey || !moduleName) { - throw new Error(`${loadChildrenString} was not a proper loadChildren string`); - } - - moduleName += classNameAppend; - lazyRouteKey += modulePathAppend; - const modulePath = plugin.lazyRoutes[lazyRouteKey]; - - return { - modulePath, - moduleName, - loadChildrenString - }; - }); - - modules.forEach((module, index) => { - const relativePath = path.relative(dirName, module.modulePath!).replace(/\\/g, '/'); - refactor.prependBefore(node, `import * as __lazy_${index}__ from './${relativePath}'`); - }); - - const jsonContent: string = modules - .map((module, index) => - `"${module.loadChildrenString}": __lazy_${index}__.${module.moduleName}`) - .join(); - - refactor.appendAfter(node, `export const LAZY_MODULE_MAP = {${jsonContent}};`); - }); -} - - -// Super simple TS transpiler loader for testing / isolated usage. does not type check! -export function ngcLoader(this: LoaderContext & { _compilation: any }, source: string | null) { - const cb = this.async(); - const sourceFileName: string = this.resourcePath; - const timeLabel = `ngcLoader+${sourceFileName}+`; - time(timeLabel); - - const plugin = this._compilation._ngToolsWebpackPluginInstance; - if (plugin) { - // We must verify that the plugin is an instance of the right class. - // Throw an error if it isn't, that often means multiple @ngtools/webpack installs. - if (!(plugin instanceof AotPlugin) && !(plugin instanceof AngularCompilerPlugin)) { - throw new Error('Angular Compiler was detected but it was an instance of the wrong class.\n' - + 'This likely means you have several @ngtools/webpack packages installed. ' - + 'You can check this with `npm ls @ngtools/webpack`, and then remove the extra copies.' - ); - } - - if (plugin instanceof AngularCompilerPlugin) { - time(timeLabel + '.ngcLoader.AngularCompilerPlugin'); - plugin.done - .then(() => { - timeEnd(timeLabel + '.ngcLoader.AngularCompilerPlugin'); - const result = plugin.getCompiledFile(sourceFileName); - - if (result.sourceMap) { - // Process sourcemaps for Webpack. - // Remove the sourceMappingURL. - result.outputText = result.outputText.replace(sourceMappingUrlRe, ''); - // Set the map source to use the full path of the file. - const sourceMap = JSON.parse(result.sourceMap); - sourceMap.sources = sourceMap.sources.map((fileName: string) => { - return path.join(path.dirname(sourceFileName), fileName); - }); - result.sourceMap = sourceMap; - } - - // Manually add the dependencies for TS files. - // Type only imports will be stripped out by compilation so we need to add them as - // as dependencies. - // Component resources files (html and css templates) also need to be added manually for - // AOT, so that this file is reloaded when they change. - if (sourceFileName.endsWith('.ts')) { - result.errorDependencies.forEach(dep => this.addDependency(dep)); - const dependencies = plugin.getDependencies(sourceFileName); - dependencies.forEach(dep => this.addDependency(dep)); - } - - // NgFactory files depend on the component template, but we can't know what that file - // is (if any). So we add all the dependencies that the original component file has - // to the factory as well, which includes html and css templates, and the component - // itself (for inline html/templates templates). - const ngFactoryRe = /\.ngfactory.js$/; - if (ngFactoryRe.test(sourceFileName)) { - const originalFile = sourceFileName.replace(ngFactoryRe, '.ts'); - this.addDependency(originalFile); - const origDependencies = plugin.getDependencies(originalFile); - origDependencies.forEach(dep => this.addDependency(dep)); - } - - // NgStyle files depend on the style file they represent. - // E.g. `some-style.less.shim.ngstyle.js` depends on `some-style.less`. - // Those files can in turn depend on others, so we have to add them all. - const ngStyleRe = /(?:\.shim)?\.ngstyle\.js$/; - if (ngStyleRe.test(sourceFileName)) { - const styleFile = sourceFileName.replace(ngStyleRe, ''); - const styleDependencies = plugin.getResourceDependencies(styleFile); - styleDependencies.forEach(dep => this.addDependency(dep)); - } - - timeEnd(timeLabel); - cb(null, result.outputText, result.sourceMap); - }) - .catch(err => { - timeEnd(timeLabel); - cb(err); - }); - } else if (plugin instanceof AotPlugin) { - time(timeLabel + '.ngcLoader.AotPlugin'); - if (plugin.compilerHost.readFile(sourceFileName) == source) { - // In the case where the source is the same as the one in compilerHost, we don't have - // extra TS loaders and there's no need to do any trickery. - source = null; - } - const refactor = new TypeScriptFileRefactor( - sourceFileName, plugin.compilerHost, plugin.program, source); - - // Force a few compiler options to make sure we get the result we want. - const compilerOptions: ts.CompilerOptions = Object.assign({}, plugin.compilerOptions, { - inlineSources: true, - inlineSourceMap: false, - sourceRoot: plugin.basePath - }); - - Promise.resolve() - .then(() => { - time(timeLabel + '.ngcLoader.AotPlugin.refactor'); - let promise: Promise; - if (!plugin.skipCodeGeneration) { - promise = Promise.resolve() - .then(() => _removeDecorators(refactor)) - .then(() => _refactorBootstrap(plugin, refactor)) - .then(() => _replaceExport(plugin, refactor)) - .then(() => _exportModuleMap(plugin, refactor)); - } else { - promise = Promise.resolve() - .then(() => _replaceResources(refactor)) - .then(() => _removeModuleId(refactor)) - .then(() => _exportModuleMap(plugin, refactor)); - } - return promise.then(() => timeEnd(timeLabel + '.ngcLoader.AotPlugin.refactor')); - }) - .then(() => { - if (plugin.typeCheck) { - time(timeLabel + '.ngcLoader.AotPlugin.typeCheck'); - // Check all diagnostics from this and reverse dependencies also. - if (!plugin.firstRun) { - _diagnoseDeps(this._module.reasons, plugin, new Set()); - } - // We do this here because it will throw on error, resulting in rebuilding this file - // the next time around if it changes. - plugin.diagnose(sourceFileName); - timeEnd(timeLabel + '.ngcLoader.AotPlugin.typeCheck'); - } - }) - .then(() => { - time(timeLabel + '.ngcLoader.AotPlugin.addDependency'); - // Add resources as dependencies. - _getResourcesUrls(refactor).forEach((url: string) => { - this.addDependency(path.resolve(path.dirname(sourceFileName), url)); - }); - // Dependencies must use system path separator. - _getImports(refactor, compilerOptions, plugin.compilerHost, plugin.moduleResolutionCache) - .forEach((dep) => this.addDependency(dep.replace(/\//g, path.sep))); - timeEnd(timeLabel + '.ngcLoader.AotPlugin.addDependency'); - }) - .then(() => { - if (source) { - time(timeLabel + '.ngcLoader.AotPlugin.getDiagnostics'); - // We need to validate diagnostics. We ignore type checking though, to save time. - const diagnostics = refactor.getDiagnostics(false); - if (diagnostics.length) { - let message = ''; - - diagnostics.forEach(diagnostic => { - const messageText = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - - if (diagnostic.file) { - const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); - const fileName = diagnostic.file.fileName; - const { line, character } = position; - message += `${fileName} (${line + 1},${character + 1}): ${messageText}\n`; - } else { - message += `${messageText}\n`; - } - }); - throw new Error(message); - } - timeEnd(timeLabel + '.ngcLoader.AotPlugin.getDiagnostics'); - } - - time(timeLabel + '.ngcLoader.AotPlugin.transpile'); - const result = refactor.transpile(compilerOptions); - timeEnd(timeLabel + '.ngcLoader.AotPlugin.transpile'); - - timeEnd(timeLabel + '.ngcLoader.AotPlugin'); - timeEnd(timeLabel); - - if (result.outputText === undefined) { - throw new Error('TypeScript compilation failed.'); - } - cb(null, result.outputText, result.sourceMap); - }) - .catch(err => cb(err)); - } - } else { - const options = loaderUtils.getOptions(this) || {}; - const tsConfigPath = options.tsConfigPath; - - if (tsConfigPath === undefined) { - throw new Error('@ngtools/webpack is being used as a loader but no `tsConfigPath` option nor ' - + 'AotPlugin was detected. You must provide at least one of these.' - ); - } - - const tsConfig = ts.readConfigFile(tsConfigPath, ts.sys.readFile); - - if (tsConfig.error) { - throw tsConfig.error; - } - - const compilerOptions: ts.CompilerOptions = tsConfig.config.compilerOptions; - for (const key of Object.keys(options)) { - if (key == 'tsConfigPath') { - continue; - } - compilerOptions[key] = options[key]; - } - const compilerHost = ts.createCompilerHost(compilerOptions); - const refactor = new TypeScriptFileRefactor(sourceFileName, compilerHost); - _replaceResources(refactor); - - const result = refactor.transpile(compilerOptions); - // Webpack is going to take care of this. - result.outputText = result.outputText.replace(sourceMappingUrlRe, ''); - timeEnd(timeLabel); - cb(null, result.outputText, result.sourceMap); - } -} diff --git a/packages/@ngtools/webpack/src/ngtools_api.ts b/packages/@ngtools/webpack/src/ngtools_api.ts deleted file mode 100644 index e66ea1a71809..000000000000 --- a/packages/@ngtools/webpack/src/ngtools_api.ts +++ /dev/null @@ -1,187 +0,0 @@ -// @ignoreDep @angular/compiler-cli -// @ignoreDep typescript -/** - * This is a copy of types in @compiler-cli/src/ngtools_api.d.ts file, - * together with safe imports for private apis for cases where @angular/compiler-cli isn't - * available or is below version 5. - */ -import * as path from 'path'; -import * as ts from 'typescript'; - -export const DEFAULT_ERROR_CODE = 100; -export const UNKNOWN_ERROR_CODE = 500; -export const SOURCE = 'angular' as 'angular'; -export interface Diagnostic { - messageText: string; - span?: any; - category: ts.DiagnosticCategory; - code: number; - source: 'angular'; -} -export interface CompilerOptions extends ts.CompilerOptions { - basePath?: string; - skipMetadataEmit?: boolean; - strictMetadataEmit?: boolean; - skipTemplateCodegen?: boolean; - flatModuleOutFile?: string; - flatModuleId?: string; - generateCodeForLibraries?: boolean; - annotateForClosureCompiler?: boolean; - annotationsAs?: 'decorators' | 'static fields'; - trace?: boolean; - enableLegacyTemplate?: boolean; - disableExpressionLowering?: boolean; - i18nOutLocale?: string; - i18nOutFormat?: string; - i18nOutFile?: string; - i18nInFormat?: string; - i18nInLocale?: string; - i18nInFile?: string; - i18nInMissingTranslations?: 'error' | 'warning' | 'ignore'; - preserveWhitespaces?: boolean; -} -export interface CompilerHost extends ts.CompilerHost { - moduleNameToFileName(moduleName: string, containingFile?: string): string | null; - fileNameToModuleName(importedFilePath: string, containingFilePath: string): string | null; - resourceNameToFileName(resourceName: string, containingFilePath: string): string | null; - toSummaryFileName(fileName: string, referringSrcFileName: string): string; - fromSummaryFileName(fileName: string, referringLibFileName: string): string; - readResource?(fileName: string): Promise | string; -} -export interface CustomTransformers { - beforeTs?: ts.TransformerFactory[]; - afterTs?: ts.TransformerFactory[]; -} -export interface TsEmitArguments { - program: ts.Program; - host: CompilerHost; - options: CompilerOptions; - targetSourceFile?: ts.SourceFile; - writeFile?: ts.WriteFileCallback; - cancellationToken?: ts.CancellationToken; - emitOnlyDtsFiles?: boolean; - customTransformers?: ts.CustomTransformers; -} -export interface TsEmitCallback { - (args: TsEmitArguments): ts.EmitResult; -} -export interface Program { - getTsProgram(): ts.Program; - getTsOptionDiagnostics(cancellationToken?: ts.CancellationToken): ts.Diagnostic[]; - getNgOptionDiagnostics(cancellationToken?: ts.CancellationToken): Diagnostic[]; - getTsSyntacticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): - ts.Diagnostic[]; - getNgStructuralDiagnostics(cancellationToken?: ts.CancellationToken): Diagnostic[]; - getTsSemanticDiagnostics(sourceFile?: ts.SourceFile, cancellationToken?: ts.CancellationToken): - ts.Diagnostic[]; - getNgSemanticDiagnostics(fileName?: string, cancellationToken?: ts.CancellationToken): - Diagnostic[]; - loadNgStructureAsync(): Promise; - listLazyRoutes?(): LazyRoute[]; - emit({ emitFlags, cancellationToken, customTransformers, emitCallback }: { - emitFlags?: any; - cancellationToken?: ts.CancellationToken; - customTransformers?: CustomTransformers; - emitCallback?: TsEmitCallback; - }): ts.EmitResult; -} - -export interface LazyRoute { - route: string; - module: { name: string, filePath: string }; - referencedModule: { name: string, filePath: string }; -} - -export declare type Diagnostics = Array; - -// Interfaces for the function declarations. -export interface CreateProgramInterface { - ({ rootNames, options, host, oldProgram }: { - rootNames: string[]; - options: CompilerOptions; - host: CompilerHost; - oldProgram?: Program; - }): Program; -} -export interface CreateCompilerHostInterface { - ({ options, tsHost }: { - options: CompilerOptions; - tsHost?: ts.CompilerHost; - }): CompilerHost; -} -export interface FormatDiagnosticsInterface { - (diags: Diagnostics): string; -} -export interface ParsedConfiguration { - project: string; - options: CompilerOptions; - rootNames: string[]; - emitFlags: any; - errors: Diagnostics; -} -export interface ReadConfigurationInterface { - (project: string, existingOptions?: ts.CompilerOptions): ParsedConfiguration; -} - -// Manually check for Compiler CLI availability and supported version. -// This is needed because @ngtools/webpack does not depend directly on @angular/compiler-cli, since -// it is installed as part of global Angular CLI installs and compiler-cli is not of its -// dependencies. -export function CompilerCliIsSupported() { - let version; - - // Check that Angular is available. - try { - version = require('@angular/compiler-cli').VERSION; - } catch (e) { - throw new Error('The "@angular/compiler-cli" package was not properly installed. Error: ' + e); - } - - // Check that Angular is also not part of this module's node_modules (it should be the project's). - const compilerCliPath = require.resolve('@angular/compiler-cli'); - if (compilerCliPath.startsWith(path.dirname(__dirname))) { - throw new Error('The @ngtools/webpack plugin now relies on the project @angular/compiler-cli. ' - + 'Please clean your node_modules and reinstall.'); - } - - // Throw if we're neither 2.3.1 or more, nor 4.x.y, nor 5.x.y. - if (!(version.major == '5' - || version.major == '4' - || (version.major == '2' - && (version.minor == '4' - || version.minor == '3' && version.patch == '1')))) { - throw new Error('Version of @angular/compiler-cli needs to be 2.3.1 or greater. ' - + `Current version is "${version.full}".`); - } -} - -// These imports do not exist on a global install for Angular CLI, so we cannot use a static ES6 -// import. -let compilerCli: any = {}; -try { - compilerCli = require('@angular/compiler-cli'); -} catch (e) { - // Don't throw an error if the private API does not exist. - // Instead, the `CompilerCliIsSupported` method should return throw and indicate the - // plugin cannot be used. -} - -export const VERSION = compilerCli.VERSION; -export const __NGTOOLS_PRIVATE_API_2 = compilerCli.__NGTOOLS_PRIVATE_API_2; - -// These imports do not exist on Angular versions lower than 5, so we cannot use a static ES6 -// import. -let ngtools2: any = {}; -try { - ngtools2 = require('@angular/compiler-cli/ngtools2'); -} catch (e) { - // Don't throw an error if the private API does not exist. - // Instead, the `AngularCompilerPlugin.isSupported` method should return false and indicate the - // plugin cannot be used. -} - -export const createProgram: CreateProgramInterface = ngtools2.createProgram; -export const createCompilerHost: CreateCompilerHostInterface = ngtools2.createCompilerHost; -export const formatDiagnostics: FormatDiagnosticsInterface = ngtools2.formatDiagnostics; -export const readConfiguration: ReadConfigurationInterface = compilerCli.readConfiguration; -export const EmitFlags = ngtools2.EmitFlags; diff --git a/packages/@ngtools/webpack/src/paths-plugin.ts b/packages/@ngtools/webpack/src/paths-plugin.ts deleted file mode 100644 index 8f05721669a9..000000000000 --- a/packages/@ngtools/webpack/src/paths-plugin.ts +++ /dev/null @@ -1,163 +0,0 @@ -// @ignoreDep typescript -import * as path from 'path'; -import * as ts from 'typescript'; -import { - ResolverPlugin, - Callback, - Tapable, - NormalModuleFactory, - NormalModuleFactoryRequest, -} from './webpack'; - - -const ModulesInRootPlugin: new (a: string, b: string, c: string) => ResolverPlugin - = require('enhanced-resolve/lib/ModulesInRootPlugin'); - -export interface Mapping { - onlyModule: boolean; - alias: string; - aliasPattern: RegExp; - target: string; -} - - -function escapeRegExp(str: string): string { - return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'); -} - - -export interface PathsPluginOptions { - nmf: NormalModuleFactory; - tsConfigPath: string; - compilerOptions?: ts.CompilerOptions; - compilerHost?: ts.CompilerHost; -} - -export class PathsPlugin implements Tapable { - private _nmf: NormalModuleFactory; - private _tsConfigPath: string; - private _compilerOptions: ts.CompilerOptions; - private _host: ts.CompilerHost; - - source: string; - target: string; - - private _mappings: Mapping[]; - - private _absoluteBaseUrl: string; - - private static _loadOptionsFromTsConfig(tsConfigPath: string, host?: ts.CompilerHost): - ts.CompilerOptions { - const tsConfig = ts.readConfigFile(tsConfigPath, (path: string) => { - if (host) { - return host.readFile(path); - } else { - return ts.sys.readFile(path); - } - }); - if (tsConfig.error) { - throw tsConfig.error; - } - return tsConfig.config.compilerOptions; - } - - constructor(options: PathsPluginOptions) { - if (!options.hasOwnProperty('tsConfigPath')) { - // This could happen in JavaScript. - throw new Error('tsConfigPath option is mandatory.'); - } - this._tsConfigPath = options.tsConfigPath; - - if (options.compilerOptions) { - this._compilerOptions = options.compilerOptions; - } else { - this._compilerOptions = PathsPlugin._loadOptionsFromTsConfig(this._tsConfigPath); - } - - if (options.compilerHost) { - this._host = options.compilerHost; - } else { - this._host = ts.createCompilerHost(this._compilerOptions, false); - } - - this._nmf = options.nmf; - this.source = 'described-resolve'; - this.target = 'resolve'; - - this._absoluteBaseUrl = path.resolve( - path.dirname(this._tsConfigPath), - this._compilerOptions.baseUrl || '.' - ); - - this._mappings = []; - let paths = this._compilerOptions.paths || {}; - Object.keys(paths).forEach(alias => { - let onlyModule = alias.indexOf('*') === -1; - let excapedAlias = escapeRegExp(alias); - let targets = paths[alias]; - targets.forEach(target => { - let aliasPattern: RegExp; - if (onlyModule) { - aliasPattern = new RegExp(`^${excapedAlias}$`); - } else { - let withStarCapturing = excapedAlias.replace('\\*', '(.*)'); - aliasPattern = new RegExp(`^${withStarCapturing}`); - } - - this._mappings.push({ - onlyModule, - alias, - aliasPattern, - target: target - }); - }); - }); - } - - apply(resolver: ResolverPlugin): void { - let baseUrl = this._compilerOptions.baseUrl || '.'; - - if (baseUrl) { - resolver.apply(new ModulesInRootPlugin('module', this._absoluteBaseUrl, 'resolve')); - } - - this._nmf.plugin('before-resolve', (request: NormalModuleFactoryRequest, - callback: Callback) => { - // Only work on TypeScript issuers. - if (!request.contextInfo.issuer || !request.contextInfo.issuer.endsWith('.ts')) { - return callback(null, request); - } - - for (let mapping of this._mappings) { - const match = request.request.match(mapping.aliasPattern); - if (!match) { continue; } - let newRequestStr = mapping.target; - if (!mapping.onlyModule) { - newRequestStr = newRequestStr.replace('*', match[1]); - } - const moduleResolver = ts.resolveModuleName( - request.request, - request.contextInfo.issuer, - this._compilerOptions, - this._host - ); - let moduleFilePath = moduleResolver.resolvedModule - && moduleResolver.resolvedModule.resolvedFileName; - - // If TypeScript gives us a .d.ts it's probably a node module and we need to let webpack - // do the resolution. - if (moduleFilePath && moduleFilePath.endsWith('.d.ts')) { - moduleFilePath = moduleFilePath.replace(/\.d\.ts$/, '.js'); - if (!this._host.fileExists(moduleFilePath)) { - continue; - } - } - if (moduleFilePath) { - return callback(null, Object.assign({}, request, { request: moduleFilePath })); - } - } - - return callback(null, request); - }); - } -} diff --git a/packages/@ngtools/webpack/src/plugin.ts b/packages/@ngtools/webpack/src/plugin.ts deleted file mode 100644 index 8c256a366794..000000000000 --- a/packages/@ngtools/webpack/src/plugin.ts +++ /dev/null @@ -1,661 +0,0 @@ -// @ignoreDep typescript -import * as fs from 'fs'; -import * as path from 'path'; -import * as ts from 'typescript'; -import * as SourceMap from 'source-map'; - -const ContextElementDependency = require('webpack/lib/dependencies/ContextElementDependency'); -const NodeWatchFileSystem = require('webpack/lib/node/NodeWatchFileSystem'); - -import {CompilerCliIsSupported, __NGTOOLS_PRIVATE_API_2, VERSION} from './ngtools_api'; -import {WebpackResourceLoader} from './resource_loader'; -import {WebpackCompilerHost} from './compiler_host'; -import {resolveEntryModuleFromMain} from './entry_resolver'; -import {Tapable} from './webpack'; -import {PathsPlugin} from './paths-plugin'; -import {findLazyRoutes, LazyRouteMap} from './lazy_routes'; -import {VirtualFileSystemDecorator} from './virtual_file_system_decorator'; -import {time, timeEnd} from './benchmark'; - - -/** - * Option Constants - */ -export interface AotPluginOptions { - sourceMap?: boolean; - tsConfigPath: string; - basePath?: string; - entryModule?: string; - mainPath?: string; - typeChecking?: boolean; - skipCodeGeneration?: boolean; - replaceExport?: boolean; - hostOverrideFileSystem?: { [path: string]: string }; - hostReplacementPaths?: { [path: string]: string }; - i18nFile?: string; - i18nFormat?: string; - locale?: string; - missingTranslation?: string; - - // Use tsconfig to include path globs. - exclude?: string | string[]; - compilerOptions?: ts.CompilerOptions; -} - - -const inlineSourceMapRe = /\/\/# sourceMappingURL=data:application\/json;base64,([\s\S]+)$/; - - -export class AotPlugin implements Tapable { - private _options: AotPluginOptions; - - private _compilerOptions: ts.CompilerOptions; - private _angularCompilerOptions: any; - private _program: ts.Program; - private _moduleResolutionCache?: ts.ModuleResolutionCache; - private _rootFilePath: string[]; - private _compilerHost: WebpackCompilerHost; - private _resourceLoader: WebpackResourceLoader; - private _discoveredLazyRoutes: LazyRouteMap; - private _lazyRoutes: LazyRouteMap = Object.create(null); - private _tsConfigPath: string; - private _entryModule: string; - - private _donePromise: Promise | null; - private _compiler: any = null; - private _compilation: any = null; - - private _typeCheck = true; - private _skipCodeGeneration = false; - private _replaceExport = false; - private _basePath: string; - private _genDir: string; - - private _i18nFile?: string; - private _i18nFormat?: string; - private _locale?: string; - private _missingTranslation?: string; - - private _diagnoseFiles: { [path: string]: boolean } = {}; - private _firstRun = true; - - constructor(options: AotPluginOptions) { - CompilerCliIsSupported(); - this._options = Object.assign({}, options); - this._setupOptions(this._options); - } - - get options() { return this._options; } - get basePath() { return this._basePath; } - get compilation() { return this._compilation; } - get compilerHost() { return this._compilerHost; } - get compilerOptions() { return this._compilerOptions; } - get done() { return this._donePromise; } - get entryModule() { - const splitted = this._entryModule.split('#'); - const path = splitted[0]; - const className = splitted[1] || 'default'; - return {path, className}; - } - get genDir() { return this._genDir; } - get program() { return this._program; } - get moduleResolutionCache() { return this._moduleResolutionCache; } - get skipCodeGeneration() { return this._skipCodeGeneration; } - get replaceExport() { return this._replaceExport; } - get typeCheck() { return this._typeCheck; } - get i18nFile() { return this._i18nFile; } - get i18nFormat() { return this._i18nFormat; } - get locale() { return this._locale; } - get missingTranslation() { return this._missingTranslation; } - get firstRun() { return this._firstRun; } - get lazyRoutes() { return this._lazyRoutes; } - get discoveredLazyRoutes() { return this._discoveredLazyRoutes; } - - private _setupOptions(options: AotPluginOptions) { - time('AotPlugin._setupOptions'); - // Fill in the missing options. - if (!options.hasOwnProperty('tsConfigPath')) { - throw new Error('Must specify "tsConfigPath" in the configuration of @ngtools/webpack.'); - } - // TS represents paths internally with '/' and expects the tsconfig path to be in this format - this._tsConfigPath = options.tsConfigPath.replace(/\\/g, '/'); - - // Check the base path. - const maybeBasePath = path.resolve(process.cwd(), this._tsConfigPath); - let basePath = maybeBasePath; - if (fs.statSync(maybeBasePath).isFile()) { - basePath = path.dirname(basePath); - } - if (options.hasOwnProperty('basePath')) { - basePath = path.resolve(process.cwd(), options.basePath); - } - - const configResult = ts.readConfigFile(this._tsConfigPath, ts.sys.readFile); - if (configResult.error) { - const diagnostic = configResult.error; - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - - if (diagnostic.file) { - const {line, character} = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); - throw new Error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message})`); - } else { - throw new Error(message); - } - } - - const tsConfigJson = configResult.config; - - if (options.hasOwnProperty('compilerOptions')) { - tsConfigJson.compilerOptions = Object.assign({}, - tsConfigJson.compilerOptions, - options.compilerOptions - ); - } - - // Default exclude to **/*.spec.ts files. - if (!options.hasOwnProperty('exclude')) { - options['exclude'] = ['**/*.spec.ts']; - } - - // Add custom excludes to default TypeScript excludes. - if (options.hasOwnProperty('exclude')) { - // If the tsconfig doesn't contain any excludes, we must add the default ones before adding - // any extra ones (otherwise we'd include all of these which can cause unexpected errors). - // This is the same logic as present in TypeScript. - if (!tsConfigJson.exclude) { - tsConfigJson['exclude'] = ['node_modules', 'bower_components', 'jspm_packages']; - if (tsConfigJson.compilerOptions && tsConfigJson.compilerOptions.outDir) { - tsConfigJson.exclude.push(tsConfigJson.compilerOptions.outDir); - } - } - - // Join our custom excludes with the existing ones. - tsConfigJson.exclude = tsConfigJson.exclude.concat(options.exclude); - } - - const tsConfig = ts.parseJsonConfigFileContent( - tsConfigJson, ts.sys, basePath, undefined, this._tsConfigPath); - - let fileNames = tsConfig.fileNames; - this._rootFilePath = fileNames; - - // Check the genDir. We generate a default gendir that's under basepath; it will generate - // a `node_modules` directory and because of that we don't want TypeScript resolution to - // resolve to that directory but the real `node_modules`. - let genDir = path.join(basePath, '$$_gendir'); - - this._compilerOptions = tsConfig.options; - - // Default plugin sourceMap to compiler options setting. - if (!options.hasOwnProperty('sourceMap')) { - options.sourceMap = this._compilerOptions.sourceMap || false; - } - - // Force the right sourcemap options. - if (options.sourceMap) { - this._compilerOptions.sourceMap = true; - this._compilerOptions.inlineSources = true; - this._compilerOptions.inlineSourceMap = false; - this._compilerOptions.sourceRoot = basePath; - } else { - this._compilerOptions.sourceMap = false; - this._compilerOptions.sourceRoot = undefined; - this._compilerOptions.inlineSources = undefined; - this._compilerOptions.inlineSourceMap = undefined; - this._compilerOptions.mapRoot = undefined; - } - - // Default noEmitOnError to true - if (this._compilerOptions.noEmitOnError !== false) { - this._compilerOptions.noEmitOnError = true; - } - - // Compose Angular Compiler Options. - this._angularCompilerOptions = Object.assign( - { genDir }, - this._compilerOptions, - tsConfig.raw['angularCompilerOptions'], - { basePath } - ); - - if (this._angularCompilerOptions.hasOwnProperty('genDir')) { - genDir = path.resolve(basePath, this._angularCompilerOptions.genDir); - this._angularCompilerOptions.genDir = genDir; - } - - this._basePath = basePath; - this._genDir = genDir; - - if (options.typeChecking !== undefined) { - this._typeCheck = options.typeChecking; - } - if (options.skipCodeGeneration !== undefined) { - this._skipCodeGeneration = options.skipCodeGeneration; - } - - this._compilerHost = new WebpackCompilerHost(this._compilerOptions, this._basePath); - - // Override some files in the FileSystem. - if (options.hostOverrideFileSystem) { - for (const filePath of Object.keys(options.hostOverrideFileSystem)) { - this._compilerHost.writeFile(filePath, options.hostOverrideFileSystem[filePath], false); - } - } - // Override some files in the FileSystem with paths from the actual file system. - if (options.hostReplacementPaths) { - for (const filePath of Object.keys(options.hostReplacementPaths)) { - const replacementFilePath = options.hostReplacementPaths[filePath]; - const content = this._compilerHost.readFile(replacementFilePath); - this._compilerHost.writeFile(filePath, content, false); - } - } - - this._program = ts.createProgram( - this._rootFilePath, this._compilerOptions, this._compilerHost); - - // We use absolute paths everywhere. - if (ts.createModuleResolutionCache) { - this._moduleResolutionCache = ts.createModuleResolutionCache( - this._basePath, - (fileName: string) => this._compilerHost.resolve(fileName), - ); - } - - // We enable caching of the filesystem in compilerHost _after_ the program has been created, - // because we don't want SourceFile instances to be cached past this point. - this._compilerHost.enableCaching(); - - this._resourceLoader = new WebpackResourceLoader(); - - if (options.entryModule) { - this._entryModule = options.entryModule; - } else if ((tsConfig.raw['angularCompilerOptions'] as any) - && (tsConfig.raw['angularCompilerOptions'] as any).entryModule) { - this._entryModule = path.resolve(this._basePath, - (tsConfig.raw['angularCompilerOptions'] as any).entryModule); - } - - // still no _entryModule? => try to resolve from mainPath - if (!this._entryModule && options.mainPath) { - const mainPath = path.resolve(basePath, options.mainPath); - this._entryModule = resolveEntryModuleFromMain(mainPath, this._compilerHost, this._program); - } - - if (options.hasOwnProperty('i18nFile')) { - this._i18nFile = options.i18nFile; - } - if (options.hasOwnProperty('i18nFormat')) { - this._i18nFormat = options.i18nFormat; - } - if (options.hasOwnProperty('locale')) { - this._locale = options.locale; - } - if (options.hasOwnProperty('replaceExport')) { - this._replaceExport = options.replaceExport || this._replaceExport; - } - if (options.hasOwnProperty('missingTranslation')) { - const [MAJOR, MINOR, PATCH] = VERSION.full.split('.').map((x: string) => parseInt(x, 10)); - if (MAJOR < 4 || (MINOR == 2 && PATCH < 2)) { - console.warn((`The --missing-translation parameter will be ignored because it is only ` - + `compatible with Angular version 4.2.0 or higher. If you want to use it, please ` - + `upgrade your Angular version.\n`)); - } - this._missingTranslation = options.missingTranslation; - } - timeEnd('AotPlugin._setupOptions'); - } - - private _findLazyRoutesInAst(): LazyRouteMap { - time('AotPlugin._findLazyRoutesInAst'); - const result: LazyRouteMap = Object.create(null); - const changedFilePaths = this._compilerHost.getChangedFilePaths(); - for (const filePath of changedFilePaths) { - const fileLazyRoutes = findLazyRoutes(filePath, this._compilerHost, this._program); - for (const routeKey of Object.keys(fileLazyRoutes)) { - const route = fileLazyRoutes[routeKey]; - if (routeKey in this._lazyRoutes) { - if (route === null) { - this._lazyRoutes[routeKey] = null; - } else if (this._lazyRoutes[routeKey] !== route) { - this._compilation.warnings.push( - new Error(`Duplicated path in loadChildren detected during a rebuild. ` - + `We will take the latest version detected and override it to save rebuild time. ` - + `You should perform a full build to validate that your routes don't overlap.`) - ); - } - } else { - result[routeKey] = route; - } - } - } - timeEnd('AotPlugin._findLazyRoutesInAst'); - return result; - } - - private _getLazyRoutesFromNgtools() { - try { - time('AotPlugin._getLazyRoutesFromNgtools'); - const result = __NGTOOLS_PRIVATE_API_2.listLazyRoutes({ - program: this._program, - host: this._compilerHost, - angularCompilerOptions: this._angularCompilerOptions, - entryModule: this._entryModule - }); - timeEnd('AotPlugin._getLazyRoutesFromNgtools'); - return result; - } catch (err) { - // We silence the error that the @angular/router could not be found. In that case, there is - // basically no route supported by the app itself. - if (err.message.startsWith('Could not resolve module @angular/router')) { - return {}; - } else { - throw err; - } - } - } - - // registration hook for webpack plugin - apply(compiler: any) { - this._compiler = compiler; - - // Decorate inputFileSystem to serve contents of CompilerHost. - // Use decorated inputFileSystem in watchFileSystem. - compiler.plugin('environment', () => { - compiler.inputFileSystem = new VirtualFileSystemDecorator( - compiler.inputFileSystem, this._compilerHost); - compiler.watchFileSystem = new NodeWatchFileSystem(compiler.inputFileSystem); - }); - - compiler.plugin('invalid', () => { - // Turn this off as soon as a file becomes invalid and we're about to start a rebuild. - this._firstRun = false; - this._diagnoseFiles = {}; - }); - - // Add lazy modules to the context module for @angular/core/src/linker - compiler.plugin('context-module-factory', (cmf: any) => { - const angularCorePackagePath = require.resolve('@angular/core/package.json'); - const angularCorePackageJson = require(angularCorePackagePath); - const angularCoreModulePath = path.resolve(path.dirname(angularCorePackagePath), - angularCorePackageJson['module']); - // Pick the last part after the last node_modules instance. We do this to let people have - // a linked @angular/core or cli which would not be under the same path as the project - // being built. - const angularCoreModuleDir = path.dirname(angularCoreModulePath).split(/node_modules/).pop(); - - // Also support the es2015 in Angular versions that have it. - let angularCoreEs2015Dir: string | undefined; - if (angularCorePackageJson['es2015']) { - const angularCoreEs2015Path = path.resolve(path.dirname(angularCorePackagePath), - angularCorePackageJson['es2015']); - angularCoreEs2015Dir = path.dirname(angularCoreEs2015Path).split(/node_modules/).pop(); - } - - cmf.plugin('after-resolve', (result: any, callback: (err?: any, request?: any) => void) => { - if (!result) { - return callback(); - } - - // Alter only request from Angular; - // @angular/core/src/linker matches for 2.*.*, - // The other logic is for flat modules and requires reading the package.json of angular - // (see above). - if (!result.resource.endsWith(path.join('@angular/core/src/linker')) - && !(angularCoreModuleDir && result.resource.endsWith(angularCoreModuleDir)) - && !(angularCoreEs2015Dir && result.resource.endsWith(angularCoreEs2015Dir))) { - return callback(null, result); - } - - this.done!.then(() => { - result.resource = this.genDir; - result.dependencies.forEach((d: any) => d.critical = false); - result.resolveDependencies = (_fs: any, _resource: any, _recursive: any, - _regExp: RegExp, cb: any) => { - const dependencies = Object.keys(this._lazyRoutes) - .map((key) => { - const value = this._lazyRoutes[key]; - if (value !== null) { - return new ContextElementDependency(value, key); - } else { - return null; - } - }) - .filter(x => !!x); - cb(null, dependencies); - }; - return callback(null, result); - }, () => callback(null)) - .catch(err => callback(err)); - }); - }); - - compiler.plugin('make', (compilation: any, cb: any) => this._make(compilation, cb)); - compiler.plugin('after-emit', (compilation: any, cb: any) => { - compilation._ngToolsWebpackPluginInstance = null; - cb(); - }); - compiler.plugin('done', () => { - this._donePromise = null; - this._compilation = null; - }); - - compiler.plugin('after-resolvers', (compiler: any) => { - // Virtual file system. - // Wait for the plugin to be done when requesting `.ts` files directly (entry points), or - // when the issuer is a `.ts` file. - compiler.resolvers.normal.plugin('before-resolve', (request: any, cb: () => void) => { - if (this.done && (request.request.endsWith('.ts') - || (request.context.issuer && request.context.issuer.endsWith('.ts')))) { - this.done.then(() => cb(), () => cb()); - } else { - cb(); - } - }); - }); - - compiler.plugin('normal-module-factory', (nmf: any) => { - compiler.resolvers.normal.apply(new PathsPlugin({ - nmf, - tsConfigPath: this._tsConfigPath, - compilerOptions: this._compilerOptions, - compilerHost: this._compilerHost - })); - }); - } - - private _translateSourceMap(sourceText: string, fileName: string, - {line, character}: {line: number, character: number}) { - const match = sourceText.match(inlineSourceMapRe); - - if (!match) { - return {line, character, fileName}; - } - - // On any error, return line and character. - try { - const sourceMapJson = JSON.parse(Buffer.from(match[1], 'base64').toString()); - const consumer = new SourceMap.SourceMapConsumer(sourceMapJson); - - const original = consumer.originalPositionFor({ line, column: character }); - return { - line: typeof original.line == 'number' ? original.line : line, - character: typeof original.column == 'number' ? original.column : character, - fileName: original.source || fileName - }; - } catch (e) { - return {line, character, fileName}; - } - } - - diagnose(fileName: string) { - if (this._diagnoseFiles[fileName]) { - return; - } - this._diagnoseFiles[fileName] = true; - - const sourceFile = this._program.getSourceFile(fileName); - if (!sourceFile) { - return; - } - - const diagnostics: Array = [ - ...(this._program.getCompilerOptions().declaration - ? this._program.getDeclarationDiagnostics(sourceFile) : []), - ...this._program.getSyntacticDiagnostics(sourceFile), - ...this._program.getSemanticDiagnostics(sourceFile) - ]; - - if (diagnostics.length > 0) { - diagnostics.forEach(diagnostic => { - const messageText = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - let message; - - if (diagnostic.file) { - const position = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start!); - - const sourceText = diagnostic.file.getFullText(); - let {line, character, fileName} = this._translateSourceMap(sourceText, - diagnostic.file.fileName, position); - - message = `${fileName} (${line + 1},${character + 1}): ${messageText}`; - } else { - message = messageText; - } - - switch (diagnostic.category) { - case ts.DiagnosticCategory.Error: - this._compilation.errors.push(message); - break; - - default: - this._compilation.warnings.push(message); - } - }); - } - } - - private _make(compilation: any, cb: (err?: any, request?: any) => void) { - time('AotPlugin._make'); - this._compilation = compilation; - if (this._compilation._ngToolsWebpackPluginInstance) { - return cb(new Error('An @ngtools/webpack plugin already exist for this compilation.')); - } - - this._compilation._ngToolsWebpackPluginInstance = this; - - this._resourceLoader.update(compilation); - - this._donePromise = Promise.resolve() - .then(() => { - if (this._skipCodeGeneration) { - return; - } - - time('AotPlugin._make.codeGen'); - // Create the Code Generator. - return __NGTOOLS_PRIVATE_API_2.codeGen({ - basePath: this._basePath, - compilerOptions: this._compilerOptions, - program: this._program, - host: this._compilerHost, - angularCompilerOptions: this._angularCompilerOptions, - i18nFile: this.i18nFile, - i18nFormat: this.i18nFormat, - locale: this.locale, - missingTranslation: this.missingTranslation, - - readResource: (path: string) => this._resourceLoader.get(path) - }) - .then(() => timeEnd('AotPlugin._make.codeGen')); - }) - .then(() => { - // Get the ngfactory that were created by the previous step, and add them to the root - // file path (if those files exists). - const newRootFilePath = this._compilerHost.getChangedFilePaths() - .filter(x => x.match(/\.ngfactory\.ts$/)); - // Remove files that don't exist anymore, and add new files. - this._rootFilePath = this._rootFilePath - .filter(x => this._compilerHost.fileExists(x)) - .concat(newRootFilePath); - - // Create a new Program, based on the old one. This will trigger a resolution of all - // transitive modules, which include files that might just have been generated. - // This needs to happen after the code generator has been created for generated files - // to be properly resolved. - time('AotPlugin._make.createProgram'); - this._program = ts.createProgram( - this._rootFilePath, this._compilerOptions, this._compilerHost, this._program); - timeEnd('AotPlugin._make.createProgram'); - }) - .then(() => { - // Re-diagnose changed files. - time('AotPlugin._make.diagnose'); - const changedFilePaths = this._compilerHost.getChangedFilePaths(); - changedFilePaths.forEach(filePath => this.diagnose(filePath)); - timeEnd('AotPlugin._make.diagnose'); - }) - .then(() => { - if (this._typeCheck) { - time('AotPlugin._make._typeCheck'); - const diagnostics = this._program.getGlobalDiagnostics(); - if (diagnostics.length > 0) { - const message = diagnostics - .map(diagnostic => { - const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); - - if (diagnostic.file) { - const {line, character} = diagnostic.file.getLineAndCharacterOfPosition( - diagnostic.start!); - return `${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message})`; - } else { - return message; - } - }) - .join('\n'); - - throw new Error(message); - } - timeEnd('AotPlugin._make._typeCheck'); - } - }) - .then(() => { - // We need to run the `listLazyRoutes` the first time because it also navigates libraries - // and other things that we might miss using the findLazyRoutesInAst. - time('AotPlugin._make._discoveredLazyRoutes'); - this._discoveredLazyRoutes = this.firstRun - ? this._getLazyRoutesFromNgtools() - : this._findLazyRoutesInAst(); - - // Process the lazy routes discovered. - Object.keys(this.discoveredLazyRoutes) - .forEach(k => { - const lazyRoute = this.discoveredLazyRoutes[k]; - k = k.split('#')[0]; - if (lazyRoute === null) { - return; - } - - if (this.skipCodeGeneration) { - this._lazyRoutes[k] = lazyRoute; - } else { - const factoryPath = lazyRoute.replace(/(\.d)?\.ts$/, '.ngfactory.ts'); - const lr = path.relative(this.basePath, factoryPath); - this._lazyRoutes[k + '.ngfactory'] = path.join(this.genDir, lr); - } - }); - timeEnd('AotPlugin._make._discoveredLazyRoutes'); - }) - .then(() => { - if (this._compilation.errors == 0) { - this._compilerHost.resetChangedFileTracker(); - } - - timeEnd('AotPlugin._make'); - cb(); - }, (err: any) => { - compilation.errors.push(err.stack); - timeEnd('AotPlugin._make'); - cb(); - }); - } -} diff --git a/packages/@ngtools/webpack/src/refactor.ts b/packages/@ngtools/webpack/src/refactor.ts deleted file mode 100644 index 91faa5e37464..000000000000 --- a/packages/@ngtools/webpack/src/refactor.ts +++ /dev/null @@ -1,272 +0,0 @@ -// @ignoreDep typescript -// TODO: move this in its own package. -import * as path from 'path'; -import * as ts from 'typescript'; -import {SourceMapConsumer, SourceMapGenerator} from 'source-map'; - -const MagicString = require('magic-string'); - - -/** - * Find all nodes from the AST in the subtree of node of SyntaxKind kind. - * @param node The root node to check, or null if the whole tree should be searched. - * @param sourceFile The source file where the node is. - * @param kind The kind of nodes to find. - * @param recursive Whether to go in matched nodes to keep matching. - * @param max The maximum number of items to return. - * @return all nodes of kind, or [] if none is found - */ -// TODO: replace this with collectDeepNodes and add limits to collectDeepNodes -export function findAstNodes( - node: ts.Node | null, - sourceFile: ts.SourceFile, - kind: ts.SyntaxKind, - recursive = false, - max = Infinity -): T[] { - // TODO: refactor operations that only need `refactor.findAstNodes()` to use this instead. - if (max == 0) { - return []; - } - if (!node) { - node = sourceFile; - } - - let arr: T[] = []; - if (node.kind === kind) { - // If we're not recursively looking for children, stop here. - if (!recursive) { - return [node as T]; - } - - arr.push(node as T); - max--; - } - - if (max > 0) { - for (const child of node.getChildren(sourceFile)) { - findAstNodes(child, sourceFile, kind, recursive, max) - .forEach((node: ts.Node) => { - if (max > 0) { - arr.push(node as T); - } - max--; - }); - - if (max <= 0) { - break; - } - } - } - return arr; -} - -export interface TranspileOutput { - outputText: string; - sourceMap: any | null; -} - - -function resolve(filePath: string, _host: ts.CompilerHost, program: ts.Program) { - if (path.isAbsolute(filePath)) { - return filePath; - } - const compilerOptions = program.getCompilerOptions(); - const basePath = compilerOptions.baseUrl || compilerOptions.rootDir; - if (!basePath) { - throw new Error(`Trying to resolve '${filePath}' without a basePath.`); - } - return path.join(basePath, filePath); -} - - -export class TypeScriptFileRefactor { - private _fileName: string; - private _sourceFile: ts.SourceFile; - private _sourceString: any; - private _sourceText: string; - private _changed = false; - - get fileName() { return this._fileName; } - get sourceFile() { return this._sourceFile; } - get sourceText() { return this._sourceString.toString(); } - - constructor(fileName: string, - _host: ts.CompilerHost, - private _program?: ts.Program, - source?: string | null) { - fileName = resolve(fileName, _host, _program!).replace(/\\/g, '/'); - this._fileName = fileName; - if (_program) { - if (source) { - this._sourceFile = ts.createSourceFile(fileName, source, ts.ScriptTarget.Latest, true); - } else { - this._sourceFile = _program.getSourceFile(fileName); - } - } - if (!this._sourceFile) { - this._sourceFile = ts.createSourceFile(fileName, source || _host.readFile(fileName), - ts.ScriptTarget.Latest, true); - } - this._sourceText = this._sourceFile.getFullText(this._sourceFile); - this._sourceString = new MagicString(this._sourceText); - } - - /** - * Collates the diagnostic messages for the current source file - */ - getDiagnostics(typeCheck = true): ts.Diagnostic[] { - if (!this._program) { - return []; - } - let diagnostics: ts.Diagnostic[] = []; - // only concat the declaration diagnostics if the tsconfig config sets it to true. - if (this._program.getCompilerOptions().declaration == true) { - diagnostics = diagnostics.concat(this._program.getDeclarationDiagnostics(this._sourceFile)); - } - diagnostics = diagnostics.concat( - this._program.getSyntacticDiagnostics(this._sourceFile), - typeCheck ? this._program.getSemanticDiagnostics(this._sourceFile) : []); - - return diagnostics; - } - - /** - * Find all nodes from the AST in the subtree of node of SyntaxKind kind. - * @param node The root node to check, or null if the whole tree should be searched. - * @param kind The kind of nodes to find. - * @param recursive Whether to go in matched nodes to keep matching. - * @param max The maximum number of items to return. - * @return all nodes of kind, or [] if none is found - */ - findAstNodes(node: ts.Node | null, - kind: ts.SyntaxKind, - recursive = false, - max = Infinity): ts.Node[] { - return findAstNodes(node, this._sourceFile, kind, recursive, max); - } - - findFirstAstNode(node: ts.Node | null, kind: ts.SyntaxKind): ts.Node | null { - return this.findAstNodes(node, kind, false, 1)[0] || null; - } - - appendAfter(node: ts.Node, text: string): void { - this._sourceString.appendRight(node.getEnd(), text); - } - append(node: ts.Node, text: string): void { - this._sourceString.appendLeft(node.getEnd(), text); - } - - prependBefore(node: ts.Node, text: string) { - this._sourceString.appendLeft(node.getStart(), text); - } - - insertImport(symbolName: string, modulePath: string): void { - // Find all imports. - const allImports = this.findAstNodes(this._sourceFile, ts.SyntaxKind.ImportDeclaration); - const maybeImports = allImports - .filter((node: ts.ImportDeclaration) => { - // Filter all imports that do not match the modulePath. - return node.moduleSpecifier.kind == ts.SyntaxKind.StringLiteral - && (node.moduleSpecifier as ts.StringLiteral).text == modulePath; - }) - .filter((node: ts.ImportDeclaration) => { - // Remove import statements that are either `import 'XYZ'` or `import * as X from 'XYZ'`. - const clause = node.importClause as ts.ImportClause; - if (!clause || clause.name || !clause.namedBindings) { - return false; - } - return clause.namedBindings.kind == ts.SyntaxKind.NamedImports; - }) - .map((node: ts.ImportDeclaration) => { - // Return the `{ ... }` list of the named import. - return (node.importClause as ts.ImportClause).namedBindings as ts.NamedImports; - }); - - if (maybeImports.length) { - // There's an `import {A, B, C} from 'modulePath'`. - // Find if it's in either imports. If so, just return; nothing to do. - const hasImportAlready = maybeImports.some((node: ts.NamedImports) => { - return node.elements.some((element: ts.ImportSpecifier) => { - return element.name.text == symbolName; - }); - }); - if (hasImportAlready) { - return; - } - // Just pick the first one and insert at the end of its identifier list. - this.appendAfter(maybeImports[0].elements[maybeImports[0].elements.length - 1], - `, ${symbolName}`); - } else { - // Find the last import and insert after. - this.appendAfter(allImports[allImports.length - 1], - `import {${symbolName}} from '${modulePath}';`); - } - } - - removeNode(node: ts.Node) { - this._sourceString.remove(node.getStart(this._sourceFile), node.getEnd()); - this._changed = true; - } - - removeNodes(...nodes: Array) { - nodes.forEach(node => node && this.removeNode(node)); - } - - replaceNode(node: ts.Node, replacement: string) { - let replaceSymbolName: boolean = node.kind === ts.SyntaxKind.Identifier; - this._sourceString.overwrite(node.getStart(this._sourceFile), - node.getEnd(), - replacement, - { storeName: replaceSymbolName }); - this._changed = true; - } - - sourceMatch(re: RegExp) { - return this._sourceText.match(re) !== null; - } - - transpile(compilerOptions: ts.CompilerOptions): TranspileOutput { - const source = this.sourceText; - const result = ts.transpileModule(source, { - compilerOptions: Object.assign({}, compilerOptions, { - sourceMap: true, - inlineSources: false, - inlineSourceMap: false, - sourceRoot: '' - }), - fileName: this._fileName - }); - - if (result.sourceMapText) { - const sourceMapJson = JSON.parse(result.sourceMapText); - sourceMapJson.sources = [ this._fileName ]; - - const consumer = new SourceMapConsumer(sourceMapJson); - const map = SourceMapGenerator.fromSourceMap(consumer); - if (this._changed) { - const sourceMap = this._sourceString.generateMap({ - file: path.basename(this._fileName.replace(/\.ts$/, '.js')), - source: this._fileName, - hires: true, - }); - map.applySourceMap(new SourceMapConsumer(sourceMap), this._fileName); - } - - const sourceMap = map.toJSON(); - const fileName = process.platform.startsWith('win') - ? this._fileName.replace(/\//g, '\\') - : this._fileName; - sourceMap.sources = [ fileName ]; - sourceMap.file = path.basename(fileName, '.ts') + '.js'; - sourceMap.sourcesContent = [ this._sourceText ]; - - return { outputText: result.outputText, sourceMap }; - } else { - return { - outputText: result.outputText, - sourceMap: null - }; - } - } -} diff --git a/packages/@ngtools/webpack/src/resource_loader.ts b/packages/@ngtools/webpack/src/resource_loader.ts deleted file mode 100644 index 38dc019c6fbc..000000000000 --- a/packages/@ngtools/webpack/src/resource_loader.ts +++ /dev/null @@ -1,137 +0,0 @@ -import * as vm from 'vm'; -import * as path from 'path'; - -const NodeTemplatePlugin = require('webpack/lib/node/NodeTemplatePlugin'); -const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin'); -const LoaderTargetPlugin = require('webpack/lib/LoaderTargetPlugin'); -const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); - - -interface CompilationOutput { - outputName: string; - source: string; -} - -export class WebpackResourceLoader { - private _parentCompilation: any; - private _context: string; - private _uniqueId = 0; - private _resourceDependencies = new Map(); - - constructor() {} - - update(parentCompilation: any) { - this._parentCompilation = parentCompilation; - this._context = parentCompilation.context; - this._uniqueId = 0; - } - - getResourceDependencies(filePath: string) { - return this._resourceDependencies.get(filePath) || []; - } - - private _compile(filePath: string): Promise { - - if (!this._parentCompilation) { - throw new Error('WebpackResourceLoader cannot be used without parentCompilation'); - } - - const compilerName = `compiler(${this._uniqueId++})`; - const outputOptions = { filename: filePath }; - const relativePath = path.relative(this._context || '', filePath); - const childCompiler = this._parentCompilation.createChildCompiler(relativePath, outputOptions); - childCompiler.context = this._context; - childCompiler.apply( - new NodeTemplatePlugin(outputOptions), - new NodeTargetPlugin(), - new SingleEntryPlugin(this._context, filePath), - new LoaderTargetPlugin('node') - ); - - // Store the result of the parent compilation before we start the child compilation - let assetsBeforeCompilation = Object.assign( - {}, - this._parentCompilation.assets[outputOptions.filename] - ); - - // Fix for "Uncaught TypeError: __webpack_require__(...) is not a function" - // Hot module replacement requires that every child compiler has its own - // cache. @see https://github.com/ampedandwired/html-webpack-plugin/pull/179 - childCompiler.plugin('compilation', function (compilation: any) { - if (compilation.cache) { - if (!compilation.cache[compilerName]) { - compilation.cache[compilerName] = {}; - } - compilation.cache = compilation.cache[compilerName]; - } - }); - - // Compile and return a promise - return new Promise((resolve, reject) => { - childCompiler.runAsChild((err: Error, entries: any[], childCompilation: any) => { - // Resolve / reject the promise - if (childCompilation && childCompilation.errors && childCompilation.errors.length) { - const errorDetails = childCompilation.errors.map(function (error: any) { - return error.message + (error.error ? ':\n' + error.error : ''); - }).join('\n'); - reject(new Error('Child compilation failed:\n' + errorDetails)); - } else if (err) { - reject(err); - } else { - // Replace [hash] placeholders in filename - const outputName = this._parentCompilation.mainTemplate.applyPluginsWaterfall( - 'asset-path', outputOptions.filename, { - hash: childCompilation.hash, - chunk: entries[0] - }); - - // Restore the parent compilation to the state like it was before the child compilation. - Object.keys(childCompilation.assets).forEach((fileName) => { - // If it wasn't there and it's a source file (absolute path) - delete it. - if (assetsBeforeCompilation[fileName] === undefined && path.isAbsolute(fileName)) { - delete this._parentCompilation.assets[fileName]; - } else { - // Otherwise, add it to the parent compilation. - this._parentCompilation.assets[fileName] = childCompilation.assets[fileName]; - } - }); - - // Save the dependencies for this resource. - this._resourceDependencies.set(outputName, childCompilation.fileDependencies); - - resolve({ - // Output name. - outputName, - // Compiled code. - source: childCompilation.assets[outputName].source() - }); - } - }); - }); - } - - private _evaluate(output: CompilationOutput): Promise { - try { - const outputName = output.outputName; - const vmContext = vm.createContext(Object.assign({ require: require }, global)); - const vmScript = new vm.Script(output.source, { filename: outputName }); - - // Evaluate code and cast to string - let evaluatedSource: string; - evaluatedSource = vmScript.runInContext(vmContext); - - if (typeof evaluatedSource == 'string') { - return Promise.resolve(evaluatedSource); - } - - return Promise.reject('The loader "' + outputName + '" didn\'t return a string.'); - } catch (e) { - return Promise.reject(e); - } - } - - get(filePath: string): Promise { - return this._compile(filePath) - .then((result: CompilationOutput) => this._evaluate(result)); - } -} diff --git a/packages/@ngtools/webpack/src/transformers/elide_imports.ts b/packages/@ngtools/webpack/src/transformers/elide_imports.ts deleted file mode 100644 index a12bb030f77b..000000000000 --- a/packages/@ngtools/webpack/src/transformers/elide_imports.ts +++ /dev/null @@ -1,121 +0,0 @@ -// @ignoreDep typescript -import * as ts from 'typescript'; - -import { collectDeepNodes } from './ast_helpers'; -import { RemoveNodeOperation, TransformOperation } from './interfaces'; - - -interface RemovedSymbol { - symbol: ts.Symbol; - importDecl: ts.ImportDeclaration; - importSpec: ts.ImportSpecifier; - singleImport: boolean; - removed: ts.Identifier[]; - all: ts.Identifier[]; -} - -// Remove imports for which all identifiers have been removed. -// Needs type checker, and works even if it's not the first transformer. -// Works by removing imports for symbols whose identifiers have all been removed. -// Doesn't use the `symbol.declarations` because that previous transforms might have removed nodes -// but the type checker doesn't know. -// See https://github.com/Microsoft/TypeScript/issues/17552 for more information. -export function elideImports( - sourceFile: ts.SourceFile, - removedNodes: ts.Node[], - getTypeChecker: () => ts.TypeChecker, -): TransformOperation[] { - const ops: TransformOperation[] = []; - - if (removedNodes.length === 0) { - return []; - } - - // Get all children identifiers inside the removed nodes. - const removedIdentifiers = removedNodes - .map((node) => collectDeepNodes(node, ts.SyntaxKind.Identifier)) - .reduce((prev, curr) => prev.concat(curr), []) - // Also add the top level nodes themselves if they are identifiers. - .concat(removedNodes.filter((node) => - node.kind === ts.SyntaxKind.Identifier) as ts.Identifier[]); - - if (removedIdentifiers.length === 0) { - return []; - } - - // Get all imports in the source file. - const allImports = collectDeepNodes( - sourceFile, ts.SyntaxKind.ImportDeclaration); - - if (allImports.length === 0) { - return []; - } - - const removedSymbolMap: Map = new Map(); - const typeChecker = getTypeChecker(); - - // Find all imports that use a removed identifier and add them to the map. - allImports - .filter((node: ts.ImportDeclaration) => { - // TODO: try to support removing `import * as X from 'XYZ'`. - // Filter out import statements that are either `import 'XYZ'` or `import * as X from 'XYZ'`. - const clause = node.importClause as ts.ImportClause; - if (!clause || clause.name || !clause.namedBindings) { - return false; - } - return clause.namedBindings.kind == ts.SyntaxKind.NamedImports; - }) - .forEach((importDecl: ts.ImportDeclaration) => { - const importClause = importDecl.importClause as ts.ImportClause; - const namedImports = importClause.namedBindings as ts.NamedImports; - - namedImports.elements.forEach((importSpec: ts.ImportSpecifier) => { - const importId = importSpec.name; - const symbol = typeChecker.getSymbolAtLocation(importId); - - const removedNodesForImportId = removedIdentifiers.filter((id) => - id.text === importId.text && typeChecker.getSymbolAtLocation(id) === symbol); - - if (removedNodesForImportId.length > 0) { - removedSymbolMap.set(importId.text, { - symbol, - importDecl, - importSpec, - singleImport: namedImports.elements.length === 1, - removed: removedNodesForImportId, - all: [] - }); - } - }); - }); - - - if (removedSymbolMap.size === 0) { - return []; - } - - // Find all identifiers in the source file that have a removed symbol, and add them to the map. - collectDeepNodes(sourceFile, ts.SyntaxKind.Identifier) - .forEach((id) => { - if (removedSymbolMap.has(id.text)) { - const symbol = removedSymbolMap.get(id.text); - if (typeChecker.getSymbolAtLocation(id) === symbol.symbol) { - symbol.all.push(id); - } - } - }); - - Array.from(removedSymbolMap.values()) - .filter((symbol) => { - // If the number of removed imports plus one (the import specifier) is equal to the total - // number of identifiers for that symbol, it's safe to remove the import. - return symbol.removed.length + 1 === symbol.all.length; - }) - .forEach((symbol) => { - // Remove the whole declaration if it's a single import. - const nodeToRemove = symbol.singleImport ? symbol.importDecl : symbol.importSpec; - ops.push(new RemoveNodeOperation(sourceFile, nodeToRemove)); - }); - - return ops; -} diff --git a/packages/@ngtools/webpack/src/transformers/export_lazy_module_map.spec.ts b/packages/@ngtools/webpack/src/transformers/export_lazy_module_map.spec.ts deleted file mode 100644 index 4663e302fbd9..000000000000 --- a/packages/@ngtools/webpack/src/transformers/export_lazy_module_map.spec.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { transformTypescript } from './ast_helpers'; -import { exportLazyModuleMap } from './export_lazy_module_map'; - -describe('@ngtools/webpack transformers', () => { - describe('export_lazy_module_map', () => { - it('should create module map for JIT', () => { - const input = stripIndent` - export { AppModule } from './app/app.module'; - `; - // tslint:disable:max-line-length - const output = stripIndent` - import * as __lazy_0__ from "app/lazy/lazy.module.ts"; - import * as __lazy_1__ from "app/lazy2/lazy2.module.ts"; - export { AppModule } from './app/app.module'; - export var LAZY_MODULE_MAP = { "./lazy/lazy.module#LazyModule": __lazy_0__.LazyModule, "./lazy2/lazy2.module#LazyModule2": __lazy_1__.LazyModule2 }; - `; - // tslint:enable:max-line-length - - const transformer = exportLazyModuleMap( - () => true, - () => ({ - './lazy/lazy.module#LazyModule': '/project/src/app/lazy/lazy.module.ts', - './lazy2/lazy2.module#LazyModule2': '/project/src/app/lazy2/lazy2.module.ts', - }), - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should create module map for AOT', () => { - const input = stripIndent` - export { AppModule } from './app/app.module'; - `; - // tslint:disable:max-line-length - const expected = stripIndent` - import * as __lazy_0__ from "app/lazy/lazy.module.ngfactory.ts"; - import * as __lazy_1__ from "app/lazy2/lazy2.module.ngfactory.ts"; - export { AppModule } from './app/app.module'; - export var LAZY_MODULE_MAP = { "./lazy/lazy.module#LazyModule": __lazy_0__.LazyModuleNgFactory, "./lazy2/lazy2.module#LazyModule2": __lazy_1__.LazyModule2NgFactory }; - `; - // tslint:enable:max-line-length - - const transformer = exportLazyModuleMap( - () => true, - () => ({ - './lazy/lazy.module.ngfactory#LazyModuleNgFactory': - '/project/src/app/lazy/lazy.module.ngfactory.ts', - './lazy2/lazy2.module.ngfactory#LazyModule2NgFactory': - '/project/src/app/lazy2/lazy2.module.ngfactory.ts', - }), - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${expected}`); - }); - }); - - it('should not do anything if shouldTransform returns false', () => { - const input = stripIndent` - export { AppModule } from './app/app.module'; - `; - - const transformer = exportLazyModuleMap( - () => false, - () => ({ - './lazy/lazy.module#LazyModule': '/project/src/app/lazy/lazy.module.ts', - './lazy2/lazy2.module#LazyModule2': '/project/src/app/lazy2/lazy2.module.ts', - }), - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${input}`); - }); -}); diff --git a/packages/@ngtools/webpack/src/transformers/export_lazy_module_map.ts b/packages/@ngtools/webpack/src/transformers/export_lazy_module_map.ts deleted file mode 100644 index d6ddf92ad7f7..000000000000 --- a/packages/@ngtools/webpack/src/transformers/export_lazy_module_map.ts +++ /dev/null @@ -1,83 +0,0 @@ -// @ignoreDep typescript -import * as path from 'path'; -import * as ts from 'typescript'; - -import { LazyRouteMap } from '../lazy_routes'; -import { getLastNode, getFirstNode } from './ast_helpers'; -import { StandardTransform, TransformOperation, AddNodeOperation } from './interfaces'; -import { makeTransform } from './make_transform'; - -export function exportLazyModuleMap( - shouldTransform: (fileName: string) => boolean, - lazyRoutesCb: () => LazyRouteMap, -): ts.TransformerFactory { - - const standardTransform: StandardTransform = function (sourceFile: ts.SourceFile) { - const ops: TransformOperation[] = []; - - const lazyRoutes = lazyRoutesCb(); - - if (!shouldTransform(sourceFile.fileName)) { - return ops; - } - - const dirName = path.normalize(path.dirname(sourceFile.fileName)); - - const modules = Object.keys(lazyRoutes) - .map((loadChildrenString) => { - const [, moduleName] = loadChildrenString.split('#'); - const modulePath = lazyRoutes[loadChildrenString]; - - return { - modulePath, - moduleName, - loadChildrenString - }; - }); - - modules.forEach((module, index) => { - const relativePath = path.relative(dirName, module.modulePath!).replace(/\\/g, '/'); - // Create the new namespace import node. - const namespaceImport = ts.createNamespaceImport(ts.createIdentifier(`__lazy_${index}__`)); - const importClause = ts.createImportClause(undefined, namespaceImport); - const newImport = ts.createImportDeclaration(undefined, undefined, importClause, - ts.createLiteral(relativePath)); - - ops.push(new AddNodeOperation( - sourceFile, - getFirstNode(sourceFile), - newImport - )); - }); - - const lazyModuleObjectLiteral = ts.createObjectLiteral( - modules.map((mod, idx) => { - let [modulePath, moduleName] = mod.loadChildrenString.split('#'); - if (modulePath.match(/\.ngfactory/)) { - modulePath = modulePath.replace('.ngfactory', ''); - moduleName = moduleName.replace('NgFactory', ''); - } - - return ts.createPropertyAssignment( - ts.createLiteral(`${modulePath}#${moduleName}`), - ts.createPropertyAccess(ts.createIdentifier(`__lazy_${idx}__`), mod.moduleName)); - }) - ); - - const lazyModuleVariableStmt = ts.createVariableStatement( - [ts.createToken(ts.SyntaxKind.ExportKeyword)], - [ts.createVariableDeclaration('LAZY_MODULE_MAP', undefined, lazyModuleObjectLiteral)] - ); - - ops.push(new AddNodeOperation( - sourceFile, - getLastNode(sourceFile), - undefined, - lazyModuleVariableStmt - )); - - return ops; - }; - - return makeTransform(standardTransform); -} diff --git a/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts b/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts deleted file mode 100644 index 324e41bbb4f8..000000000000 --- a/packages/@ngtools/webpack/src/transformers/export_ngfactory.spec.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { transformTypescript } from './ast_helpers'; -import { exportNgFactory } from './export_ngfactory'; - -describe('@ngtools/webpack transformers', () => { - describe('export_ngfactory', () => { - it('should export the ngfactory', () => { - const input = stripIndent` - export { AppModule } from './app/app.module'; - `; - const output = stripIndent` - export { AppModuleNgFactory } from "./app/app.module.ngfactory"; - export { AppModule } from './app/app.module'; - `; - - const transformer = exportNgFactory( - () => true, - () => ({ path: '/project/src/app/app.module', className: 'AppModule' }), - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should export the ngfactory when there is a barrel file', () => { - const input = stripIndent` - export { AppModule } from './app'; - `; - const output = stripIndent` - export { AppModuleNgFactory } from "./app/app.module.ngfactory"; - export { AppModule } from './app'; - `; - - const transformer = exportNgFactory( - () => true, - () => ({ path: '/project/src/app/app.module', className: 'AppModule' }), - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should not do anything if shouldTransform returns false', () => { - const input = stripIndent` - export { AppModule } from './app/app.module'; - `; - - const transformer = exportNgFactory( - () => false, - () => ({ path: '/project/src/app/app.module', className: 'AppModule' }), - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${input}`); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts b/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts deleted file mode 100644 index 1b31be26cb95..000000000000 --- a/packages/@ngtools/webpack/src/transformers/export_ngfactory.ts +++ /dev/null @@ -1,71 +0,0 @@ -// @ignoreDep typescript -import * as ts from 'typescript'; -import { relative, dirname } from 'path'; - -import { collectDeepNodes, getFirstNode } from './ast_helpers'; -import { StandardTransform, TransformOperation, AddNodeOperation } from './interfaces'; -import { makeTransform } from './make_transform'; - -export function exportNgFactory( - shouldTransform: (fileName: string) => boolean, - getEntryModule: () => { path: string, className: string }, -): ts.TransformerFactory { - - const standardTransform: StandardTransform = function (sourceFile: ts.SourceFile) { - const ops: TransformOperation[] = []; - - const entryModule = getEntryModule(); - - if (!shouldTransform(sourceFile.fileName) || !entryModule) { - return ops; - } - - // Find all identifiers using the entry module class name. - const entryModuleIdentifiers = collectDeepNodes(sourceFile, - ts.SyntaxKind.Identifier) - .filter(identifier => identifier.text === entryModule.className); - - if (entryModuleIdentifiers.length === 0) { - return []; - } - - const relativeEntryModulePath = relative(dirname(sourceFile.fileName), entryModule.path); - const normalizedEntryModulePath = `./${relativeEntryModulePath}`.replace(/\\/g, '/'); - - // Get the module path from the import. - let modulePath: string; - entryModuleIdentifiers.forEach((entryModuleIdentifier) => { - if (entryModuleIdentifier.parent.kind !== ts.SyntaxKind.ExportSpecifier) { - return; - } - - const exportSpec = entryModuleIdentifier.parent as ts.ExportSpecifier; - const moduleSpecifier = exportSpec.parent.parent.moduleSpecifier; - - if (moduleSpecifier.kind !== ts.SyntaxKind.StringLiteral) { - return; - } - - modulePath = (moduleSpecifier as ts.StringLiteral).text; - - // Add the transform operations. - const factoryClassName = entryModule.className + 'NgFactory'; - const factoryModulePath = normalizedEntryModulePath + '.ngfactory'; - - const namedExports = ts.createNamedExports([ts.createExportSpecifier(undefined, - ts.createIdentifier(factoryClassName))]); - const newImport = ts.createExportDeclaration(undefined, undefined, namedExports, - ts.createLiteral(factoryModulePath)); - - ops.push(new AddNodeOperation( - sourceFile, - getFirstNode(sourceFile), - newImport - )); - }); - - return ops; - }; - - return makeTransform(standardTransform); -} diff --git a/packages/@ngtools/webpack/src/transformers/index.ts b/packages/@ngtools/webpack/src/transformers/index.ts deleted file mode 100644 index 4ee76368978c..000000000000 --- a/packages/@ngtools/webpack/src/transformers/index.ts +++ /dev/null @@ -1,11 +0,0 @@ -export * from './interfaces'; -export * from './ast_helpers'; -export * from './make_transform'; -export * from './insert_import'; -export * from './elide_imports'; -export * from './replace_bootstrap'; -export * from './export_ngfactory'; -export * from './export_lazy_module_map'; -export * from './register_locale_data'; -export * from './replace_resources'; -export * from './remove_decorators'; diff --git a/packages/@ngtools/webpack/src/transformers/interfaces.ts b/packages/@ngtools/webpack/src/transformers/interfaces.ts deleted file mode 100644 index 5bf6440cddfc..000000000000 --- a/packages/@ngtools/webpack/src/transformers/interfaces.ts +++ /dev/null @@ -1,39 +0,0 @@ -import * as ts from 'typescript'; - -export enum OPERATION_KIND { - Remove, - Add, - Replace -} - -export interface StandardTransform { - (sourceFile: ts.SourceFile): TransformOperation[]; -} - -export abstract class TransformOperation { - constructor( - public kind: OPERATION_KIND, - public sourceFile: ts.SourceFile, - public target: ts.Node - ) { } -} - -export class RemoveNodeOperation extends TransformOperation { - constructor(sourceFile: ts.SourceFile, target: ts.Node) { - super(OPERATION_KIND.Remove, sourceFile, target); - } -} - -export class AddNodeOperation extends TransformOperation { - constructor(sourceFile: ts.SourceFile, target: ts.Node, - public before?: ts.Node, public after?: ts.Node) { - super(OPERATION_KIND.Add, sourceFile, target); - } -} - -export class ReplaceNodeOperation extends TransformOperation { - kind: OPERATION_KIND.Replace; - constructor(sourceFile: ts.SourceFile, target: ts.Node, public replacement: ts.Node) { - super(OPERATION_KIND.Replace, sourceFile, target); - } -} diff --git a/packages/@ngtools/webpack/src/transformers/multiple_transformers.spec.ts b/packages/@ngtools/webpack/src/transformers/multiple_transformers.spec.ts deleted file mode 100644 index 62e7757a9220..000000000000 --- a/packages/@ngtools/webpack/src/transformers/multiple_transformers.spec.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { createTypescriptContext, transformTypescript } from './ast_helpers'; -import { replaceBootstrap } from './replace_bootstrap'; -import { exportNgFactory } from './export_ngfactory'; -import { exportLazyModuleMap } from './export_lazy_module_map'; -import { removeDecorators } from './remove_decorators'; - - -describe('@ngtools/webpack transformers', () => { - describe('multiple_transformers', () => { - it('should apply multiple transformers on the same file', () => { - const input = stripIndent` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - import { Component } from '@angular/core'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] - }) - class AppComponent { - title = 'app'; - } - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - - // tslint:disable:max-line-length - const output = stripIndent` - import * as __lazy_0__ from "app/lazy/lazy.module.ngfactory.ts"; - import * as __lazy_1__ from "app/lazy2/lazy2.module.ngfactory.ts"; - - import { enableProdMode } from '@angular/core'; - import { environment } from './environments/environment'; - - import * as __NgCli_bootstrap_1 from "./app/app.module.ngfactory"; - import * as __NgCli_bootstrap_2 from "@angular/platform-browser"; - - class AppComponent { - constructor() { this.title = 'app'; } - } - - if (environment.production) { - enableProdMode(); - } - __NgCli_bootstrap_2.platformBrowser().bootstrapModuleFactory(__NgCli_bootstrap_1.AppModuleNgFactory); - - export var LAZY_MODULE_MAP = { "./lazy/lazy.module#LazyModule": __lazy_0__.LazyModuleNgFactory, "./lazy2/lazy2.module#LazyModule2": __lazy_1__.LazyModule2NgFactory }; - `; - // tslint:enable:max-line-length - - const { program, compilerHost } = createTypescriptContext(input); - - const shouldTransform = () => true; - const getEntryModule = () => - ({ path: '/project/src/app/app.module', className: 'AppModule' }); - const getTypeChecker = () => program.getTypeChecker(); - - - const transformers = [ - replaceBootstrap(shouldTransform, getEntryModule, getTypeChecker), - exportNgFactory(shouldTransform, getEntryModule), - exportLazyModuleMap(shouldTransform, - () => ({ - './lazy/lazy.module.ngfactory#LazyModuleNgFactory': - '/project/src/app/lazy/lazy.module.ngfactory.ts', - './lazy2/lazy2.module.ngfactory#LazyModule2NgFactory': - '/project/src/app/lazy2/lazy2.module.ngfactory.ts', - })), - removeDecorators(shouldTransform, getTypeChecker), - ]; - - const result = transformTypescript(undefined, transformers, program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/transformers/register_locale_data.spec.ts b/packages/@ngtools/webpack/src/transformers/register_locale_data.spec.ts deleted file mode 100644 index c086e2427133..000000000000 --- a/packages/@ngtools/webpack/src/transformers/register_locale_data.spec.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { transformTypescript } from './ast_helpers'; -import { registerLocaleData } from './register_locale_data'; - -describe('@ngtools/webpack transformers', () => { - describe('register_locale_data', () => { - it('should add locale imports', () => { - const input = stripIndent` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - const output = stripIndent` - import * as __NgCli_locale_1 from "@angular/common/locales/fr"; - import * as __NgCli_locale_2 from "@angular/common"; - __NgCli_locale_2.registerLocaleData(__NgCli_locale_1.default); - - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - - const transformer = registerLocaleData( - () => true, - () => ({ path: '/project/src/app/app.module', className: 'AppModule' }), - 'fr' - ); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should not add locale imports when there is no entry module', () => { - const input = stripIndent` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - - const transformer = registerLocaleData(() => true, () => undefined, 'fr'); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${input}`); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/transformers/remove_decorators.spec.ts b/packages/@ngtools/webpack/src/transformers/remove_decorators.spec.ts deleted file mode 100644 index 3fbfe4ad7203..000000000000 --- a/packages/@ngtools/webpack/src/transformers/remove_decorators.spec.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { createTypescriptContext, transformTypescript } from './ast_helpers'; -import { removeDecorators } from './remove_decorators'; - -describe('@ngtools/webpack transformers', () => { - describe('decorator_remover', () => { - it('should remove Angular decorators', () => { - const input = stripIndent` - import { Component } from '@angular/core'; - - @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] - }) - export class AppComponent { - title = 'app'; - } - `; - const output = stripIndent` - export class AppComponent { - constructor() { - this.title = 'app'; - } - } - `; - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = removeDecorators( - () => true, - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should not remove non-Angular decorators', () => { - const input = stripIndent` - import { Component } from 'another-lib'; - - @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] - }) - export class AppComponent { - title = 'app'; - } - `; - const output = ` - import * as tslib_1 from "tslib"; - import { Component } from 'another-lib'; - let AppComponent = class AppComponent { - constructor() { - this.title = 'app'; - } - }; - AppComponent = tslib_1.__decorate([ - Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] - }) - ], AppComponent); - export { AppComponent }; - `; - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = removeDecorators( - () => true, - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should remove imports for identifiers within the decorator', () => { - const input = stripIndent` - import { Component } from '@angular/core'; - import { ChangeDetectionStrategy } from '@angular/core'; - - @Component({ - selector: 'app-root', - changeDetection: ChangeDetectionStrategy.OnPush, - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] - }) - export class AppComponent { - title = 'app'; - } - `; - const output = stripIndent` - export class AppComponent { - constructor() { - this.title = 'app'; - } - } - `; - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = removeDecorators( - () => true, - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should not remove imports from types that are still used', () => { - const input = stripIndent` - import { Component, EventEmitter } from '@angular/core'; - - @Component({ - selector: 'app-root', - changeDetection: ChangeDetectionStrategy.OnPush, - templateUrl: './app.component.html', - styleUrls: ['./app.component.css'] - }) - export class AppComponent { - notify: EventEmitter = new EventEmitter(); - title = 'app'; - } - `; - const output = stripIndent` - import { EventEmitter } from '@angular/core'; - - export class AppComponent { - constructor() { - this.notify = new EventEmitter(); - this.title = 'app'; - } - } - `; - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = removeDecorators( - () => true, - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/transformers/remove_decorators.ts b/packages/@ngtools/webpack/src/transformers/remove_decorators.ts deleted file mode 100644 index 64f186592fd2..000000000000 --- a/packages/@ngtools/webpack/src/transformers/remove_decorators.ts +++ /dev/null @@ -1,86 +0,0 @@ -import * as ts from 'typescript'; - -import { collectDeepNodes } from './ast_helpers'; -import { StandardTransform, TransformOperation, RemoveNodeOperation } from './interfaces'; -import { makeTransform } from './make_transform'; - - -export function removeDecorators( - shouldTransform: (fileName: string) => boolean, - getTypeChecker: () => ts.TypeChecker, -): ts.TransformerFactory { - - const standardTransform: StandardTransform = function (sourceFile: ts.SourceFile) { - const ops: TransformOperation[] = []; - - if (!shouldTransform(sourceFile.fileName)) { - return ops; - } - - collectDeepNodes(sourceFile, ts.SyntaxKind.Decorator) - .filter((decorator) => shouldRemove(decorator, getTypeChecker())) - .forEach((decorator) => { - // Remove the decorator node. - ops.push(new RemoveNodeOperation(sourceFile, decorator)); - }); - - return ops; - }; - - return makeTransform(standardTransform, getTypeChecker); -} - -function shouldRemove(decorator: ts.Decorator, typeChecker: ts.TypeChecker): boolean { - const origin = getDecoratorOrigin(decorator, typeChecker); - - return origin && origin.module === '@angular/core'; -} - -// Decorator helpers. -interface DecoratorOrigin { - name: string; - module: string; -} - -function getDecoratorOrigin( - decorator: ts.Decorator, - typeChecker: ts.TypeChecker -): DecoratorOrigin | null { - if (!ts.isCallExpression(decorator.expression)) { - return null; - } - - let identifier: ts.Node; - let name: string; - if (ts.isPropertyAccessExpression(decorator.expression.expression)) { - identifier = decorator.expression.expression.expression; - name = decorator.expression.expression.name.text; - } else if (ts.isIdentifier(decorator.expression.expression)) { - identifier = decorator.expression.expression; - } else { - return null; - } - - // NOTE: resolver.getReferencedImportDeclaration would work as well but is internal - const symbol = typeChecker.getSymbolAtLocation(identifier); - if (symbol && symbol.declarations && symbol.declarations.length > 0) { - const declaration = symbol.declarations[0]; - let module: string; - if (ts.isImportSpecifier(declaration)) { - name = (declaration.propertyName || declaration.name).text; - module = (declaration.parent.parent.parent.moduleSpecifier as ts.StringLiteral).text; - } else if (ts.isNamespaceImport(declaration)) { - // Use the name from the decorator namespace property access - module = (declaration.parent.parent.moduleSpecifier as ts.StringLiteral).text; - } else if (ts.isImportClause(declaration)) { - name = declaration.name.text; - module = (declaration.parent.moduleSpecifier as ts.StringLiteral).text; - } else { - return null; - } - - return { name, module }; - } - - return null; -} diff --git a/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts b/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts deleted file mode 100644 index ce4143e0247a..000000000000 --- a/packages/@ngtools/webpack/src/transformers/replace_bootstrap.spec.ts +++ /dev/null @@ -1,115 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { createTypescriptContext, transformTypescript } from './ast_helpers'; -import { replaceBootstrap } from './replace_bootstrap'; - -describe('@ngtools/webpack transformers', () => { - describe('replace_bootstrap', () => { - it('should replace bootstrap', () => { - const input = stripIndent` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - - // tslint:disable:max-line-length - const output = stripIndent` - import { enableProdMode } from '@angular/core'; - import { environment } from './environments/environment'; - - import * as __NgCli_bootstrap_1 from "./app/app.module.ngfactory"; - import * as __NgCli_bootstrap_2 from "@angular/platform-browser"; - - if (environment.production) { - enableProdMode(); - } - __NgCli_bootstrap_2.platformBrowser().bootstrapModuleFactory(__NgCli_bootstrap_1.AppModuleNgFactory); - `; - // tslint:enable:max-line-length - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = replaceBootstrap( - () => true, - () => ({ path: '/project/src/app/app.module', className: 'AppModule' }), - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should replace bootstrap when barrel files are used', () => { - const input = stripIndent` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - - // tslint:disable:max-line-length - const output = stripIndent` - import { enableProdMode } from '@angular/core'; - import { environment } from './environments/environment'; - - import * as __NgCli_bootstrap_1 from "./app/app.module.ngfactory"; - import * as __NgCli_bootstrap_2 from "@angular/platform-browser"; - - if (environment.production) { - enableProdMode(); - } - __NgCli_bootstrap_2.platformBrowser().bootstrapModuleFactory(__NgCli_bootstrap_1.AppModuleNgFactory); - `; - // tslint:enable:max-line-length - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = replaceBootstrap( - () => true, - () => ({ path: '/project/src/app/app.module', className: 'AppModule' }), - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should not replace bootstrap when there is no entry module', () => { - const input = stripIndent` - import { enableProdMode } from '@angular/core'; - import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; - - import { AppModule } from './app/app.module'; - import { environment } from './environments/environment'; - - if (environment.production) { - enableProdMode(); - } - - platformBrowserDynamic().bootstrapModule(AppModule); - `; - - const { program, compilerHost } = createTypescriptContext(input); - const transformer = replaceBootstrap( - () => true, - () => undefined, - () => program.getTypeChecker(), - ); - const result = transformTypescript(undefined, [transformer], program, compilerHost); - - expect(oneLine`${result}`).toEqual(oneLine`${input}`); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/transformers/replace_resources.spec.ts b/packages/@ngtools/webpack/src/transformers/replace_resources.spec.ts deleted file mode 100644 index 0382d746c96f..000000000000 --- a/packages/@ngtools/webpack/src/transformers/replace_resources.spec.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { oneLine, stripIndent } from 'common-tags'; -import { transformTypescript } from './ast_helpers'; -import { replaceResources } from './replace_resources'; - -describe('@ngtools/webpack transformers', () => { - describe('replace_resources', () => { - it('should replace resources', () => { - const input = stripIndent` - import { Component } from '@angular/core'; - - @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css', './app.component.2.css'] - }) - export class AppComponent { - title = 'app'; - } - `; - const output = stripIndent` - import * as tslib_1 from "tslib"; - import { Component } from '@angular/core'; - let AppComponent = class AppComponent { - constructor() { - this.title = 'app'; - } - }; - AppComponent = tslib_1.__decorate([ - Component({ - selector: 'app-root', - template: require("./app.component.html"), - styles: [require("./app.component.css"), require("./app.component.2.css")] - }) - ], AppComponent); - export { AppComponent }; - `; - - const transformer = replaceResources(() => true); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - - it('should not replace resources if shouldTransform returns false', () => { - const input = stripIndent` - import { Component } from '@angular/core'; - - @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css', './app.component.2.css'] - }) - export class AppComponent { - title = 'app'; - } - `; - const output = ` - import * as tslib_1 from "tslib"; - import { Component } from '@angular/core'; - let AppComponent = class AppComponent { - constructor() { - this.title = 'app'; - } - }; - AppComponent = tslib_1.__decorate([ - Component({ - selector: 'app-root', - templateUrl: './app.component.html', - styleUrls: ['./app.component.css', './app.component.2.css'] - }) - ], AppComponent); - export { AppComponent }; - `; - - const transformer = replaceResources(() => false); - const result = transformTypescript(input, [transformer]); - - expect(oneLine`${result}`).toEqual(oneLine`${output}`); - }); - }); -}); diff --git a/packages/@ngtools/webpack/src/type_checker.ts b/packages/@ngtools/webpack/src/type_checker.ts deleted file mode 100644 index e17f363b78ff..000000000000 --- a/packages/@ngtools/webpack/src/type_checker.ts +++ /dev/null @@ -1,173 +0,0 @@ -// @ignoreDep typescript -import * as process from 'process'; -import * as ts from 'typescript'; -import chalk from 'chalk'; - -import { WebpackCompilerHost } from './compiler_host'; -import { time, timeEnd } from './benchmark'; -import { CancellationToken, gatherDiagnostics } from './gather_diagnostics'; -import { - Program, - CompilerOptions, - CompilerHost, - createProgram, - createCompilerHost, - formatDiagnostics, -} from './ngtools_api'; - -// Force basic color support on terminals with no color support. -// Chalk typings don't have the correct constructor parameters. -const chalkCtx = new (chalk.constructor as any)(chalk.supportsColor ? {} : { level: 1 }); -const { bold, red, yellow } = chalkCtx; - -export enum MESSAGE_KIND { - Init, - Update -} - -export abstract class TypeCheckerMessage { - constructor(public kind: MESSAGE_KIND) { } -} - -export class InitMessage extends TypeCheckerMessage { - constructor( - public compilerOptions: ts.CompilerOptions, - public basePath: string, - public jitMode: boolean, - public rootNames: string[], - ) { - super(MESSAGE_KIND.Init); - } -} - -export class UpdateMessage extends TypeCheckerMessage { - constructor(public rootNames: string[], public changedCompilationFiles: string[]) { - super(MESSAGE_KIND.Update); - } -} - -let typeChecker: TypeChecker; -let lastCancellationToken: CancellationToken; - -process.on('message', (message: TypeCheckerMessage) => { - time('TypeChecker.message'); - switch (message.kind) { - case MESSAGE_KIND.Init: - const initMessage = message as InitMessage; - typeChecker = new TypeChecker( - initMessage.compilerOptions, - initMessage.basePath, - initMessage.jitMode, - initMessage.rootNames, - ); - break; - case MESSAGE_KIND.Update: - if (!typeChecker) { - throw new Error('TypeChecker: update message received before initialization'); - } - if (lastCancellationToken) { - // This cancellation token doesn't seem to do much, messages don't seem to be processed - // before the diagnostics finish. - lastCancellationToken.requestCancellation(); - } - const updateMessage = message as UpdateMessage; - lastCancellationToken = new CancellationToken(); - typeChecker.update(updateMessage.rootNames, updateMessage.changedCompilationFiles, - lastCancellationToken); - break; - default: - throw new Error(`TypeChecker: Unexpected message received: ${message}.`); - } - timeEnd('TypeChecker.message'); -}); - - -class TypeChecker { - private _program: ts.Program | Program; - private _compilerHost: WebpackCompilerHost & CompilerHost; - - constructor( - private _compilerOptions: CompilerOptions, - _basePath: string, - private _JitMode: boolean, - private _rootNames: string[], - ) { - time('TypeChecker.constructor'); - const compilerHost = new WebpackCompilerHost(_compilerOptions, _basePath); - compilerHost.enableCaching(); - // We don't set a async resource loader on the compiler host because we only support - // html templates, which are the only ones that can throw errors, and those can be loaded - // synchronously. - // If we need to also report errors on styles then we'll need to ask the main thread - // for these resources. - this._compilerHost = createCompilerHost({ - options: this._compilerOptions, - tsHost: compilerHost - }) as CompilerHost & WebpackCompilerHost; - timeEnd('TypeChecker.constructor'); - } - - private _update(rootNames: string[], changedCompilationFiles: string[]) { - time('TypeChecker._update'); - this._rootNames = rootNames; - changedCompilationFiles.forEach((fileName) => { - this._compilerHost.invalidate(fileName); - }); - timeEnd('TypeChecker._update'); - } - - private _createOrUpdateProgram() { - if (this._JitMode) { - // Create the TypeScript program. - time('TypeChecker._createOrUpdateProgram.ts.createProgram'); - this._program = ts.createProgram( - this._rootNames, - this._compilerOptions, - this._compilerHost, - this._program as ts.Program - ) as ts.Program; - timeEnd('TypeChecker._createOrUpdateProgram.ts.createProgram'); - } else { - time('TypeChecker._createOrUpdateProgram.ng.createProgram'); - // Create the Angular program. - this._program = createProgram({ - rootNames: this._rootNames, - options: this._compilerOptions, - host: this._compilerHost, - oldProgram: this._program as Program - }) as Program; - timeEnd('TypeChecker._createOrUpdateProgram.ng.createProgram'); - } - } - - private _diagnose(cancellationToken: CancellationToken) { - const allDiagnostics = gatherDiagnostics( - this._program, this._JitMode, 'TypeChecker', cancellationToken); - - // Report diagnostics. - if (!cancellationToken.isCancellationRequested()) { - const errors = allDiagnostics.filter((d) => d.category === ts.DiagnosticCategory.Error); - const warnings = allDiagnostics.filter((d) => d.category === ts.DiagnosticCategory.Warning); - - if (errors.length > 0) { - const message = formatDiagnostics(errors); - console.error(bold(red('ERROR in ' + message))); - } else { - // Reset the changed file tracker only if there are no errors. - this._compilerHost.resetChangedFileTracker(); - } - - if (warnings.length > 0) { - const message = formatDiagnostics(warnings); - console.log(bold(yellow('WARNING in ' + message))); - } - } - } - - public update(rootNames: string[], changedCompilationFiles: string[], - cancellationToken: CancellationToken) { - this._update(rootNames, changedCompilationFiles); - this._createOrUpdateProgram(); - this._diagnose(cancellationToken); - } -} diff --git a/packages/@ngtools/webpack/src/type_checker_bootstrap.js b/packages/@ngtools/webpack/src/type_checker_bootstrap.js deleted file mode 100644 index e5a3ab002ecc..000000000000 --- a/packages/@ngtools/webpack/src/type_checker_bootstrap.js +++ /dev/null @@ -1,2 +0,0 @@ -require('../../../../lib/bootstrap-local'); -require('./type_checker.ts'); diff --git a/packages/@ngtools/webpack/src/virtual_file_system_decorator.ts b/packages/@ngtools/webpack/src/virtual_file_system_decorator.ts deleted file mode 100644 index 7cf5d3d88b4b..000000000000 --- a/packages/@ngtools/webpack/src/virtual_file_system_decorator.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { Stats } from 'fs'; - -import { InputFileSystem, NodeWatchFileSystemInterface, Callback } from './webpack'; -import { WebpackCompilerHost } from './compiler_host'; - -export const NodeWatchFileSystem: NodeWatchFileSystemInterface = require( - 'webpack/lib/node/NodeWatchFileSystem'); - -export class VirtualFileSystemDecorator implements InputFileSystem { - constructor( - private _inputFileSystem: InputFileSystem, - private _webpackCompilerHost: WebpackCompilerHost - ) { } - - // We only need to intercept calls to individual files that are present in WebpackCompilerHost. - private _readFileSync(path: string): string | null { - if (this._webpackCompilerHost.fileExists(path, false)) { - return this._webpackCompilerHost.readFile(path); - } - - return null; - } - - private _statSync(path: string): Stats | null { - if (this._webpackCompilerHost.fileExists(path, false)) { - return this._webpackCompilerHost.stat(path); - } - - return null; - } - - getVirtualFilesPaths() { - return this._webpackCompilerHost.getNgFactoryPaths(); - } - - stat(path: string, callback: Callback): void { - const result = this._statSync(path); - if (result) { - callback(null, result); - } else { - this._inputFileSystem.stat(path, callback); - } - } - - readdir(path: string, callback: Callback): void { - this._inputFileSystem.readdir(path, callback); - } - - readFile(path: string, callback: Callback): void { - const result = this._readFileSync(path); - if (result) { - callback(null, result); - } else { - this._inputFileSystem.readFile(path, callback); - } - } - - readJson(path: string, callback: Callback): void { - this._inputFileSystem.readJson(path, callback); - } - - readlink(path: string, callback: Callback): void { - this._inputFileSystem.readlink(path, callback); - } - - statSync(path: string): Stats { - const result = this._statSync(path); - return result || this._inputFileSystem.statSync(path); - } - - readdirSync(path: string): string[] { - return this._inputFileSystem.readdirSync(path); - } - - readFileSync(path: string): string { - const result = this._readFileSync(path); - return result || this._inputFileSystem.readFileSync(path); - } - - readJsonSync(path: string): string { - return this._inputFileSystem.readJsonSync(path); - } - - readlinkSync(path: string): string { - return this._inputFileSystem.readlinkSync(path); - } - - purge(changes?: string[] | string): void { - if (typeof changes === 'string') { - this._webpackCompilerHost.invalidate(changes); - } else if (Array.isArray(changes)) { - changes.forEach((fileName: string) => this._webpackCompilerHost.invalidate(fileName)); - } - if (this._inputFileSystem.purge) { - this._inputFileSystem.purge(changes); - } - } -} - -export class VirtualWatchFileSystemDecorator extends NodeWatchFileSystem { - constructor(private _virtualInputFileSystem: VirtualFileSystemDecorator) { - super(_virtualInputFileSystem); - } - - watch(files: any, dirs: any, missing: any, startTime: any, options: any, callback: any, - callbackUndelayed: any) { - const newCallback = (err: any, filesModified: any, contextModified: any, missingModified: any, - fileTimestamps: { [k: string]: number }, contextTimestamps: { [k: string]: number }) => { - // Update fileTimestamps with timestamps from virtual files. - const virtualFilesStats = this._virtualInputFileSystem.getVirtualFilesPaths() - .map((fileName) => ({ - path: fileName, - mtime: +this._virtualInputFileSystem.statSync(fileName).mtime - })); - virtualFilesStats.forEach(stats => fileTimestamps[stats.path] = +stats.mtime); - callback(err, filesModified, contextModified, missingModified, fileTimestamps, - contextTimestamps); - }; - return super.watch(files, dirs, missing, startTime, options, newCallback, callbackUndelayed); - } -} diff --git a/packages/@ngtools/webpack/src/webpack.ts b/packages/@ngtools/webpack/src/webpack.ts deleted file mode 100644 index e6c9a580f69e..000000000000 --- a/packages/@ngtools/webpack/src/webpack.ts +++ /dev/null @@ -1,84 +0,0 @@ -import { Stats } from 'fs'; - -// Declarations for (some) Webpack types. Only what's needed. - -export interface Request { - request?: Request; - relativePath: string; -} - -export interface Callback { - (err?: Error | null, result?: T): void; -} - -export interface ResolverCallback { - (request: Request, callback: Callback): void; -} - -export interface Tapable { - apply(plugin: ResolverPlugin): void; -} - -export interface ResolverPlugin extends Tapable { - plugin(source: string, cb: ResolverCallback): void; - doResolve(target: string, req: Request, desc: string, callback: Callback): void; - join(relativePath: string, innerRequest: Request): Request; -} - -export interface LoaderCallback { - (err: Error | null, source?: string, sourceMap?: string): void; -} - -export interface ModuleReason { - dependency: any; - module: NormalModule; -} - -export interface NormalModule { - buildTimestamp: number; - built: boolean; - reasons: ModuleReason[]; - resource: string; -} - -export interface NormalModuleFactory { - plugin(event: string, - callback: (data: NormalModuleFactoryRequest, callback: Callback) => void): any; -} - -export interface NormalModuleFactoryRequest { - request: string; - contextInfo: { issuer: string }; -} - -export interface LoaderContext { - _module: NormalModule; - - addDependency(path: string): void; - async(): LoaderCallback; - cacheable(): void; - - readonly resourcePath: string; - readonly query: any; -} - -export interface InputFileSystem { - stat(path: string, callback: Callback): void; - readdir(path: string, callback: Callback): void; - readFile(path: string, callback: Callback): void; - readJson(path: string, callback: Callback): void; - readlink(path: string, callback: Callback): void; - statSync(path: string): Stats; - readdirSync(path: string): string[]; - readFileSync(path: string): string; - readJsonSync(path: string): string; - readlinkSync(path: string): string; - purge(changes?: string[] | string): void; -} - -export interface NodeWatchFileSystemInterface { - inputFileSystem: InputFileSystem; - new(inputFileSystem: InputFileSystem): NodeWatchFileSystemInterface; - watch(files: any, dirs: any, missing: any, startTime: any, options: any, callback: any, - callbackUndelayed: any): any; -} diff --git a/packages/@ngtools/webpack/tsconfig.json b/packages/@ngtools/webpack/tsconfig.json deleted file mode 100644 index 46fb29b75bb1..000000000000 --- a/packages/@ngtools/webpack/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../../tsconfig.json", - - "compilerOptions": { - "outDir": "../../../dist/@ngtools/webpack", - "rootDir": ".", - "baseUrl": "" - } -} diff --git a/packages/_/benchmark/package.json b/packages/_/benchmark/package.json new file mode 100644 index 000000000000..ba691f860a1a --- /dev/null +++ b/packages/_/benchmark/package.json @@ -0,0 +1,11 @@ +{ + "name": "@_/benchmark", + "version": "0.0.0", + "description": "CLI tool for Angular", + "main": "src/index.js", + "typings": "src/index.d.ts", + "scripts": { + "preinstall": "echo DO NOT INSTALL THIS PROJECT, ONLY THE ROOT PROJECT. && exit 1" + }, + "private": true +} diff --git a/packages/_/benchmark/src/benchmark.ts b/packages/_/benchmark/src/benchmark.ts new file mode 100644 index 000000000000..7c22abe0136f --- /dev/null +++ b/packages/_/benchmark/src/benchmark.ts @@ -0,0 +1,86 @@ +/** + * @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 + */ +declare const global: { + benchmarkReporter: { + reportBenchmark: Function, + }, +}; + + +const kNanosecondsPerSeconds = 1e9; +const kBenchmarkIterationMaxCount = 10000; +const kBenchmarkTimeoutInMsec = 5000; +const kWarmupIterationCount = 100; +const kTopMetricCount = 5; + + +function _run(fn: (i: number) => void, collector: number[]) { + const timeout = Date.now(); + // Gather the first 5 seconds runs, or kMaxNumberOfIterations runs whichever comes first + // (soft timeout). + for (let i = 0; + i < kBenchmarkIterationMaxCount && (Date.now() - timeout) < kBenchmarkTimeoutInMsec; + i++) { + // Start time. + const start = process.hrtime(); + fn(i); + // Get the stop difference time. + const diff = process.hrtime(start); + + // Add to metrics. + collector.push(diff[0] * kNanosecondsPerSeconds + diff[1]); + } +} + + +function _stats(metrics: number[]) { + metrics.sort((a, b) => a - b); + + const count = metrics.length; + const middle = count / 2; + const mean = Number.isInteger(middle) + ? metrics[middle] : ((metrics[middle - 0.5] + metrics[middle + 0.5]) / 2); + const total = metrics.reduce((acc, curr) => acc + curr, 0); + const average = total / count; + + return { + count: count, + fastest: metrics.slice(0, kTopMetricCount), + slowest: metrics.reverse().slice(0, kTopMetricCount), + mean, + average, + }; +} + + +export function benchmark(name: string, fn: (i: number) => void, base?: (i: number) => void) { + it(name + ' (time in nanoseconds)', (done) => { + process.nextTick(() => { + for (let i = 0; i < kWarmupIterationCount; i++) { + // Warm it up. + fn(i); + } + + const reporter = global.benchmarkReporter; + const metrics: number[] = []; + const baseMetrics: number[] = []; + + _run(fn, metrics); + if (base) { + _run(base, baseMetrics); + } + + reporter.reportBenchmark({ + ..._stats(metrics), + base: base ? _stats(baseMetrics) : null, + }); + + done(); + }); + }); +} diff --git a/packages/_/benchmark/src/index.ts b/packages/_/benchmark/src/index.ts new file mode 100644 index 000000000000..df56b2754b0b --- /dev/null +++ b/packages/_/benchmark/src/index.ts @@ -0,0 +1,8 @@ +/** + * @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 + */ +export * from './benchmark'; diff --git a/packages/_/builders/builders.json b/packages/_/builders/builders.json new file mode 100644 index 000000000000..87914ed792d2 --- /dev/null +++ b/packages/_/builders/builders.json @@ -0,0 +1,10 @@ +{ + "$schema": "../architect/src/builders-schema.json", + "builders": { + "true": { + "class": "./src/true", + "schema": "./src/noop-schema.json", + "description": "Always succeed." + } + } +} diff --git a/packages/_/builders/package.json b/packages/_/builders/package.json new file mode 100644 index 000000000000..0f9d3729d481 --- /dev/null +++ b/packages/_/builders/package.json @@ -0,0 +1,12 @@ +{ + "name": "@_/builders", + "version": "0.0.0", + "description": "CLI tool for Angular", + "main": "src/index.js", + "typings": "src/index.d.ts", + "builders": "builders.json", + "private": true, + "dependencies": { + "rxjs": "6.3.3" + } +} diff --git a/packages/_/builders/src/noop-schema.json b/packages/_/builders/src/noop-schema.json new file mode 100644 index 000000000000..afadf0925f37 --- /dev/null +++ b/packages/_/builders/src/noop-schema.json @@ -0,0 +1,4 @@ +{ + "$schema": "http://json-schema.org/schema", + "type": "object" +} \ No newline at end of file diff --git a/packages/_/builders/src/true.ts b/packages/_/builders/src/true.ts new file mode 100644 index 000000000000..efe9b7cb0046 --- /dev/null +++ b/packages/_/builders/src/true.ts @@ -0,0 +1,20 @@ +/** + * @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 { Observable, of } from 'rxjs'; + +export class TrueBuilder { + constructor() {} + + run(): Observable<{ success: boolean }> { + return of({ + success: true, + }); + } +} + +export default TrueBuilder; diff --git a/packages/_/devkit/collection.json b/packages/_/devkit/collection.json new file mode 100644 index 000000000000..0353b644307c --- /dev/null +++ b/packages/_/devkit/collection.json @@ -0,0 +1,9 @@ +{ + "schematics": { + "package": { + "factory": "./package/factory", + "schema": "./package/schema.json", + "description": "Create an empty schematic project or add a blank schematic to the current project." + } + } +} diff --git a/packages/_/devkit/package.json b/packages/_/devkit/package.json new file mode 100644 index 000000000000..23b4a671ac7e --- /dev/null +++ b/packages/_/devkit/package.json @@ -0,0 +1,14 @@ +{ + "name": "devkit", + "version": "0.0.0", + "description": "Schematics specific to DevKit (used internally, not released)", + "scripts": { + "preinstall": "echo DO NOT INSTALL THIS PROJECT, ONLY THE ROOT PROJECT. && exit 1" + }, + "schematics": "./collection.json", + "private": true, + "dependencies": { + "@angular-devkit/core": "0.0.0", + "@angular-devkit/schematics": "0.0.0" + } +} diff --git a/packages/_/devkit/package/factory.ts b/packages/_/devkit/package/factory.ts new file mode 100644 index 000000000000..9068a3d4ac24 --- /dev/null +++ b/packages/_/devkit/package/factory.ts @@ -0,0 +1,102 @@ +/** + * @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 { JsonAstObject, JsonValue, parseJsonAst } from '@angular-devkit/core'; +import { + Rule, + Tree, + UpdateRecorder, + apply, + chain, + mergeWith, + template, + url, +} from '@angular-devkit/schematics'; +import { Schema } from './schema'; + + +function appendPropertyInAstObject( + recorder: UpdateRecorder, + node: JsonAstObject, + propertyName: string, + value: JsonValue, + indent = 4, +) { + const indentStr = '\n' + new Array(indent + 1).join(' '); + + if (node.properties.length > 0) { + // Insert comma. + const last = node.properties[node.properties.length - 1]; + recorder.insertRight(last.start.offset + last.text.replace(/\s+$/, '').length, ','); + } + + recorder.insertLeft( + node.end.offset - 1, + ' ' + + `"${propertyName}": ${JSON.stringify(value, null, 2).replace(/\n/g, indentStr)}` + + indentStr.slice(0, -2), + ); +} + +function addPackageToMonorepo(options: Schema, path: string): Rule { + return (tree: Tree) => { + const collectionJsonContent = tree.read('/.monorepo.json'); + if (!collectionJsonContent) { + throw new Error('Could not find monorepo.json'); + } + const collectionJsonAst = parseJsonAst(collectionJsonContent.toString('utf-8')); + if (collectionJsonAst.kind !== 'object') { + throw new Error('Invalid monorepo content.'); + } + + const packages = collectionJsonAst.properties.find(x => x.key.value == 'packages'); + if (!packages) { + throw new Error('Cannot find packages key in monorepo.'); + } + if (packages.value.kind != 'object') { + throw new Error('Invalid packages key.'); + } + + const readmeUrl = `https://github.com/angular/angular-cli/blob/master/${path}/README.md`; + + const recorder = tree.beginUpdate('/.monorepo.json'); + appendPropertyInAstObject( + recorder, + packages.value, + options.name, + { + name: options.displayName, + links: [{ label: 'README', url: readmeUrl }], + version: '0.0.1', + hash: '', + }, + ); + tree.commitUpdate(recorder); + }; +} + + +export default function (options: Schema): Rule { + const path = 'packages/' + + options.name + .replace(/^@/, '') + .replace(/-/g, '_'); + + // Verify if we need to create a full project, or just add a new schematic. + const source = apply(url('./project-files'), [ + template({ + ...options as object, + dot: '.', + path, + }), + ]); + + return chain([ + mergeWith(source), + addPackageToMonorepo(options, path), + ]); +} diff --git a/packages/_/devkit/package/project-files/__path__/README.md b/packages/_/devkit/package/project-files/__path__/README.md new file mode 100644 index 000000000000..f4b425475360 --- /dev/null +++ b/packages/_/devkit/package/project-files/__path__/README.md @@ -0,0 +1,3 @@ +# <%= displayName %> + +Work in progress diff --git a/packages/_/devkit/package/project-files/__path__/package.json b/packages/_/devkit/package/project-files/__path__/package.json new file mode 100644 index 000000000000..7126e5f40667 --- /dev/null +++ b/packages/_/devkit/package/project-files/__path__/package.json @@ -0,0 +1,16 @@ +{ + "name": "<%= name %>", + "version": "0.0.0", + "description": "<%= description %>", + "main": "src/index.js", + "typings": "src/index.d.ts", + "scripts": { + "preinstall": "echo DO NOT INSTALL THIS PROJECT, ONLY THE ROOT PROJECT. && exit 1" + }, + "keywords": [ + ], + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "0.0.0" + } +} diff --git a/packages/_/devkit/package/project-files/__path__/src/index.ts b/packages/_/devkit/package/project-files/__path__/src/index.ts new file mode 100644 index 000000000000..258badcf91cd --- /dev/null +++ b/packages/_/devkit/package/project-files/__path__/src/index.ts @@ -0,0 +1,10 @@ +/** + * @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 + */ + +// TODO: Make this useful (and awesome). +export default 1; diff --git a/packages/_/devkit/package/schema.d.ts b/packages/_/devkit/package/schema.d.ts new file mode 100644 index 000000000000..0f2b32ac37a9 --- /dev/null +++ b/packages/_/devkit/package/schema.d.ts @@ -0,0 +1,13 @@ +/** + * @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 + */ + +export interface Schema { + name: string; + description: string; + displayName: string; +} diff --git a/packages/_/devkit/package/schema.json b/packages/_/devkit/package/schema.json new file mode 100644 index 000000000000..1689719bd985 --- /dev/null +++ b/packages/_/devkit/package/schema.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/schema", + "id": "SchematicsSchematicSchema", + "title": "DevKit Package Schematic Schema", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The package name for the new schematic.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "description": { + "type": "string", + "description": "The description of the new package" + }, + "displayName": { + "type": "string", + "$default": { + "$source": "interpolation", + "value": "${name}" + }, + "description": "The human readable name." + } + } +} diff --git a/packages/angular/cli/BUILD b/packages/angular/cli/BUILD new file mode 100644 index 000000000000..b98389597251 --- /dev/null +++ b/packages/angular/cli/BUILD @@ -0,0 +1,207 @@ +# 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 + +licenses(["notice"]) # MIT + +load("@build_bazel_rules_typescript//:defs.bzl", "ts_library") +load("//tools:ts_json_schema.bzl", "ts_json_schema") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "angular-cli", + srcs = glob( + ["**/*.ts"], + exclude = [ + "**/*_spec.ts", + "**/*_spec_large.ts", + ], + ), + data = glob(["**/*.json"]), + module_name = "@angular/cli", + deps = [ + ":command_schemas", + "//packages/angular_devkit/architect", + "//packages/angular_devkit/core", + "//packages/angular_devkit/core:node", + "//packages/angular_devkit/schematics", + "//packages/angular_devkit/schematics:tools", + "@rxjs", + "@rxjs//operators", + # @typings: es2017.object + # @typings: inquirer + # @typings: node + # @typings: semver + ], +) + +ts_library( + name = "command_schemas", + srcs = [], + deps = [ + ":add_schema", + ":build_schema", + ":config_schema", + ":deprecated_schema", + ":doc_schema", + ":e2e_schema", + ":easter_egg_schema", + ":eject_schema", + ":generate_schema", + ":help_schema", + ":lint_schema", + ":new_schema", + ":run_schema", + ":serve_schema", + ":test_schema", + ":update_schema", + ":version_schema", + ":xi18n_schema", + ], +) + +ts_json_schema( + name = "add_schema", + src = "commands/add.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "build_schema", + src = "commands/build.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "config_schema", + src = "commands/config.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "deprecated_schema", + src = "commands/deprecated.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "doc_schema", + src = "commands/doc.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "e2e_schema", + src = "commands/e2e.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "easter_egg_schema", + src = "commands/easter-egg.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "eject_schema", + src = "commands/eject.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "generate_schema", + src = "commands/generate.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "help_schema", + src = "commands/help.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "lint_schema", + src = "commands/lint.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "new_schema", + src = "commands/new.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "run_schema", + src = "commands/run.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "serve_schema", + src = "commands/serve.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "test_schema", + src = "commands/test.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "update_schema", + src = "commands/update.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "version_schema", + src = "commands/version.json", + data = [ + "commands/definitions.json", + ], +) + +ts_json_schema( + name = "xi18n_schema", + src = "commands/xi18n.json", + data = [ + "commands/definitions.json", + ], +) diff --git a/packages/angular/cli/README.md b/packages/angular/cli/README.md new file mode 100644 index 000000000000..a0e74dfcf7e4 --- /dev/null +++ b/packages/angular/cli/README.md @@ -0,0 +1,268 @@ +## Angular CLI + + +[![Dependency Status][david-badge]][david-badge-url] +[![devDependency Status][david-dev-badge]][david-dev-badge-url] + +[![npm](https://img.shields.io/npm/v/%40angular/cli.svg)][npm-badge-url] +[![npm](https://img.shields.io/npm/v/%40angular/cli/next.svg)][npm-badge-url] +[![npm](https://img.shields.io/npm/l/@angular/cli.svg)][npm-badge-url] +[![npm](https://img.shields.io/npm/dm/@angular/cli.svg)][npm-badge-url] + +[![Join the chat at https://gitter.im/angular/angular-cli](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/angular/angular-cli?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[![GitHub forks](https://img.shields.io/github/forks/angular/angular-cli.svg?style=social&label=Fork)](https://github.com/angular/angular-cli/fork) +[![GitHub stars](https://img.shields.io/github/stars/angular/angular-cli.svg?style=social&label=Star)](https://github.com/angular/angular-cli) + + +## Note + +If you are updating from a beta or RC version, check out our [1.0 Update Guide](https://github.com/angular/angular-cli/wiki/stories-1.0-update). + +If you wish to collaborate, check out [our issue list](https://github.com/angular/angular-cli/issues). + +Before submitting new issues, have a look at [issues marked with the `type: faq` label](https://github.com/angular/angular-cli/issues?utf8=%E2%9C%93&q=is%3Aissue%20label%3A%22type%3A%20faq%22%20). + +## Prerequisites + +Both the CLI and generated project have dependencies that require Node 8.9 or higher, together +with NPM 5.5.1 or higher. + +## Table of Contents + +* [Installation](#installation) +* [Usage](#usage) +* [Generating a New Project](#generating-and-serving-an-angular-project-via-a-development-server) +* [Generating Components, Directives, Pipes and Services](#generating-components-directives-pipes-and-services) +* [Updating Angular CLI](#updating-angular-cli) +* [Development Hints for working on Angular CLI](#development-hints-for-working-on-angular-cli) +* [Documentation](#documentation) +* [License](#license) + +## Installation + +**BEFORE YOU INSTALL:** please read the [prerequisites](#prerequisites) + +### Install Globablly +```bash +npm install -g @angular/cli +``` + +### Install Locally +```bash +npm install @angular/cli +``` + +To run a locally installed version of the angular-cli, you can call `ng` commands directly by adding the `.bin` folder within your local `node_modules` folder to your PATH. The `node_modules` and `.bin` folders are created in the directory where `npm install @angular/cli` was run upon completion of the install command. + +Alternatively, you can install [npx](https://www.npmjs.com/package/npx) and run `npx ng ` within the local directory where `npm install @angular/cli` was run, which will use the locally installed angular-cli. + +### Install Specific Version (Example: 6.1.1) +```bash +npm install -g @angular/cli@6.1.1 +``` + +## Usage + +```bash +ng help +``` + +### Generating and serving an Angular project via a development server + +```bash +ng new PROJECT-NAME +cd PROJECT-NAME +ng serve +``` +Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. + +You can configure the default HTTP host and port used by the development server with two command-line options : + +```bash +ng serve --host 0.0.0.0 --port 4201 +``` + +### Generating Components, Directives, Pipes and Services + +You can use the `ng generate` (or just `ng g`) command to generate Angular components: + +```bash +ng generate component my-new-component +ng g component my-new-component # using the alias + +# components support relative path generation +# if in the directory src/app/feature/ and you run +ng g component new-cmp +# your component will be generated in src/app/feature/new-cmp +# but if you were to run +ng g component ./newer-cmp +# your component will be generated in src/app/newer-cmp +# if in the directory src/app you can also run +ng g component feature/new-cmp +# and your component will be generated in src/app/feature/new-cmp +``` +You can find all possible blueprints in the table below: + +Scaffold | Usage +--- | --- +[Component](https://github.com/angular/angular-cli/wiki/generate-component) | `ng g component my-new-component` +[Directive](https://github.com/angular/angular-cli/wiki/generate-directive) | `ng g directive my-new-directive` +[Pipe](https://github.com/angular/angular-cli/wiki/generate-pipe) | `ng g pipe my-new-pipe` +[Service](https://github.com/angular/angular-cli/wiki/generate-service) | `ng g service my-new-service` +[Class](https://github.com/angular/angular-cli/wiki/generate-class) | `ng g class my-new-class` +[Guard](https://github.com/angular/angular-cli/wiki/generate-guard) | `ng g guard my-new-guard` +[Interface](https://github.com/angular/angular-cli/wiki/generate-interface) | `ng g interface my-new-interface` +[Enum](https://github.com/angular/angular-cli/wiki/generate-enum) | `ng g enum my-new-enum` +[Module](https://github.com/angular/angular-cli/wiki/generate-module) | `ng g module my-module` + + + + +angular-cli will add reference to `components`, `directives` and `pipes` automatically in the `app.module.ts`. If you need to add this references to another custom module, follow these steps: + + 1. `ng g module new-module` to create a new module + 2. call `ng g component new-module/new-component` + +This should add the new `component`, `directive` or `pipe` reference to the `new-module` you've created. + +### Updating Angular CLI + +If you're using Angular CLI `1.0.0-beta.28` or less, you need to uninstall `angular-cli` package. It should be done due to changing of package's name and scope from `angular-cli` to `@angular/cli`: +```bash +npm uninstall -g angular-cli +npm uninstall --save-dev angular-cli +``` + +To update Angular CLI to a new version, you must update both the global package and your project's local package. + +Global package: +```bash +npm uninstall -g @angular/cli +npm cache verify +# if npm version is < 5 then use `npm cache clean` +npm install -g @angular/cli@latest +``` + +Local project package: +```bash +rm -rf node_modules dist # use rmdir /S/Q node_modules dist in Windows Command Prompt; use rm -r -fo node_modules,dist in Windows PowerShell +npm install --save-dev @angular/cli@latest +npm install +``` + +If you are updating to 1.0 from a beta or RC version, check out our [1.0 Update Guide](https://github.com/angular/angular-cli/wiki/stories-1.0-update). + +You can find more details about changes between versions in [the Releases tab on GitHub](https://github.com/angular/angular-cli/releases). + + +## Development Hints for working on Angular CLI + +### Working with master + +```bash +git clone https://github.com/angular/angular-cli.git +npm install +npm run build +cd dist/@angular/cli +npm link +``` + +`npm link` is very similar to `npm install -g` except that instead of downloading the package +from the repo, the just built `dist/@angular/cli/` folder becomes the global package. +Additionally, this repository publishes several packages and we use special logic to load all of them +on development setups. + +Any changes to the files in the `angular-cli/` folder will immediately affect the global `@angular/cli` package, +meaning that, in order to quickly test any changes you make to the cli project, you should simply just run `npm run build` +again. + +Now you can use `@angular/cli` via the command line: + +```bash +ng new foo +cd foo +npm link @angular/cli +ng serve +``` + +`npm link @angular/cli` is needed because by default the globally installed `@angular/cli` just loads +the local `@angular/cli` from the project which was fetched remotely from npm. +`npm link @angular/cli` symlinks the global `@angular/cli` package to the local `@angular/cli` package. +Now the `angular-cli` you cloned before is in three places: +The folder you cloned it into, npm's folder where it stores global packages and the Angular CLI project you just created. + +You can also use `ng new foo --link-cli` to automatically link the `@angular/cli` package. + +Please read the official [npm-link documentation](https://docs.npmjs.com/cli/link) +and the [npm-link cheatsheet](http://browsenpm.org/help#linkinganynpmpackagelocally) for more information. + +To run the Angular CLI E2E test suite, use the `node ./tests/legacy-cli/run_e2e` command. +It can also receive a filename to only run that test (e.g. `node ./tests/legacy-cli/run_e2e tests/legacy-cli/e2e/tests/build/dev-build.ts`). + +As part of the test procedure, all packages will be built and linked. +You will need to re-run `npm link` to re-link the development Angular CLI environment after tests finish. + +### Debugging with VS Code + +In order to debug some Angular CLI behaviour using Visual Studio Code, you can run `npm run build`, and then use a launch configuration like the following: + +```json +{ + "type": "node", + "request": "launch", + "name": "ng serve", + "cwd": "", + "program": "${workspaceFolder}/dist/@angular/cli/bin/ng", + "args": [ + "", + ...other arguments + ], + "console": "integratedTerminal" +} +``` + +Then you can add breakpoints in `dist/@angular` files. + +For more informations about Node.js debugging in VS Code, see the related [VS Code Documentation](https://code.visualstudio.com/docs/nodejs/nodejs-debugging). + +### CPU Profiling + +In order to investigate performance issues, CPU profiling is often usefull. + +To capture a CPU profiling, you can: +1. install the v8-profiler-node8 dependency: `npm install v8-profiler-node8 --no-save` +1. set the NG_CLI_PROFILING Environment variable to the file name you want: + * on Unix systems (Linux & Mac OS X): ̀`export NG_CLI_PROFILING=my-profile` + * on Windows: ̀̀`setx NG_CLI_PROFILING my-profile` + +Then, just run the ng command on which you want to capture a CPU profile. +You will then obtain a `my-profile.cpuprofile` file in the folder from wich you ran the ng command. + +You can use the Chrome Devtools to process it. To do so: +1. open `chrome://inspect/#devices` in Chrome +1. click on "Open dedicated DevTools for Node" +1. go to the "profiler" tab +1. click on the "Load" button and select the generated .cpuprofile file +1. on the left panel, select the associated file + +In addition to this one, another, more elaborated way to capture a CPU profile using the Chrome Devtools is detailed in https://github.com/angular/angular-cli/issues/8259#issue-269908550. + +## Documentation + +The documentation for the Angular CLI is located in this repo's [wiki](https://github.com/angular/angular-cli/wiki). + +## License + +MIT + + +[travis-badge]: https://travis-ci.org/angular/angular-cli.svg?branch=master +[travis-badge-url]: https://travis-ci.org/angular/angular-cli +[david-badge]: https://david-dm.org/angular/angular-cli.svg +[david-badge-url]: https://david-dm.org/angular/angular-cli +[david-dev-badge]: https://david-dm.org/angular/angular-cli/dev-status.svg +[david-dev-badge-url]: https://david-dm.org/angular/angular-cli?type=dev +[npm-badge]: https://img.shields.io/npm/v/@angular/cli.svg +[npm-badge-url]: https://www.npmjs.com/package/@angular/cli + diff --git a/packages/angular/cli/bin/ng b/packages/angular/cli/bin/ng new file mode 100755 index 000000000000..7fb032affdcb --- /dev/null +++ b/packages/angular/cli/bin/ng @@ -0,0 +1,25 @@ +#!/usr/bin/env node +'use strict'; + +// Provide a title to the process in `ps`. +// Due to an obscure Mac bug, do not start this title with any symbol. +try { + process.title = 'ng ' + Array.from(process.argv).slice(2).join(' '); +} catch(_) { + // If an error happened above, use the most basic title. + process.title = 'ng'; +} + +// Some older versions of Node do not support let or const. +var version = process.version.substr(1).split('.'); +if (Number(version[0]) < 8 || (Number(version[0]) === 8 && Number(version[1]) < 9)) { + process.stderr.write( + 'You are running version ' + process.version + ' of Node.js, which is not supported by Angular CLI v6.\n' + + 'The official Node.js version that is supported is 8.9 and greater.\n\n' + + 'Please visit https://nodejs.org/en/ to find instructions on how to update Node.js.\n' + ); + + process.exit(3); +} + +require('../lib/init'); diff --git a/packages/angular/cli/bin/ng-update-message.js b/packages/angular/cli/bin/ng-update-message.js new file mode 100755 index 000000000000..81e161911116 --- /dev/null +++ b/packages/angular/cli/bin/ng-update-message.js @@ -0,0 +1,44 @@ +#!/usr/bin/env node +'use strict'; + +// Check if the current directory contains '.angular-cli.json'. If it does, show a message to the user that they +// should use the migration script. + +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + + +let found = false; +let current = path.dirname(path.dirname(__dirname)); +while (current !== path.dirname(current)) { + if (fs.existsSync(path.join(current, 'angular-cli.json')) + || fs.existsSync(path.join(current, '.angular-cli.json'))) { + found = os.homedir() !== current || fs.existsSync(path.join(current, 'package.json')); + break; + } + if (fs.existsSync(path.join(current, 'angular.json')) + || fs.existsSync(path.join(current, '.angular.json')) + || fs.existsSync(path.join(current, 'package.json'))) { + break; + } + + current = path.dirname(current); +} + + +if (found) { + // ------------------------------------------------------------------------------------------ + // If changing this message, please update the same message in + // `packages/@angular/cli/models/command-runner.ts` + + // eslint-disable-next-line no-console + console.error(`\u001b[31m + ${'='.repeat(80)} + The Angular CLI configuration format has been changed, and your existing configuration can + be updated automatically by running the following command: + + ng update @angular/cli + ${'='.repeat(80)} + \u001b[39m`.replace(/^ {4}/gm, '')); +} diff --git a/packages/angular/cli/commands.json b/packages/angular/cli/commands.json new file mode 100644 index 000000000000..be69ff2dbe62 --- /dev/null +++ b/packages/angular/cli/commands.json @@ -0,0 +1,21 @@ +{ + "add": "./commands/add.json", + "build": "./commands/build.json", + "config": "./commands/config.json", + "doc": "./commands/doc.json", + "e2e": "./commands/e2e.json", + "make-this-awesome": "./commands/easter-egg.json", + "eject": "./commands/eject.json", + "generate": "./commands/generate.json", + "get": "./commands/deprecated.json", + "set": "./commands/deprecated.json", + "help": "./commands/help.json", + "lint": "./commands/lint.json", + "new": "./commands/new.json", + "run": "./commands/run.json", + "serve": "./commands/serve.json", + "test": "./commands/test.json", + "update": "./commands/update.json", + "version": "./commands/version.json", + "xi18n": "./commands/xi18n.json" +} diff --git a/packages/angular/cli/commands/add-impl.ts b/packages/angular/cli/commands/add-impl.ts new file mode 100644 index 000000000000..fe0ee5bbd1c6 --- /dev/null +++ b/packages/angular/cli/commands/add-impl.ts @@ -0,0 +1,80 @@ +/** + * @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 + */ + +// tslint:disable:no-global-tslint-disable no-any +import { tags, terminal } from '@angular-devkit/core'; +import { NodePackageDoesNotSupportSchematics } from '@angular-devkit/schematics/tools'; +import { Arguments } from '../models/interface'; +import { SchematicCommand } from '../models/schematic-command'; +import { NpmInstall } from '../tasks/npm-install'; +import { getPackageManager } from '../utilities/config'; +import { Schema as AddCommandSchema } from './add'; + +export class AddCommand extends SchematicCommand { + readonly allowPrivateSchematics = true; + + async run(options: AddCommandSchema & Arguments) { + if (!options.collection) { + this.logger.fatal( + `The "ng add" command requires a name argument to be specified eg. ` + + `${terminal.yellow('ng add [name] ')}. For more details, use "ng help".`, + ); + + return 1; + } + + const packageManager = getPackageManager(); + + const npmInstall: NpmInstall = require('../tasks/npm-install').default; + + const packageName = options.collection.startsWith('@') + ? options.collection.split('/', 2).join('/') + : options.collection.split('/', 1)[0]; + + // Remove the tag/version from the package name. + const collectionName = ( + packageName.startsWith('@') + ? packageName.split('@', 2).join('@') + : packageName.split('@', 1).join('@') + ) + options.collection.slice(packageName.length); + + // We don't actually add the package to package.json, that would be the work of the package + // itself. + await npmInstall( + packageName, + this.logger, + packageManager, + this.workspace.root, + ); + + const runOptions = { + schematicOptions: options['--'] || [], + workingDir: this.workspace.root, + collectionName, + schematicName: 'ng-add', + allowPrivate: true, + dryRun: false, + force: false, + }; + + try { + return await this.runSchematic(runOptions); + } catch (e) { + if (e instanceof NodePackageDoesNotSupportSchematics) { + this.logger.error(tags.oneLine` + The package that you are trying to add does not support schematics. You can try using + a different version of the package or contact the package author to add ng-add support. + `); + + return 1; + } + + throw e; + } + } +} diff --git a/packages/angular/cli/commands/add.json b/packages/angular/cli/commands/add.json new file mode 100644 index 000000000000..b2cb5b9eb06d --- /dev/null +++ b/packages/angular/cli/commands/add.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/add.json", + "description": "Add support for a library to your project.", + "$longDescription": "./add.md", + + "$scope": "in", + "$impl": "./add-impl#AddCommand", + + "type": "object", + "allOf": [ + { + "properties": { + "collection": { + "type": "string", + "description": "The package to be added.", + "$default": { + "$source": "argv", + "index": 0 + } + } + }, + "required": [ + ] + }, + { + "$ref": "./definitions.json#/definitions/schematic" + }, + { + "$ref": "./definitions.json#/definitions/base" + } + ] +} diff --git a/packages/angular/cli/commands/add.md b/packages/angular/cli/commands/add.md new file mode 100644 index 000000000000..c120a4b9d98d --- /dev/null +++ b/packages/angular/cli/commands/add.md @@ -0,0 +1,2 @@ +Add support for a library in your project, for example adding `@angular/pwa` which would configure +your project for PWA support. diff --git a/packages/angular/cli/commands/build-impl.ts b/packages/angular/cli/commands/build-impl.ts new file mode 100644 index 000000000000..39154941098b --- /dev/null +++ b/packages/angular/cli/commands/build-impl.ts @@ -0,0 +1,24 @@ +/** + * @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 { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Version } from '../upgrade/version'; +import { Schema as BuildCommandSchema } from './build'; + +export class BuildCommand extends ArchitectCommand { + public readonly target = 'build'; + + public async run(options: ArchitectCommandOptions & Arguments) { + // Check Angular and TypeScript versions. + Version.assertCompatibleAngularVersion(this.workspace.root); + Version.assertTypescriptVersion(this.workspace.root); + + return this.runArchitectTarget(options); + } +} diff --git a/packages/angular/cli/commands/build-long.md b/packages/angular/cli/commands/build-long.md new file mode 100644 index 000000000000..1116fcb1dc4e --- /dev/null +++ b/packages/angular/cli/commands/build-long.md @@ -0,0 +1,5 @@ +Resources in CSS, such as images and fonts, are automatically written and fingerprinted at the root +of the output folder. If a resource is less than 10kb, it is also included inline. + +Uses the Webpack build tool, with environment and build options specified in the CLI configuration +file. diff --git a/packages/angular/cli/commands/build.json b/packages/angular/cli/commands/build.json new file mode 100644 index 000000000000..043b370a998c --- /dev/null +++ b/packages/angular/cli/commands/build.json @@ -0,0 +1,16 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/build.json", + "description": "Compiles an Angular app into an output directory named dist/ at the given output path. Must be executed from within a workspace directory.", + "$longDescription": "./build-long.md", + + "$aliases": [ "b" ], + "$scope": "in", + "$type": "architect", + "$impl": "./build-impl#BuildCommand", + + "allOf": [ + { "$ref": "./definitions.json#/definitions/architect" }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/config-impl.ts b/packages/angular/cli/commands/config-impl.ts new file mode 100644 index 000000000000..b6ad2d52e0d5 --- /dev/null +++ b/packages/angular/cli/commands/config-impl.ts @@ -0,0 +1,277 @@ +/** + * @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 { + InvalidJsonCharacterException, + JsonArray, + JsonObject, + JsonParseMode, + JsonValue, + experimental, + parseJson, + tags, +} from '@angular-devkit/core'; +import { writeFileSync } from 'fs'; +import { Command } from '../models/command'; +import { Arguments, CommandScope } from '../models/interface'; +import { + getWorkspace, + getWorkspaceRaw, + migrateLegacyGlobalConfig, + validateWorkspace, +} from '../utilities/config'; +import { Schema as ConfigCommandSchema, Value as ConfigCommandSchemaValue } from './config'; + + +const validCliPaths = new Map([ + ['cli.warnings.versionMismatch', 'boolean'], + ['cli.warnings.typescriptMismatch', 'boolean'], + ['cli.defaultCollection', 'string'], + ['cli.packageManager', 'string'], +]); + +/** + * Splits a JSON path string into fragments. Fragments can be used to get the value referenced + * by the path. For example, a path of "a[3].foo.bar[2]" would give you a fragment array of + * ["a", 3, "foo", "bar", 2]. + * @param path The JSON string to parse. + * @returns {string[]} The fragments for the string. + * @private + */ +function parseJsonPath(path: string): string[] { + const fragments = (path || '').split(/\./g); + const result: string[] = []; + + while (fragments.length > 0) { + const fragment = fragments.shift(); + if (fragment == undefined) { + break; + } + + const match = fragment.match(/([^\[]+)((\[.*\])*)/); + if (!match) { + throw new Error('Invalid JSON path.'); + } + + result.push(match[1]); + if (match[2]) { + const indices = match[2].slice(1, -1).split(']['); + result.push(...indices); + } + } + + return result.filter(fragment => !!fragment); +} + +function getValueFromPath( + root: T, + path: string, +): JsonValue | undefined { + const fragments = parseJsonPath(path); + + try { + return fragments.reduce((value: JsonValue, current: string | number) => { + if (value == undefined || typeof value != 'object') { + return undefined; + } else if (typeof current == 'string' && !Array.isArray(value)) { + return value[current]; + } else if (typeof current == 'number' && Array.isArray(value)) { + return value[current]; + } else { + return undefined; + } + }, root); + } catch { + return undefined; + } +} + +function setValueFromPath( + root: T, + path: string, + newValue: JsonValue, +): JsonValue | undefined { + const fragments = parseJsonPath(path); + + try { + return fragments.reduce((value: JsonValue, current: string | number, index: number) => { + if (value == undefined || typeof value != 'object') { + return undefined; + } else if (typeof current == 'string' && !Array.isArray(value)) { + if (index === fragments.length - 1) { + value[current] = newValue; + } else if (value[current] == undefined) { + if (typeof fragments[index + 1] == 'number') { + value[current] = []; + } else if (typeof fragments[index + 1] == 'string') { + value[current] = {}; + } + } + + return value[current]; + } else if (typeof current == 'number' && Array.isArray(value)) { + if (index === fragments.length - 1) { + value[current] = newValue; + } else if (value[current] == undefined) { + if (typeof fragments[index + 1] == 'number') { + value[current] = []; + } else if (typeof fragments[index + 1] == 'string') { + value[current] = {}; + } + } + + return value[current]; + } else { + return undefined; + } + }, root); + } catch { + return undefined; + } +} + +function normalizeValue(value: ConfigCommandSchemaValue, path: string): JsonValue { + const cliOptionType = validCliPaths.get(path); + if (cliOptionType) { + switch (cliOptionType) { + case 'boolean': + if (('' + value).trim() === 'true') { + return true; + } else if (('' + value).trim() === 'false') { + return false; + } + break; + case 'number': + const numberValue = Number(value); + if (!Number.isFinite(numberValue)) { + return numberValue; + } + break; + case 'string': + return value; + } + + throw new Error(`Invalid value type; expected a ${cliOptionType}.`); + } + + if (typeof value === 'string') { + try { + return parseJson(value, JsonParseMode.Loose); + } catch (e) { + if (e instanceof InvalidJsonCharacterException && !value.startsWith('{')) { + return value; + } else { + throw e; + } + } + } + + return value; +} + +export class ConfigCommand extends Command { + public async run(options: ConfigCommandSchema & Arguments) { + const level = options.global ? 'global' : 'local'; + + if (!options.global) { + await this.validateScope(CommandScope.InProject); + } + + let config = + (getWorkspace(level) as {} as { _workspace: experimental.workspace.WorkspaceSchema }); + + if (options.global && !config) { + try { + if (migrateLegacyGlobalConfig()) { + config = + (getWorkspace(level) as {} as { _workspace: experimental.workspace.WorkspaceSchema }); + this.logger.info(tags.oneLine` + We found a global configuration that was used in Angular CLI 1. + It has been automatically migrated.`); + } + } catch {} + } + + if (options.value == undefined) { + if (!config) { + this.logger.error('No config found.'); + + return 1; + } + + return this.get(config._workspace, options); + } else { + return this.set(options); + } + } + + private get(config: experimental.workspace.WorkspaceSchema, options: ConfigCommandSchema) { + let value; + if (options.jsonPath) { + value = getValueFromPath(config as {} as JsonObject, options.jsonPath); + } else { + value = config; + } + + if (value === undefined) { + this.logger.error('Value cannot be found.'); + + return 1; + } else if (typeof value == 'object') { + this.logger.info(JSON.stringify(value, null, 2)); + } else { + this.logger.info(value.toString()); + } + + return 0; + } + + private set(options: ConfigCommandSchema) { + if (!options.jsonPath || !options.jsonPath.trim()) { + throw new Error('Invalid Path.'); + } + if (options.global + && !options.jsonPath.startsWith('schematics.') + && !validCliPaths.has(options.jsonPath)) { + throw new Error('Invalid Path.'); + } + + const [config, configPath] = getWorkspaceRaw(options.global ? 'global' : 'local'); + if (!config || !configPath) { + this.logger.error('Confguration file cannot be found.'); + + return 1; + } + + // TODO: Modify & save without destroying comments + const configValue = config.value; + + const value = normalizeValue(options.value || '', options.jsonPath); + const result = setValueFromPath(configValue, options.jsonPath, value); + + if (result === undefined) { + this.logger.error('Value cannot be found.'); + + return 1; + } + + try { + validateWorkspace(configValue); + } catch (error) { + this.logger.fatal(error.message); + + return 1; + } + + const output = JSON.stringify(configValue, null, 2); + writeFileSync(configPath, output); + + return 0; + } + +} diff --git a/packages/angular/cli/commands/config.json b/packages/angular/cli/commands/config.json new file mode 100644 index 000000000000..899d563a2be4 --- /dev/null +++ b/packages/angular/cli/commands/config.json @@ -0,0 +1,44 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/config.json", + "description": "Get/set configuration values.", + "$longDescription": "", + + "$aliases": [], + "$scope": "all", + "$type": "native", + "$impl": "./config-impl#ConfigCommand", + + "type": "object", + "allOf": [ + { + "properties": { + "jsonPath": { + "type": "string", + "description": "The path to the value to get/set.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "value": { + "type": ["string", "number", "boolean"], + "description": "The new value to be set.", + "$default": { + "$source": "argv", + "index": 1 + } + }, + "global": { + "type": "boolean", + "description": "Get/set the value in the global configuration (in your home directory).", + "default": false, + "aliases": ["g"] + } + }, + "required": [ + ] + }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/definitions.json b/packages/angular/cli/commands/definitions.json new file mode 100644 index 000000000000..20099aaa748e --- /dev/null +++ b/packages/angular/cli/commands/definitions.json @@ -0,0 +1,66 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/definitions.json", + + "definitions": { + "architect": { + "properties": { + "project": { + "type": "string", + "description": "The name of the project to build. Can be an app or a library.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "configuration": { + "description": "A named configuration environment, as specified in the `configurations` section of `angular.json`.", + "type": "string", + "aliases": [ + "c" + ] + }, + "prod": { + "description": "When true, sets the build configuration to the production environment.\nAll builds make use of bundling and limited tree-shaking, A production build also runs limited dead code elimination using UglifyJS.", + "type": "boolean" + } + } + }, + "base": { + "type": "object", + "properties": { + "help": { + "enum": [true, false, "json", "JSON"], + "description": "Shows a help message. You can pass the format as a value.", + "default": false + } + } + }, + "schematic": { + "properties": { + "dryRun": { + "type": "boolean", + "default": false, + "aliases": [ "d" ], + "description": "Run through without making any changes." + }, + "force": { + "type": "boolean", + "default": false, + "aliases": [ "f" ], + "description": "Forces overwriting of files." + }, + "interactive": { + "type": "boolean", + "default": "true", + "description": "Disables interactive inputs (i.e., prompts)." + }, + "defaults": { + "type": "boolean", + "default": "false", + "description": "Disables interactive inputs (i.e., prompts) for options with a default." + } + } + } + } +} diff --git a/packages/angular/cli/commands/deprecated-impl.ts b/packages/angular/cli/commands/deprecated-impl.ts new file mode 100644 index 000000000000..7887eac8d04d --- /dev/null +++ b/packages/angular/cli/commands/deprecated-impl.ts @@ -0,0 +1,22 @@ +/** + * @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 { Command } from '../models/command'; +import { Schema as DeprecatedCommandSchema } from './deprecated'; + +export class DeprecatedCommand extends Command { + public async run() { + let message = 'The "${this.description.name}" command has been deprecated.'; + if (this.description.name == 'get' || this.description.name == 'set') { + message = 'get/set have been deprecated in favor of the config command.'; + } + + this.logger.error(message); + + return 0; + } +} diff --git a/packages/angular/cli/commands/deprecated.json b/packages/angular/cli/commands/deprecated.json new file mode 100644 index 000000000000..05dd86855d95 --- /dev/null +++ b/packages/angular/cli/commands/deprecated.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/deprecated.json", + "description": "Deprecated in favor of config command.", + "$longDescription": "", + + "$impl": "./deprecated-impl#DeprecatedCommand", + "$hidden": true, + "$type": "deprecated", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/doc-impl.ts b/packages/angular/cli/commands/doc-impl.ts new file mode 100644 index 000000000000..6a0e7a265ecf --- /dev/null +++ b/packages/angular/cli/commands/doc-impl.ts @@ -0,0 +1,26 @@ +/** + * @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 { Command } from '../models/command'; +import { Arguments } from '../models/interface'; +import { Schema as DocCommandSchema } from './doc'; + +const opn = require('opn'); + +export class DocCommand extends Command { + public async run(options: DocCommandSchema & Arguments) { + let searchUrl = `https://angular.io/api?query=${options.keyword}`; + if (options.search) { + searchUrl = `https://www.google.com/search?q=site%3Aangular.io+${options.keyword}`; + } + + return opn(searchUrl, { + wait: false, + }); + } +} diff --git a/packages/angular/cli/commands/doc.json b/packages/angular/cli/commands/doc.json new file mode 100644 index 000000000000..cabe8f10209d --- /dev/null +++ b/packages/angular/cli/commands/doc.json @@ -0,0 +1,35 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/doc.json", + "description": "Opens the official Angular API documentation for a given keyword.", + "$longDescription": "", + + "$aliases": [ "d" ], + "$type": "native", + "$impl": "./doc-impl#DocCommand", + + "type": "object", + "allOf": [ + { + "properties": { + "keyword": { + "type": "string", + "description": "The query to search upon.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "search": { + "aliases": ["s"], + "type": "boolean", + "default": false, + "description": "Search whole angular.io instead of just api." + } + }, + "required": [ + ] + }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/e2e-impl.ts b/packages/angular/cli/commands/e2e-impl.ts new file mode 100644 index 000000000000..f24a44ca4122 --- /dev/null +++ b/packages/angular/cli/commands/e2e-impl.ts @@ -0,0 +1,21 @@ +/** + * @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 { ArchitectCommand } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Schema as E2eCommandSchema } from './e2e'; + + +export class E2eCommand extends ArchitectCommand { + public readonly target = 'e2e'; + public readonly multiTarget = true; + + public async run(options: E2eCommandSchema & Arguments) { + return this.runArchitectTarget(options); + } +} diff --git a/packages/angular/cli/commands/e2e.json b/packages/angular/cli/commands/e2e.json new file mode 100644 index 000000000000..6e7b1079a46a --- /dev/null +++ b/packages/angular/cli/commands/e2e.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/e2e.json", + "description": "Runs the end-to-end tests.", + "$longDescription": "", + + "$aliases": [ "e" ], + "$scope": "in", + "$type": "architect", + "$impl": "./e2e-impl#E2eCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/architect" }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/easter-egg-impl.ts b/packages/angular/cli/commands/easter-egg-impl.ts new file mode 100644 index 000000000000..e6cd9ee3eb45 --- /dev/null +++ b/packages/angular/cli/commands/easter-egg-impl.ts @@ -0,0 +1,31 @@ +/** + * @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 { terminal } from '@angular-devkit/core'; +import { Command } from '../models/command'; +import { Schema as AwesomeCommandSchema } from './easter-egg'; + +function pickOne(of: string[]): string { + return of[Math.floor(Math.random() * of.length)]; +} + +export class AwesomeCommand extends Command { + async run() { + const phrase = pickOne([ + `You're on it, there's nothing for me to do!`, + `Let's take a look... nope, it's all good!`, + `You're doing fine.`, + `You're already doing great.`, + `Nothing to do; already awesome. Exiting.`, + `Error 418: As Awesome As Can Get.`, + `I spy with my little eye a great developer!`, + `Noop... already awesome.`, + ]); + this.logger.info(terminal.green(phrase)); + } +} diff --git a/packages/angular/cli/commands/easter-egg.json b/packages/angular/cli/commands/easter-egg.json new file mode 100644 index 000000000000..d0a7e94189e9 --- /dev/null +++ b/packages/angular/cli/commands/easter-egg.json @@ -0,0 +1,14 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/easter-egg.json", + "description": "", + "$longDescription": "", + "$hidden": true, + + "$impl": "./easter-egg-impl#AwesomeCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/eject-impl.ts b/packages/angular/cli/commands/eject-impl.ts new file mode 100644 index 000000000000..47fe394cc0fc --- /dev/null +++ b/packages/angular/cli/commands/eject-impl.ts @@ -0,0 +1,26 @@ +/** + * @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 { tags } from '@angular-devkit/core'; +import { Command } from '../models/command'; +import { Schema as EjectCommandSchema } from './eject'; + +export class EjectCommand extends Command { + async run() { + this.logger.error(tags.stripIndents` + The 'eject' command has been temporarily disabled, as it is not yet compatible with the new + angular.json format. The new configuration format provides further flexibility to modify the + configuration of your workspace without ejecting. Ejection will be re-enabled in a future + release of the CLI. + + If you need to eject today, use CLI 1.7 to eject your project. + `); + + return 1; + } +} diff --git a/packages/angular/cli/commands/eject.json b/packages/angular/cli/commands/eject.json new file mode 100644 index 000000000000..d5c527d02166 --- /dev/null +++ b/packages/angular/cli/commands/eject.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/eject.json", + "description": "Temporarily disabled. Ejects your app and output the proper webpack configuration and scripts.", + "$longDescription": "", + + "$hidden": true, + "$scope": "in", + "$impl": "./eject-impl#EjectCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/generate-impl.ts b/packages/angular/cli/commands/generate-impl.ts new file mode 100644 index 000000000000..49d9f60056c4 --- /dev/null +++ b/packages/angular/cli/commands/generate-impl.ts @@ -0,0 +1,103 @@ +/** + * @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 + */ + +// tslint:disable:no-global-tslint-disable no-any +import { terminal } from '@angular-devkit/core'; +import { Arguments, SubCommandDescription } from '../models/interface'; +import { SchematicCommand } from '../models/schematic-command'; +import { parseJsonSchemaToSubCommandDescription } from '../utilities/json-schema'; +import { Schema as GenerateCommandSchema } from './generate'; + +export class GenerateCommand extends SchematicCommand { + async initialize(options: GenerateCommandSchema & Arguments) { + await super.initialize(options); + + // Fill up the schematics property of the command description. + const [collectionName, schematicName] = this.parseSchematicInfo(options); + + const collection = this.getCollection(collectionName); + const subcommands: { [name: string]: SubCommandDescription } = {}; + + const schematicNames = schematicName ? [schematicName] : collection.listSchematicNames(); + // Sort as a courtesy for the user. + schematicNames.sort(); + + for (const name of schematicNames) { + const schematic = this.getSchematic(collection, name, true); + let subcommand: SubCommandDescription; + if (schematic.description.schemaJson) { + subcommand = await parseJsonSchemaToSubCommandDescription( + name, + schematic.description.path, + this._workflow.registry, + schematic.description.schemaJson, + this.logger, + ); + } else { + continue; + } + + if (this.getDefaultSchematicCollection() == collectionName) { + subcommands[name] = subcommand; + } else { + subcommands[`${collectionName}:${name}`] = subcommand; + } + } + + this.description.options.forEach(option => { + if (option.name == 'schematic') { + option.subcommands = subcommands; + } + }); + } + + public async run(options: GenerateCommandSchema & Arguments) { + const [collectionName, schematicName] = this.parseSchematicInfo(options); + + if (!schematicName || !collectionName) { + return this.printHelp(options); + } + + return this.runSchematic({ + collectionName, + schematicName, + schematicOptions: options['--'] || [], + debug: !!options.debug || false, + dryRun: !!options.dryRun || false, + force: !!options.force || false, + }); + } + + private parseSchematicInfo(options: { schematic?: string }): [string, string | undefined] { + let collectionName = this.getDefaultSchematicCollection(); + + let schematicName = options.schematic; + + if (schematicName) { + if (schematicName.includes(':')) { + [collectionName, schematicName] = schematicName.split(':', 2); + } + } + + return [collectionName, schematicName]; + } + + public async printHelp(options: GenerateCommandSchema & Arguments) { + await super.printHelp(options); + + this.logger.info(''); + // Find the generate subcommand. + const subcommand = this.description.options.filter(x => x.subcommands)[0]; + if (Object.keys((subcommand && subcommand.subcommands) || {}).length == 1) { + this.logger.info(`\nTo see help for a schematic run:`); + this.logger.info(terminal.cyan(` ng generate --help`)); + } + + return 0; + } +} diff --git a/packages/angular/cli/commands/generate.json b/packages/angular/cli/commands/generate.json new file mode 100644 index 000000000000..f8668058cc9f --- /dev/null +++ b/packages/angular/cli/commands/generate.json @@ -0,0 +1,31 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/generate.json", + "description": "Generates and/or modifies files based on a schematic.", + "$longDescription": "", + + "$aliases": [ "g" ], + "$scope": "in", + "$type": "schematics", + "$impl": "./generate-impl#GenerateCommand", + + "allOf": [ + { + "type": "object", + "properties": { + "schematic": { + "type": "string", + "description": "The schematic or collection:schematic to generate.", + "$default": { + "$source": "argv", + "index": 0 + } + } + }, + "required": [ + ] + }, + { "$ref": "./definitions.json#/definitions/base" }, + { "$ref": "./definitions.json#/definitions/schematic" } + ] +} diff --git a/packages/angular/cli/commands/help-impl.ts b/packages/angular/cli/commands/help-impl.ts new file mode 100644 index 000000000000..7bab545922e4 --- /dev/null +++ b/packages/angular/cli/commands/help-impl.ts @@ -0,0 +1,28 @@ +/** + * @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 { terminal } from '@angular-devkit/core'; +import { Command } from '../models/command'; +import { Schema as HelpCommandSchema } from './help'; + +export class HelpCommand extends Command { + async run() { + this.logger.info(`Available Commands:`); + + for (const name of Object.keys(Command.commandMap)) { + const cmd = Command.commandMap[name]; + + if (cmd.hidden) { + continue; + } + + const aliasInfo = cmd.aliases.length > 0 ? ` (${cmd.aliases.join(', ')})` : ''; + this.logger.info(` ${terminal.cyan(cmd.name)}${aliasInfo} ${cmd.description}`); + } + this.logger.info(`\nFor more detailed help run "ng [command name] --help"`); + } +} diff --git a/packages/angular/cli/commands/help.json b/packages/angular/cli/commands/help.json new file mode 100644 index 000000000000..e7aeda0ba9e4 --- /dev/null +++ b/packages/angular/cli/commands/help.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/help.json", + "description": "Displays help for the Angular CLI.", + "$longDescription": "", + + "$scope": "all", + "$aliases": [], + "$impl": "./help-impl#HelpCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/lint-impl.ts b/packages/angular/cli/commands/lint-impl.ts new file mode 100644 index 000000000000..a67a8563d951 --- /dev/null +++ b/packages/angular/cli/commands/lint-impl.ts @@ -0,0 +1,26 @@ +/** + * @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 { TargetSpecifier } from '@angular-devkit/architect'; +import { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Schema as LintCommandSchema } from './lint'; + +export class LintCommand extends ArchitectCommand { + public readonly target = 'lint'; + public readonly multiTarget = true; + + protected async runSingleTarget(targetSpec: TargetSpecifier, options: string[]) { + this.logger.info(`Linting ${JSON.stringify(targetSpec.project)}...`); + + return super.runSingleTarget(targetSpec, options); + } + + public async run(options: ArchitectCommandOptions & Arguments) { + return this.runArchitectTarget(options); + } +} diff --git a/packages/angular/cli/commands/lint.json b/packages/angular/cli/commands/lint.json new file mode 100644 index 000000000000..7d007122c28a --- /dev/null +++ b/packages/angular/cli/commands/lint.json @@ -0,0 +1,39 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/lint.json", + "description": "Lints code in existing project.", + "$longDescription": "", + + "$aliases": [ "l" ], + "$scope": "in", + "$type": "architect", + "$impl": "./lint-impl#LintCommand", + + "type": "object", + "allOf": [ + { + "properties": { + "project": { + "type": "string", + "description": "The name of the project to lint.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "configuration": { + "description": "Specify the configuration to use.", + "type": "string", + "aliases": [ + "c" + ] + } + }, + "required": [ + ] + }, + { + "$ref": "./definitions.json#/definitions/base" + } + ] +} diff --git a/packages/angular/cli/commands/new-impl.ts b/packages/angular/cli/commands/new-impl.ts new file mode 100644 index 000000000000..10f5d6cee1d6 --- /dev/null +++ b/packages/angular/cli/commands/new-impl.ts @@ -0,0 +1,46 @@ +/** + * @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 + */ + +// tslint:disable:no-global-tslint-disable no-any +import { Arguments } from '../models/interface'; +import { SchematicCommand } from '../models/schematic-command'; +import { Schema as NewCommandSchema } from './new'; + + +export class NewCommand extends SchematicCommand { + public readonly allowMissingWorkspace = true; + schematicName = 'ng-new'; + + public async run(options: NewCommandSchema & Arguments) { + let collectionName: string; + if (options.collection) { + collectionName = options.collection; + } else { + collectionName = this.parseCollectionName(options); + } + + // Register the version of the CLI in the registry. + const packageJson = require('../package.json'); + const version = packageJson.version; + + this._workflow.registry.addSmartDefaultProvider('ng-cli-version', () => version); + + return this.runSchematic({ + collectionName: collectionName, + schematicName: this.schematicName, + schematicOptions: options['--'] || [], + debug: !!options.debug, + dryRun: !!options.dryRun, + force: !!options.force, + }); + } + + private parseCollectionName(options: any): string { + return options.collection || this.getDefaultSchematicCollection(); + } +} diff --git a/packages/angular/cli/commands/new.json b/packages/angular/cli/commands/new.json new file mode 100644 index 000000000000..ed301b03a217 --- /dev/null +++ b/packages/angular/cli/commands/new.json @@ -0,0 +1,33 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/new.json", + "description": "Creates a new directory and a new Angular app.", + "$longDescription": "", + + "$aliases": [ "n" ], + "$scope": "out", + "$type": "schematic", + "$impl": "./new-impl#NewCommand", + + "type": "object", + "allOf": [ + { + "properties": { + "collection": { + "type": "string", + "aliases": [ "c" ], + "description": "Schematics collection to use." + }, + "verbose": { + "type": "boolean", + "default": false, + "aliases": [ "v" ], + "description": "Adds more details to output logging." + } + }, + "required": [] + }, + { "$ref": "./definitions.json#/definitions/base" }, + { "$ref": "./definitions.json#/definitions/schematic" } + ] +} diff --git a/packages/angular/cli/commands/run-impl.ts b/packages/angular/cli/commands/run-impl.ts new file mode 100644 index 000000000000..feefe731fa5b --- /dev/null +++ b/packages/angular/cli/commands/run-impl.ts @@ -0,0 +1,21 @@ +/** + * @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 { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Schema as RunCommandSchema } from './run'; + +export class RunCommand extends ArchitectCommand { + public async run(options: ArchitectCommandOptions & Arguments) { + if (options.target) { + return this.runArchitectTarget(options); + } else { + throw new Error('Invalid architect target.'); + } + } +} diff --git a/packages/angular/cli/commands/run.json b/packages/angular/cli/commands/run.json new file mode 100644 index 000000000000..51b74bbacf55 --- /dev/null +++ b/packages/angular/cli/commands/run.json @@ -0,0 +1,37 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/run.json", + "description": "Runs Architect targets.", + "$longDescription": "", + + "$aliases": [], + "$scope": "in", + "$type": "architect", + "$impl": "./run-impl#RunCommand", + + "type": "object", + "allOf": [ + { + "properties": { + "target": { + "type": "string", + "description": "The target to run.", + "$default": { + "$source": "argv", + "index": 0 + } + }, + "configuration": { + "description": "Specify the configuration to use.", + "type": "string", + "aliases": [ "c" ] + } + }, + "required": [ + ] + }, + { + "$ref": "./definitions.json#/definitions/base" + } + ] +} diff --git a/packages/angular/cli/commands/serve-impl.ts b/packages/angular/cli/commands/serve-impl.ts new file mode 100644 index 000000000000..ba365974e310 --- /dev/null +++ b/packages/angular/cli/commands/serve-impl.ts @@ -0,0 +1,28 @@ +/** + * @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 { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Version } from '../upgrade/version'; +import { Schema as ServeCommandSchema } from './serve'; + +export class ServeCommand extends ArchitectCommand { + public readonly target = 'serve'; + + public validate(_options: ArchitectCommandOptions & Arguments) { + // Check Angular and TypeScript versions. + Version.assertCompatibleAngularVersion(this.workspace.root); + Version.assertTypescriptVersion(this.workspace.root); + + return true; + } + + public async run(options: ArchitectCommandOptions & Arguments) { + return this.runArchitectTarget(options); + } +} diff --git a/packages/angular/cli/commands/serve.json b/packages/angular/cli/commands/serve.json new file mode 100644 index 000000000000..9b01a5039cb5 --- /dev/null +++ b/packages/angular/cli/commands/serve.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/serve.json", + "description": "Builds and serves your app, rebuilding on file changes.", + "$longDescription": "", + + "$aliases": [ "s" ], + "$scope": "in", + "$type": "architect", + "$impl": "./serve-impl#ServeCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/architect" }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/test-impl.ts b/packages/angular/cli/commands/test-impl.ts new file mode 100644 index 000000000000..28f09df4d7b2 --- /dev/null +++ b/packages/angular/cli/commands/test-impl.ts @@ -0,0 +1,20 @@ +/** + * @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 { ArchitectCommand, ArchitectCommandOptions } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Schema as TestCommandSchema } from './test'; + +export class TestCommand extends ArchitectCommand { + public readonly target = 'test'; + public readonly multiTarget = true; + + public async run(options: ArchitectCommandOptions & Arguments) { + return this.runArchitectTarget(options); + } +} diff --git a/packages/angular/cli/commands/test.json b/packages/angular/cli/commands/test.json new file mode 100644 index 000000000000..79c5a0ef8c85 --- /dev/null +++ b/packages/angular/cli/commands/test.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/test.json", + "description": "Run unit tests in existing project.", + "$longDescription": "", + + "$aliases": [ "t" ], + "$scope": "in", + "$type": "architect", + "$impl": "./test-impl#TestCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/architect" }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/update-impl.ts b/packages/angular/cli/commands/update-impl.ts new file mode 100644 index 000000000000..e5f575db4dfb --- /dev/null +++ b/packages/angular/cli/commands/update-impl.ts @@ -0,0 +1,62 @@ +/** + * @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 { normalize } from '@angular-devkit/core'; +import { Arguments, Option } from '../models/interface'; +import { SchematicCommand } from '../models/schematic-command'; +import { findUp } from '../utilities/find-up'; +import { Schema as UpdateCommandSchema } from './update'; + +export class UpdateCommand extends SchematicCommand { + public readonly allowMissingWorkspace = true; + + collectionName = '@schematics/update'; + schematicName = 'update'; + + async parseArguments(schematicOptions: string[], schema: Option[]): Promise { + const args = await super.parseArguments(schematicOptions, schema); + const maybeArgsLeftovers = args['--']; + + if (maybeArgsLeftovers + && maybeArgsLeftovers.length == 1 + && maybeArgsLeftovers[0] == '@angular/cli' + && args.migrateOnly === undefined + && args.from === undefined) { + // Check for a 1.7 angular-cli.json file. + const oldConfigFileNames = [ + normalize('.angular-cli.json'), + normalize('angular-cli.json'), + ]; + const oldConfigFilePath = findUp(oldConfigFileNames, process.cwd()) + || findUp(oldConfigFileNames, __dirname); + + if (oldConfigFilePath) { + args.migrateOnly = true; + args.from = '1.0.0'; + } + } + + // Move `--` to packages. + if (args.packages == undefined && args['--']) { + args.packages = args['--']; + delete args['--']; + } + + return args; + } + + async run(options: UpdateCommandSchema & Arguments) { + return this.runSchematic({ + collectionName: this.collectionName, + schematicName: this.schematicName, + schematicOptions: options['--'], + dryRun: !!options.dryRun, + force: false, + showNothingDone: false, + }); + } +} diff --git a/packages/angular/cli/commands/update.json b/packages/angular/cli/commands/update.json new file mode 100644 index 000000000000..3f6bdb900f21 --- /dev/null +++ b/packages/angular/cli/commands/update.json @@ -0,0 +1,18 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/update.json", + "description": "Updates your application and its dependencies.", + "$longDescription": "", + + "$scope": "all", + "$aliases": [], + "$type": "schematics", + "$impl": "./update-impl#UpdateCommand", + + "type": "object", + "allOf": [ + { + "$ref": "./definitions.json#/definitions/base" + } + ] +} diff --git a/packages/angular/cli/commands/version-impl.ts b/packages/angular/cli/commands/version-impl.ts new file mode 100644 index 000000000000..5f357396e25b --- /dev/null +++ b/packages/angular/cli/commands/version-impl.ts @@ -0,0 +1,179 @@ +/** + * @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 { terminal } from '@angular-devkit/core'; +import * as child_process from 'child_process'; +import * as fs from 'fs'; +import * as path from 'path'; +import { Command } from '../models/command'; +import { findUp } from '../utilities/find-up'; +import { Schema as VersionCommandSchema } from './version'; + +export class VersionCommand extends Command { + public static aliases = ['v']; + + async run() { + const pkg = require(path.resolve(__dirname, '..', 'package.json')); + let projPkg; + try { + projPkg = require(path.resolve(this.workspace.root, 'package.json')); + } catch (exception) { + projPkg = undefined; + } + + const patterns = [ + /^@angular\/.*/, + /^@angular-devkit\/.*/, + /^@ngtools\/.*/, + /^@schematics\/.*/, + /^rxjs$/, + /^typescript$/, + /^ng-packagr$/, + /^webpack$/, + ]; + + const maybeNodeModules = findUp('node_modules', __dirname); + const packageRoot = projPkg + ? path.resolve(this.workspace.root, 'node_modules') + : maybeNodeModules; + + const packageNames = [ + ...Object.keys(pkg && pkg['dependencies'] || {}), + ...Object.keys(pkg && pkg['devDependencies'] || {}), + ...Object.keys(projPkg && projPkg['dependencies'] || {}), + ...Object.keys(projPkg && projPkg['devDependencies'] || {}), + ]; + + if (packageRoot != null) { + // Add all node_modules and node_modules/@*/* + const nodePackageNames = fs.readdirSync(packageRoot) + .reduce((acc, name) => { + if (name.startsWith('@')) { + return acc.concat( + fs.readdirSync(path.resolve(packageRoot, name)) + .map(subName => name + '/' + subName), + ); + } else { + return acc.concat(name); + } + }, []); + + packageNames.push(...nodePackageNames); + } + + const versions = packageNames + .filter(x => patterns.some(p => p.test(x))) + .reduce((acc, name) => { + if (name in acc) { + return acc; + } + + acc[name] = this.getVersion(name, packageRoot, maybeNodeModules); + + return acc; + }, {} as { [module: string]: string }); + + let ngCliVersion = pkg.version; + if (!__dirname.match(/node_modules/)) { + let gitBranch = '??'; + try { + const gitRefName = '' + child_process.execSync('git symbolic-ref HEAD', {cwd: __dirname}); + gitBranch = path.basename(gitRefName.replace('\n', '')); + } catch { + } + + ngCliVersion = `local (v${pkg.version}, branch: ${gitBranch})`; + } + let angularCoreVersion = ''; + const angularSameAsCore: string[] = []; + + if (projPkg) { + // Filter all angular versions that are the same as core. + angularCoreVersion = versions['@angular/core']; + if (angularCoreVersion) { + for (const angularPackage of Object.keys(versions)) { + if (versions[angularPackage] == angularCoreVersion + && angularPackage.startsWith('@angular/')) { + angularSameAsCore.push(angularPackage.replace(/^@angular\//, '')); + delete versions[angularPackage]; + } + } + + // Make sure we list them in alphabetical order. + angularSameAsCore.sort(); + } + } + + const namePad = ' '.repeat( + Object.keys(versions).sort((a, b) => b.length - a.length)[0].length + 3, + ); + const asciiArt = ` + _ _ ____ _ ___ + / \\ _ __ __ _ _ _| | __ _ _ __ / ___| | |_ _| + / △ \\ | '_ \\ / _\` | | | | |/ _\` | '__| | | | | | | + / ___ \\| | | | (_| | |_| | | (_| | | | |___| |___ | | + /_/ \\_\\_| |_|\\__, |\\__,_|_|\\__,_|_| \\____|_____|___| + |___/ + `.split('\n').map(x => terminal.red(x)).join('\n'); + + this.logger.info(asciiArt); + this.logger.info(` + Angular CLI: ${ngCliVersion} + Node: ${process.versions.node} + OS: ${process.platform} ${process.arch} + Angular: ${angularCoreVersion} + ... ${angularSameAsCore.reduce((acc, name) => { + // Perform a simple word wrap around 60. + if (acc.length == 0) { + return [name]; + } + const line = (acc[acc.length - 1] + ', ' + name); + if (line.length > 60) { + acc.push(name); + } else { + acc[acc.length - 1] = line; + } + + return acc; + }, []).join('\n... ')} + + Package${namePad.slice(7)}Version + -------${namePad.replace(/ /g, '-')}------------------ + ${Object.keys(versions) + .map(module => `${module}${namePad.slice(module.length)}${versions[module]}`) + .sort() + .join('\n')} + `.replace(/^ {6}/gm, '')); + } + + private getVersion( + moduleName: string, + projectNodeModules: string | null, + cliNodeModules: string | null, + ): string { + try { + if (projectNodeModules) { + const modulePkg = require(path.resolve(projectNodeModules, moduleName, 'package.json')); + + return modulePkg.version; + } + } catch (_) { + } + + try { + if (cliNodeModules) { + const modulePkg = require(path.resolve(cliNodeModules, moduleName, 'package.json')); + + return modulePkg.version + ' (cli-only)'; + } + } catch { + } + + return ''; + } +} diff --git a/packages/angular/cli/commands/version.json b/packages/angular/cli/commands/version.json new file mode 100644 index 000000000000..795eb654b7a5 --- /dev/null +++ b/packages/angular/cli/commands/version.json @@ -0,0 +1,15 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/version.json", + "description": "Outputs Angular CLI version.", + "$longDescription": "", + + "$aliases": [ "v" ], + "$scope": "all", + "$impl": "./version-impl#VersionCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/commands/xi18n-impl.ts b/packages/angular/cli/commands/xi18n-impl.ts new file mode 100644 index 000000000000..59e191dd5259 --- /dev/null +++ b/packages/angular/cli/commands/xi18n-impl.ts @@ -0,0 +1,20 @@ +/** + * @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 { ArchitectCommand } from '../models/architect-command'; +import { Arguments } from '../models/interface'; +import { Schema as Xi18nCommandSchema } from './xi18n'; + +export class Xi18nCommand extends ArchitectCommand { + public readonly target = 'extract-i18n'; + public readonly multiTarget: true; + + public async run(options: Xi18nCommandSchema & Arguments) { + return this.runArchitectTarget(options); + } +} diff --git a/packages/angular/cli/commands/xi18n.json b/packages/angular/cli/commands/xi18n.json new file mode 100644 index 000000000000..082ae7ca1ba2 --- /dev/null +++ b/packages/angular/cli/commands/xi18n.json @@ -0,0 +1,17 @@ +{ + "$schema": "http://json-schema.org/schema", + "$id": "ng-cli://commands/xi18n.json", + "description": "Extracts i18n messages from source code.", + "$longDescription": "", + + "$aliases": [], + "$scope": "in", + "$type": "architect", + "$impl": "./xi18n-impl#Xi18nCommand", + + "type": "object", + "allOf": [ + { "$ref": "./definitions.json#/definitions/architect" }, + { "$ref": "./definitions.json#/definitions/base" } + ] +} diff --git a/packages/angular/cli/lib/cli/index.ts b/packages/angular/cli/lib/cli/index.ts new file mode 100644 index 000000000000..7559bab0deb0 --- /dev/null +++ b/packages/angular/cli/lib/cli/index.ts @@ -0,0 +1,124 @@ +/** + * @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 { logging, terminal } from '@angular-devkit/core'; +import { filter } from 'rxjs/operators'; +import { runCommand } from '../../models/command-runner'; +import { getWorkspaceRaw } from '../../utilities/config'; +import { getWorkspaceDetails } from '../../utilities/project'; + + +export default async function(options: { testing?: boolean, cliArgs: string[] }) { + const logger = new logging.IndentLogger('cling'); + let loggingSubscription; + if (!options.testing) { + loggingSubscription = initializeLogging(logger); + } + + let projectDetails = getWorkspaceDetails(); + if (projectDetails === null) { + const [, localPath] = getWorkspaceRaw('local'); + if (localPath !== null) { + logger.fatal(`An invalid configuration file was found ['${localPath}'].` + + ' Please delete the file before running the command.'); + + return 1; + } + + projectDetails = { root: process.cwd() }; + } + + try { + const maybeExitCode = await runCommand(options.cliArgs, logger, projectDetails); + if (typeof maybeExitCode === 'number') { + console.assert(Number.isInteger(maybeExitCode)); + + return maybeExitCode; + } + + return 0; + } catch (err) { + if (err instanceof Error) { + logger.fatal(err.message); + if (err.stack) { + logger.fatal(err.stack); + } + } else if (typeof err === 'string') { + logger.fatal(err); + } else if (typeof err === 'number') { + // Log nothing. + } else { + logger.fatal('An unexpected error occurred: ' + JSON.stringify(err)); + } + + if (options.testing) { + debugger; + throw err; + } + + if (loggingSubscription) { + loggingSubscription.unsubscribe(); + } + + return 1; + } +} + +// Initialize logging. +function initializeLogging(logger: logging.Logger) { + return logger + .pipe(filter(entry => (entry.level != 'debug'))) + .subscribe(entry => { + let color = (x: string) => terminal.dim(terminal.white(x)); + let output = process.stdout; + switch (entry.level) { + case 'info': + color = terminal.white; + break; + case 'warn': + color = terminal.yellow; + break; + case 'error': + color = terminal.red; + output = process.stderr; + break; + case 'fatal': + color = (x) => terminal.bold(terminal.red(x)); + output = process.stderr; + break; + } + + // If we do console.log(message) or process.stdout.write(message + '\n'), the process might + // stop before the whole message is written and the stream is flushed. This happens when + // streams are asynchronous. + // + // NodeJS IO streams are different depending on platform and usage. In POSIX environment, + // for example, they're asynchronous when writing to a pipe, but synchronous when writing + // to a TTY. In windows, it's the other way around. You can verify which is which with + // stream.isTTY and platform, but this is not good enough. + // In the async case, one should wait for the callback before sending more data or + // continuing the process. In our case it would be rather hard to do (but not impossible). + // + // Instead we take the easy way out and simply chunk the message and call the write + // function while the buffer drain itself asynchronously. With a smaller chunk size than + // the buffer, we are mostly certain that it works. In this case, the chunk has been picked + // as half a page size (4096/2 = 2048), minus some bytes for the color formatting. + // On POSIX it seems the buffer is 2 pages (8192), but just to be sure (could be different + // by platform). + // + // For more details, see https://nodejs.org/api/process.html#process_a_note_on_process_i_o + const chunkSize = 2000; // Small chunk. + let message = entry.message; + while (message) { + const chunk = message.slice(0, chunkSize); + message = message.slice(chunkSize); + output.write(color(chunk)); + } + output.write('\n'); + }); +} diff --git a/packages/angular/cli/lib/config/schema.json b/packages/angular/cli/lib/config/schema.json new file mode 100644 index 000000000000..ba1c6a7b66e6 --- /dev/null +++ b/packages/angular/cli/lib/config/schema.json @@ -0,0 +1,1686 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "id": "https://angular.io/schemas/cli-1/schema", + "title": "Angular CLI Configuration", + "type": "object", + "properties": { + "$schema": { + "type": "string" + }, + "version": { + "$ref": "#/definitions/fileVersion" + }, + "cli": { + "$ref": "#/definitions/cliOptions" + }, + "schematics": { + "$ref": "#/definitions/schematicOptions" + }, + "newProjectRoot": { + "type": "string", + "description": "Path where new projects will be created." + }, + "defaultProject": { + "type": "string", + "description": "Default project name used in commands." + }, + "projects": { + "type": "object", + "patternProperties": { + "^[a-zA-Z][.0-9a-zA-Z]*(-[.0-9a-zA-Z]*)*$": { + "$ref": "#/definitions/project" + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false, + "required": [ + "version" + ], + "definitions": { + "cliOptions": { + "type": "object", + "properties": { + "defaultCollection": { + "description": "The default schematics collection to use.", + "type": "string" + }, + "packageManager": { + "description": "Specify which package manager tool to use.", + "type": "string", + "enum": [ "npm", "cnpm", "yarn" ] + }, + "warnings": { + "description": "Control CLI specific console warnings", + "type": "object", + "properties": { + "versionMismatch": { + "description": "Show a warning when the global version is newer than the local one.", + "type": "boolean" + }, + "typescriptMismatch": { + "description": "Show a warning when the TypeScript version is incompatible.", + "type": "boolean" + } + } + } + }, + "additionalProperties": false + }, + "schematicOptions": { + "type": "object", + "properties": { + "@schematics/angular:component": { + "type": "object", + "properties": { + "changeDetection": { + "description": "Specifies the change detection strategy.", + "enum": ["Default", "OnPush"], + "type": "string", + "default": "Default", + "alias": "c" + }, + "entryComponent": { + "type": "boolean", + "default": false, + "description": "Specifies if the component is an entry component of declaring module." + }, + "export": { + "type": "boolean", + "default": false, + "description": "Specifies if declaring module exports the component." + }, + "flat": { + "type": "boolean", + "description": "Flag to indicate if a dir is created.", + "default": false + }, + "inlineStyle": { + "description": "Specifies if the style will be in the ts file.", + "type": "boolean", + "default": false, + "alias": "s" + }, + "inlineTemplate": { + "description": "Specifies if the template will be in the ts file.", + "type": "boolean", + "default": false, + "alias": "t" + }, + "module": { + "type": "string", + "description": "Allows specification of the declaring module.", + "alias": "m" + }, + "prefix": { + "type": "string", + "format": "html-selector", + "description": "The prefix to apply to generated selectors.", + "alias": "p" + }, + "selector": { + "type": "string", + "format": "html-selector", + "description": "The selector to use for the component." + }, + "skipImport": { + "type": "boolean", + "description": "Flag to skip the module import.", + "default": false + }, + "spec": { + "type": "boolean", + "description": "Specifies if a spec file is generated.", + "default": true + }, + "styleext": { + "description": "The file extension to be used for style files.", + "type": "string", + "default": "css" + }, + "viewEncapsulation": { + "description": "Specifies the view encapsulation strategy.", + "enum": ["Emulated", "Native", "None", "ShadowDom"], + "type": "string", + "alias": "v" + } + } + }, + "@schematics/angular:directive": { + "type": "object", + "properties": { + "export": { + "type": "boolean", + "default": false, + "description": "Specifies if declaring module exports the directive." + }, + "flat": { + "type": "boolean", + "description": "Flag to indicate if a dir is created.", + "default": true + }, + "module": { + "type": "string", + "description": "Allows specification of the declaring module.", + "alias": "m" + }, + "prefix": { + "type": "string", + "format": "html-selector", + "description": "The prefix to apply to generated selectors.", + "default": "app", + "alias": "p" + }, + "selector": { + "type": "string", + "format": "html-selector", + "description": "The selector to use for the directive." + }, + "skipImport": { + "type": "boolean", + "description": "Flag to skip the module import.", + "default": false + }, + "spec": { + "type": "boolean", + "description": "Specifies if a spec file is generated.", + "default": true + } + } + }, + "@schematics/angular:module": { + "type": "object", + "properties": { + "routing": { + "type": "boolean", + "description": "Generates a routing module.", + "default": false + }, + "routingScope": { + "enum": ["Child", "Root"], + "type": "string", + "description": "The scope for the generated routing.", + "default": "Child" + }, + "spec": { + "type": "boolean", + "description": "Specifies if a spec file is generated.", + "default": true + }, + "flat": { + "type": "boolean", + "description": "Flag to indicate if a dir is created.", + "default": false + }, + "commonModule": { + "type": "boolean", + "description": "Flag to control whether the CommonModule is imported.", + "default": true, + "visible": false + }, + "module": { + "type": "string", + "description": "Allows specification of the declaring module.", + "alias": "m" + } + } + }, + "@schematics/angular:service": { + "type": "object", + "properties": { + "flat": { + "type": "boolean", + "default": true, + "description": "Flag to indicate if a dir is created." + }, + "spec": { + "type": "boolean", + "default": true, + "description": "Specifies if a spec file is generated." + } + } + }, + "@schematics/angular:pipe": { + "type": "object", + "properties": { + "flat": { + "type": "boolean", + "default": true, + "description": "Flag to indicate if a dir is created." + }, + "spec": { + "type": "boolean", + "default": true, + "description": "Specifies if a spec file is generated." + }, + "skipImport": { + "type": "boolean", + "default": false, + "description": "Allows for skipping the module import." + }, + "module": { + "type": "string", + "default": "", + "description": "Allows specification of the declaring module.", + "alias": "m" + }, + "export": { + "type": "boolean", + "default": false, + "description": "Specifies if declaring module exports the pipe." + } + } + }, + "@schematics/angular:class": { + "type": "object", + "properties": { + "spec": { + "type": "boolean", + "default": true, + "description": "Specifies if a spec file is generated." + } + } + } + }, + "additionalProperties": { + "type": "object" + } + }, + "fileVersion": { + "type": "integer", + "description": "File format version", + "minimum": 1 + }, + "project": { + "type": "object", + "properties": { + "cli": { + "$ref": "#/definitions/cliOptions" + }, + "schematics": { + "$ref": "#/definitions/schematicOptions" + }, + "prefix": { + "type": "string", + "format": "html-selector", + "description": "The prefix to apply to generated selectors." + }, + "root": { + "type": "string", + "description": "Root of the project files." + }, + "sourceRoot": { + "type": "string", + "description": "The root of the source files, assets and index.html file structure." + }, + "projectType": { + "type": "string", + "description": "Project type.", + "enum": [ + "application", + "library" + ] + }, + "architect": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/project/definitions/target" + } + }, + "targets": { + "type": "object", + "additionalProperties": { + "$ref": "#/definitions/project/definitions/target" + } + } + }, + "required": [ + "root", + "projectType" + ], + "anyOf": [ + { + "required": ["architect"], + "not": { + "required": ["targets"] + } + }, + { + "required": ["targets"], + "not": { + "required": ["architect"] + } + }, + { + "not": { + "required": [ + "targets", + "architect" + ] + } + } + ], + "additionalProperties": false, + "patternProperties": { + "^[a-z]{1,3}-.*": {} + }, + "definitions": { + "target": { + "oneOf": [ + { + "$comment": "Extendable target with custom builder", + "type": "object", + "properties": { + "builder": { + "type": "string", + "description": "The builder used for this package.", + "not": { + "enum": [ + "@angular-devkit/build-angular:app-shell", + "@angular-devkit/build-angular:browser", + "@angular-devkit/build-angular:dev-server", + "@angular-devkit/build-angular:extract-i18n", + "@angular-devkit/build-angular:karma", + "@angular-devkit/build-angular:protractor", + "@angular-devkit/build-angular:server", + "@angular-devkit/build-angular:tslint" + ] + } + }, + "options": { + "type": "object" + }, + "configurations": { + "type": "object", + "description": "A map of alternative target options.", + "additionalProperties": { + "type": "object" + } + } + }, + "required": [ + "builder" + ] + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:app-shell" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/appShell" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/appShell" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:browser" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/browser" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/browser" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:dev-server" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/devServer" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/devServer" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:extract-i18n" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/extracti18n" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/extracti18n" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:karma" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/karma" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/karma" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:protractor" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/protractor" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/protractor" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:server" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/server" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/server" } + } + } + }, + { + "type": "object", + "properties": { + "builder": { "const": "@angular-devkit/build-angular:tslint" }, + "options": { "$ref": "#/definitions/targetOptions/definitions/tslint" }, + "configurations": { + "type": "object", + "additionalProperties": { "$ref": "#/definitions/targetOptions/definitions/tslint" } + } + } + } + ] + } + } + }, + "global": { + "type": "object", + "properties": { + "$schema": { + "type": "string", + "format": "uri" + }, + "version": { + "$ref": "#/definitions/fileVersion" + }, + "cli": { + "$ref": "#/definitions/cliOptions" + }, + "schematics": { + "$ref": "#/definitions/schematicOptions" + } + }, + "required": [ + "version" + ] + }, + "targetOptions": { + "type": "null", + "definitions": { + "appShell": { + "description": "App Shell target options for Build Facade.", + "type": "object", + "properties": { + "browserTarget": { + "type": "string", + "description": "Target to build." + }, + "serverTarget": { + "type": "string", + "description": "Server target to use for rendering the app shell." + }, + "appModuleBundle": { + "type": "string", + "description": "Script that exports the Server AppModule to render. This should be the main JavaScript outputted by the server target. By default we will resolve the outputPath of the serverTarget and find a bundle named 'main' in it (whether or not there's a hash tag)." + }, + "route": { + "type": "string", + "description": "The route to render.", + "default": "/" + }, + "inputIndexPath": { + "type": "string", + "description": "The input path for the index.html file. By default uses the output index.html of the browser target." + }, + "outputIndexPath": { + "type": "string", + "description": "The output path of the index.html file. By default will overwrite the input file." + } + }, + "additionalProperties": false + }, + "browser": { + "title": "Webpack browser schema for Build Facade.", + "description": "Browser target options", + "properties": { + "assets": { + "type": "array", + "description": "List of static application assets.", + "default": [], + "items": { + "$ref": "#/definitions/targetOptions/definitions/browser/definitions/assetPattern" + } + }, + "main": { + "type": "string", + "description": "The name of the main entry-point file." + }, + "polyfills": { + "type": "string", + "description": "The name of the polyfills file." + }, + "tsConfig": { + "type": "string", + "description": "The name of the TypeScript configuration file." + }, + "scripts": { + "description": "Global scripts to be included in the build.", + "type": "array", + "default": [], + "items": { + "$ref": "#/definitions/targetOptions/definitions/browser/definitions/extraEntryPoint" + } + }, + "styles": { + "description": "Global styles to be included in the build.", + "type": "array", + "default": [], + "items": { + "$ref": "#/definitions/targetOptions/definitions/browser/definitions/extraEntryPoint" + } + }, + "stylePreprocessorOptions": { + "description": "Options to pass to style preprocessors.", + "type": "object", + "properties": { + "includePaths": { + "description": "Paths to include. Paths will be resolved to project root.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "additionalProperties": false + }, + "optimization": { + "type": "boolean", + "description": "Enables optimization of the build output.", + "default": false + }, + "fileReplacements": { + "description": "Replace files with other files in the build.", + "type": "array", + "items": { + "$ref": "#/definitions/targetOptions/definitions/browser/definitions/fileReplacement" + }, + "default": [] + }, + "outputPath": { + "type": "string", + "description": "Path where output will be placed." + }, + "aot": { + "type": "boolean", + "description": "Build using Ahead of Time compilation.", + "default": false + }, + "sourceMap": { + "type": "boolean", + "description": "Output sourcemaps.", + "default": true + }, + "vendorSourceMap": { + "type": "boolean", + "description": "Resolve vendor packages sourcemaps.", + "default": false + }, + "evalSourceMap": { + "type": "boolean", + "description": "Output in-file eval sourcemaps.", + "default": false + }, + "vendorChunk": { + "type": "boolean", + "description": "Use a separate bundle containing only vendor libraries.", + "default": true + }, + "commonChunk": { + "type": "boolean", + "description": "Use a separate bundle containing code used across multiple bundles.", + "default": true + }, + "baseHref": { + "type": "string", + "description": "Base url for the application being built." + }, + "deployUrl": { + "type": "string", + "description": "URL where files will be deployed." + }, + "verbose": { + "type": "boolean", + "description": "Adds more details to output logging.", + "default": false + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console while building.", + "default": true + }, + "i18nFile": { + "type": "string", + "description": "Localization file to use for i18n." + }, + "i18nFormat": { + "type": "string", + "description": "Format of the localization file specified with --i18n-file." + }, + "i18nLocale": { + "type": "string", + "description": "Locale to use for i18n." + }, + "i18nMissingTranslation": { + "type": "string", + "description": "How to handle missing translations for i18n." + }, + "extractCss": { + "type": "boolean", + "description": "Extract css from global styles onto css files instead of js ones.", + "default": false + }, + "watch": { + "type": "boolean", + "description": "Run build when files change.", + "default": false + }, + "outputHashing": { + "type": "string", + "description": "Define the output filename cache-busting hashing mode.", + "default": "none", + "enum": [ + "none", + "all", + "media", + "bundles" + ] + }, + "poll": { + "type": "number", + "description": "Enable and define the file watching poll time period in milliseconds." + }, + "deleteOutputPath": { + "type": "boolean", + "description": "Delete the output path before building.", + "default": true + }, + "preserveSymlinks": { + "type": "boolean", + "description": "Do not use the real path when resolving modules.", + "default": false + }, + "extractLicenses": { + "type": "boolean", + "description": "Extract all licenses in a separate file, in the case of production builds only.", + "default": true + }, + "showCircularDependencies": { + "type": "boolean", + "description": "Show circular dependency warnings on builds.", + "default": true + }, + "buildOptimizer": { + "type": "boolean", + "description": "Enables @angular-devkit/build-optimizer optimizations when using the 'aot' option.", + "default": false + }, + "namedChunks": { + "type": "boolean", + "description": "Use file name for lazy loaded chunks.", + "default": true + }, + "subresourceIntegrity": { + "type": "boolean", + "description": "Enables the use of subresource integrity validation.", + "default": false + }, + "serviceWorker": { + "type": "boolean", + "description": "Generates a service worker config for production builds.", + "default": false + }, + "skipAppShell": { + "type": "boolean", + "description": "Flag to prevent building an app shell.", + "default": false + }, + "index": { + "type": "string", + "description": "The name of the index HTML file." + }, + "statsJson": { + "type": "boolean", + "description": "Generates a 'stats.json' file which can be analyzed using tools such as: #webpack-bundle-analyzer' or https://webpack.github.io/analyse .", + "default": false + }, + "forkTypeChecker": { + "type": "boolean", + "description": "Run the TypeScript type checker in a forked process.", + "default": true + }, + "lazyModules": { + "description": "List of additional NgModule files that will be lazy loaded. Lazy router modules with be discovered automatically.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + }, + "budgets": { + "description": "Budget thresholds to ensure parts of your application stay within boundaries which you set.", + "type": "array", + "items": { + "$ref": "#/definitions/targetOptions/definitions/browser/definitions/budget" + }, + "default": [] + } + }, + "additionalProperties": false, + "definitions": { + "assetPattern": { + "oneOf": [ + { + "type": "object", + "properties": { + "glob": { + "type": "string", + "description": "The pattern to match." + }, + "input": { + "type": "string", + "description": "The input path dir in which to apply 'glob'. Defaults to the project root." + }, + "output": { + "type": "string", + "description": "Absolute path within the output." + }, + "ignore": { + "description": "An array of globs to ignore.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "glob", + "input", + "output" + ] + }, + { + "type": "string", + "description": "The file to include." + } + ] + }, + "fileReplacement": { + "oneOf": [ + { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "replaceWith": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "src", + "replaceWith" + ] + }, + { + "type": "object", + "properties": { + "replace": { + "type": "string" + }, + "with": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "replace", + "with" + ] + } + ] + }, + "extraEntryPoint": { + "oneOf": [ + { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "The file to include." + }, + "bundleName": { + "type": "string", + "description": "The bundle name for this extra entry point." + }, + "lazy": { + "type": "boolean", + "description": "If the bundle will be lazy loaded.", + "default": false + } + }, + "additionalProperties": false, + "required": [ + "input" + ] + }, + { + "type": "string", + "description": "The file to include." + } + ] + }, + "budget": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of budget.", + "enum": [ + "all", + "allScript", + "any", + "anyScript", + "bundle", + "initial" + ] + }, + "name": { + "type": "string", + "description": "The name of the bundle." + }, + "baseline": { + "type": "string", + "description": "The baseline size for comparison." + }, + "maximumWarning": { + "type": "string", + "description": "The maximum threshold for warning relative to the baseline." + }, + "maximumError": { + "type": "string", + "description": "The maximum threshold for error relative to the baseline." + }, + "minimumWarning": { + "type": "string", + "description": "The minimum threshold for warning relative to the baseline." + }, + "minimumError": { + "type": "string", + "description": "The minimum threshold for error relative to the baseline." + }, + "warning": { + "type": "string", + "description": "The threshold for warning relative to the baseline (min & max)." + }, + "error": { + "type": "string", + "description": "The threshold for error relative to the baseline (min & max)." + } + }, + "additionalProperties": false, + "required": [ + "type" + ] + } + } + }, + "devServer": { + "description": "Dev Server target options for Build Facade.", + "type": "object", + "properties": { + "browserTarget": { + "type": "string", + "description": "Target to serve." + }, + "port": { + "type": "number", + "description": "Port to listen on.", + "default": 4200 + }, + "host": { + "type": "string", + "description": "Host to listen on.", + "default": "localhost" + }, + "proxyConfig": { + "type": "string", + "description": "Proxy configuration file." + }, + "ssl": { + "type": "boolean", + "description": "Serve using HTTPS.", + "default": false + }, + "sslKey": { + "type": "string", + "description": "SSL key to use for serving HTTPS." + }, + "sslCert": { + "type": "string", + "description": "SSL certificate to use for serving HTTPS." + }, + "open": { + "type": "boolean", + "description": "Opens the url in default browser.", + "default": false, + "alias": "o" + }, + "liveReload": { + "type": "boolean", + "description": "Whether to reload the page on change, using live-reload.", + "default": true + }, + "publicHost": { + "type": "string", + "description": "Specify the URL that the browser client will use." + }, + "servePath": { + "type": "string", + "description": "The pathname where the app will be served." + }, + "disableHostCheck": { + "type": "boolean", + "description": "Don't verify connected clients are part of allowed hosts.", + "default": false + }, + "hmr": { + "type": "boolean", + "description": "Enable hot module replacement.", + "default": false + }, + "watch": { + "type": "boolean", + "description": "Rebuild on change.", + "default": true + }, + "hmrWarning": { + "type": "boolean", + "description": "Show a warning when the --hmr option is enabled.", + "default": true + }, + "servePathDefaultWarning": { + "type": "boolean", + "description": "Show a warning when deploy-url/base-href use unsupported serve path values.", + "default": true + }, + "optimization": { + "type": "boolean", + "description": "Enables optimization of the build output." + }, + "aot": { + "type": "boolean", + "description": "Build using Ahead of Time compilation." + }, + "sourceMap": { + "type": "boolean", + "description": "Output sourcemaps." + }, + "vendorSourceMap": { + "type": "boolean", + "description": "Resolve vendor packages sourcemaps.", + "default": false + }, + "evalSourceMap": { + "type": "boolean", + "description": "Output in-file eval sourcemaps." + }, + "vendorChunk": { + "type": "boolean", + "description": "Use a separate bundle containing only vendor libraries." + }, + "commonChunk": { + "type": "boolean", + "description": "Use a separate bundle containing code used across multiple bundles." + }, + "baseHref": { + "type": "string", + "description": "Base url for the application being built." + }, + "deployUrl": { + "type": "string", + "description": "URL where files will be deployed." + }, + "verbose": { + "type": "boolean", + "description": "Adds more details to output logging." + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console while building." + } + }, + "additionalProperties": false + }, + "extracti18n": { + "description": "Extract i18n target options for Build Facade.", + "type": "object", + "properties": { + "browserTarget": { + "type": "string", + "description": "Target to extract from." + }, + "i18nFormat": { + "type": "string", + "description": "Output format for the generated file.", + "default": "xlf", + "enum": [ + "xmb", + "xlf", + "xlif", + "xliff", + "xlf2", + "xliff2" + ] + }, + "i18nLocale": { + "type": "string", + "description": "Specifies the source language of the application." + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console.", + "default": true + }, + "outputPath": { + "type": "string", + "description": "Path where output will be placed." + }, + "outFile": { + "type": "string", + "description": "Name of the file to output." + } + }, + "additionalProperties": false + }, + "karma": { + "description": "Karma target options for Build Facade.", + "type": "object", + "properties": { + "main": { + "type": "string", + "description": "The name of the main entry-point file." + }, + "tsConfig": { + "type": "string", + "description": "The name of the TypeScript configuration file." + }, + "karmaConfig": { + "type": "string", + "description": "The name of the Karma configuration file." + }, + "polyfills": { + "type": "string", + "description": "The name of the polyfills file." + }, + "assets": { + "type": "array", + "description": "List of static application assets.", + "default": [], + "items": { + "$ref": "#/definitions/targetOptions/definitions/karma/definitions/assetPattern" + } + }, + "scripts": { + "description": "Global scripts to be included in the build.", + "type": "array", + "default": [], + "items": { + "$ref": "#/definitions/targetOptions/definitions/karma/definitions/extraEntryPoint" + } + }, + "styles": { + "description": "Global styles to be included in the build.", + "type": "array", + "default": [], + "items": { + "$ref": "#/definitions/targetOptions/definitions/karma/definitions/extraEntryPoint" + } + }, + "stylePreprocessorOptions": { + "description": "Options to pass to style preprocessors", + "type": "object", + "properties": { + "includePaths": { + "description": "Paths to include. Paths will be resolved to project root.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "additionalProperties": false + }, + "environment": { + "type": "string", + "description": "Defines the build environment." + }, + "sourceMap": { + "type": "boolean", + "description": "Output sourcemaps.", + "default": true + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console while building.", + "default": true + }, + "watch": { + "type": "boolean", + "description": "Run build when files change.", + "default": false + }, + "poll": { + "type": "number", + "description": "Enable and define the file watching poll time period in milliseconds." + }, + "preserveSymlinks": { + "type": "boolean", + "description": "Do not use the real path when resolving modules.", + "default": false + }, + "browsers": { + "type": "string", + "description": "Override which browsers tests are run against." + }, + "codeCoverage": { + "type": "boolean", + "description": "Output a code coverage report.", + "default": false + }, + "codeCoverageExclude": { + "type": "array", + "description": "Globs to exclude from code coverage.", + "items": { + "type": "string" + }, + "default": [] + }, + "fileReplacements": { + "description": "Replace files with other files in the build.", + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "replaceWith": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "src", + "replaceWith" + ] + }, + { + "type": "object", + "properties": { + "replace": { + "type": "string" + }, + "with": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "replace", + "with" + ] + } + ] + }, + "default": [] + }, + "reporters": { + "type": "array", + "description": "Karma reporters to use. Directly passed to the karma runner.", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "definitions": { + "assetPattern": { + "oneOf": [ + { + "type": "object", + "properties": { + "glob": { + "type": "string", + "description": "The pattern to match." + }, + "input": { + "type": "string", + "description": "The input path dir in which to apply 'glob'. Defaults to the project root." + }, + "output": { + "type": "string", + "description": "Absolute path within the output." + }, + "ignore": { + "description": "An array of globs to ignore.", + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "required": [ + "glob", + "input", + "output" + ] + }, + { + "type": "string", + "description": "The file to include." + } + ] + }, + "extraEntryPoint": { + "oneOf": [ + { + "type": "object", + "properties": { + "input": { + "type": "string", + "description": "The file to include." + }, + "bundleName": { + "type": "string", + "description": "The bundle name for this extra entry point." + }, + "lazy": { + "type": "boolean", + "description": "If the bundle will be lazy loaded.", + "default": false + } + }, + "additionalProperties": false, + "required": [ + "input" + ] + }, + { + "type": "string", + "description": "The file to include." + } + ] + } + } + }, + "protractor": { + "description": "Protractor target options for Build Facade.", + "type": "object", + "properties": { + "protractorConfig": { + "type": "string", + "description": "The name of the Protractor configuration file." + }, + "devServerTarget": { + "type": "string", + "description": "Dev server target to run tests against." + }, + "specs": { + "type": "array", + "description": "Override specs in the protractor config.", + "default": [], + "items": { + "type": "string", + "description": "Spec name." + } + }, + "suite": { + "type": "string", + "description": "Override suite in the protractor config." + }, + "elementExplorer": { + "type": "boolean", + "description": "Start Protractor's Element Explorer for debugging.", + "default": false + }, + "webdriverUpdate": { + "type": "boolean", + "description": "Try to update webdriver.", + "default": true + }, + "serve": { + "type": "boolean", + "description": "Compile and Serve the app.", + "default": true + }, + "port": { + "type": "number", + "description": "The port to use to serve the application." + }, + "host": { + "type": "string", + "description": "Host to listen on.", + "default": "localhost" + }, + "baseUrl": { + "type": "string", + "description": "Base URL for protractor to connect to." + } + }, + "additionalProperties": false + }, + "server": { + "title": "Angular Webpack Architect Builder Schema", + "properties": { + "main": { + "type": "string", + "description": "The name of the main entry-point file." + }, + "tsConfig": { + "type": "string", + "default": "tsconfig.app.json", + "description": "The name of the TypeScript configuration file." + }, + "stylePreprocessorOptions": { + "description": "Options to pass to style preprocessors", + "type": "object", + "properties": { + "includePaths": { + "description": "Paths to include. Paths will be resolved to project root.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "additionalProperties": false + }, + "optimization": { + "type": "boolean", + "description": "Enables optimization of the build output.", + "default": false + }, + "fileReplacements": { + "description": "Replace files with other files in the build.", + "type": "array", + "items": { + "$ref": "#/definitions/targetOptions/definitions/server/definitions/fileReplacement" + }, + "default": [] + }, + "outputPath": { + "type": "string", + "description": "Path where output will be placed." + }, + "sourceMap": { + "type": "boolean", + "description": "Output sourcemaps.", + "default": true + }, + "vendorSourceMap": { + "type": "boolean", + "description": "Resolve vendor packages sourcemaps.", + "default": false + }, + "evalSourceMap": { + "type": "boolean", + "description": "Output in-file eval sourcemaps.", + "default": false + }, + "vendorChunk": { + "type": "boolean", + "description": "Use a separate bundle containing only vendor libraries.", + "default": true + }, + "commonChunk": { + "type": "boolean", + "description": "Use a separate bundle containing code used across multiple bundles.", + "default": true + }, + "verbose": { + "type": "boolean", + "description": "Adds more details to output logging.", + "default": false + }, + "progress": { + "type": "boolean", + "description": "Log progress to the console while building.", + "default": true + }, + "i18nFile": { + "type": "string", + "description": "Localization file to use for i18n." + }, + "i18nFormat": { + "type": "string", + "description": "Format of the localization file specified with --i18n-file." + }, + "i18nLocale": { + "type": "string", + "description": "Locale to use for i18n." + }, + "i18nMissingTranslation": { + "type": "string", + "description": "How to handle missing translations for i18n." + }, + "outputHashing": { + "type": "string", + "description": "Define the output filename cache-busting hashing mode.", + "default": "none", + "enum": [ + "none", + "all", + "media", + "bundles" + ] + }, + "deleteOutputPath": { + "type": "boolean", + "description": "delete-output-path", + "default": true + }, + "preserveSymlinks": { + "type": "boolean", + "description": "Do not use the real path when resolving modules.", + "default": false + }, + "extractLicenses": { + "type": "boolean", + "description": "Extract all licenses in a separate file, in the case of production builds only.", + "default": true + }, + "showCircularDependencies": { + "type": "boolean", + "description": "Show circular dependency warnings on builds.", + "default": true + }, + "namedChunks": { + "type": "boolean", + "description": "Use file name for lazy loaded chunks.", + "default": true + }, + "bundleDependencies": { + "type": "string", + "description": "Available on server platform only. Which external dependencies to bundle into the module. By default, all of node_modules will be kept as requires.", + "default": "none", + "enum": [ + "none", + "all" + ] + }, + "statsJson": { + "type": "boolean", + "description": "Generates a 'stats.json' file which can be analyzed using tools such as: #webpack-bundle-analyzer' or https://webpack.github.io/analyse .", + "default": false + }, + "forkTypeChecker": { + "type": "boolean", + "description": "Run the TypeScript type checker in a forked process.", + "default": true + }, + "lazyModules": { + "description": "List of additional NgModule files that will be lazy loaded. Lazy router modules with be discovered automatically.", + "type": "array", + "items": { + "type": "string" + }, + "default": [] + } + }, + "additionalProperties": false, + "definitions": { + "fileReplacement": { + "oneOf": [ + { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "replaceWith": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "src", + "replaceWith" + ] + }, + { + "type": "object", + "properties": { + "replace": { + "type": "string" + }, + "with": { + "type": "string" + } + }, + "additionalProperties": false, + "required": [ + "replace", + "with" + ] + } + ] + } + } + }, + "tslint": { + "description": "TSlint target options for Build Facade.", + "type": "object", + "properties": { + "tslintConfig": { + "type": "string", + "description": "The name of the TSLint configuration file." + }, + "tsConfig": { + "description": "The name of the TypeScript configuration file.", + "oneOf": [ + { "type": "string" }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "fix": { + "type": "boolean", + "description": "Fixes linting errors (may overwrite linted files).", + "default": false + }, + "typeCheck": { + "type": "boolean", + "description": "Controls the type check for linting.", + "default": false + }, + "force": { + "type": "boolean", + "description": "Succeeds even if there was linting errors.", + "default": false + }, + "silent": { + "type": "boolean", + "description": "Show output text.", + "default": false + }, + "format": { + "type": "string", + "description": "Output format (prose, json, stylish, verbose, pmd, msbuild, checkstyle, vso, fileslist, codeFrame).", + "default": "prose", + "anyOf": [ + { + "enum": [ + "checkstyle", + "codeFrame", + "filesList", + "json", + "junit", + "msbuild", + "pmd", + "prose", + "stylish", + "tap", + "verbose", + "vso" + ] + }, + { "minLength": 1 } + ] + }, + "exclude": { + "type": "array", + "description": "Files to exclude from linting.", + "default": [], + "items": { + "type": "string" + } + }, + "files": { + "type": "array", + "description": "Files to include in linting.", + "default": [], + "items": { + "type": "string" + } + } + }, + "additionalProperties": false + } + } + } + } +} diff --git a/packages/angular/cli/lib/init.ts b/packages/angular/cli/lib/init.ts new file mode 100644 index 000000000000..41fa2f33e81f --- /dev/null +++ b/packages/angular/cli/lib/init.ts @@ -0,0 +1,157 @@ +/** + * @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 'symbol-observable'; +// symbol polyfill must go first +// tslint:disable-next-line:ordered-imports import-groups +import { tags, terminal } from '@angular-devkit/core'; +import { resolve } from '@angular-devkit/core/node'; +import * as fs from 'fs'; +import * as path from 'path'; +import { SemVer } from 'semver'; +import { Duplex } from 'stream'; +import { isWarningEnabled } from '../utilities/config'; + +const packageJson = require('../package.json'); + +function _fromPackageJson(cwd?: string) { + cwd = cwd || process.cwd(); + + do { + const packageJsonPath = path.join(cwd, 'node_modules/@angular/cli/package.json'); + if (fs.existsSync(packageJsonPath)) { + const content = fs.readFileSync(packageJsonPath, 'utf-8'); + if (content) { + const json = JSON.parse(content); + if (json['version']) { + return new SemVer(json['version']); + } + } + } + + // Check the parent. + cwd = path.dirname(cwd); + } while (cwd != path.dirname(cwd)); + + return null; +} + + +// Check if we need to profile this CLI run. +if (process.env['NG_CLI_PROFILING']) { + let profiler: { + startProfiling: (name?: string, recsamples?: boolean) => void; + stopProfiling: (name?: string) => any; // tslint:disable-line:no-any + }; + try { + profiler = require('v8-profiler-node8'); // tslint:disable-line:no-implicit-dependencies + } catch (err) { + throw new Error(`Could not require 'v8-profiler-node8'. You must install it separetely with` + + `'npm install v8-profiler-node8 --no-save.\n\nOriginal error:\n\n${err}`); + } + + profiler.startProfiling(); + + const exitHandler = (options: { cleanup?: boolean, exit?: boolean }) => { + if (options.cleanup) { + const cpuProfile = profiler.stopProfiling(); + fs.writeFileSync( + path.resolve(process.cwd(), process.env.NG_CLI_PROFILING || '') + '.cpuprofile', + JSON.stringify(cpuProfile), + ); + } + + if (options.exit) { + process.exit(); + } + }; + + process.on('exit', () => exitHandler({ cleanup: true })); + process.on('SIGINT', () => exitHandler({ exit: true })); + process.on('uncaughtException', () => exitHandler({ exit: true })); +} + +let cli; +try { + const projectLocalCli = resolve( + '@angular/cli', + { + checkGlobal: false, + basedir: process.cwd(), + preserveSymlinks: true, + }, + ); + + // This was run from a global, check local version. + const globalVersion = new SemVer(packageJson['version']); + let localVersion; + let shouldWarn = false; + + try { + localVersion = _fromPackageJson(); + shouldWarn = localVersion != null && globalVersion.compare(localVersion) > 0; + } catch (e) { + // eslint-disable-next-line no-console + console.error(e); + shouldWarn = true; + } + + if (shouldWarn && isWarningEnabled('versionMismatch')) { + const warning = terminal.yellow(tags.stripIndents` + Your global Angular CLI version (${globalVersion}) is greater than your local + version (${localVersion}). The local Angular CLI version is used. + + To disable this warning use "ng config -g cli.warnings.versionMismatch false". + `); + // Don't show warning colorised on `ng completion` + if (process.argv[2] !== 'completion') { + // eslint-disable-next-line no-console + console.error(warning); + } else { + // eslint-disable-next-line no-console + console.error(warning); + process.exit(1); + } + } + + // No error implies a projectLocalCli, which will load whatever + // version of ng-cli you have installed in a local package.json + cli = require(projectLocalCli); +} catch { + // If there is an error, resolve could not find the ng-cli + // library from a package.json. Instead, include it from a relative + // path to this script file (which is likely a globally installed + // npm package). Most common cause for hitting this is `ng new` + cli = require('./cli'); +} + +if ('default' in cli) { + cli = cli['default']; +} + +// This is required to support 1.x local versions with a 6+ global +let standardInput; +try { + standardInput = process.stdin; +} catch (e) { + delete process.stdin; + process.stdin = new Duplex(); + standardInput = process.stdin; +} + +cli({ + cliArgs: process.argv.slice(2), + inputStream: standardInput, + outputStream: process.stdout, +}) + .then((exitCode: number) => { + process.exit(exitCode); + }) + .catch((err: Error) => { + console.error('Unknown error: ' + err.toString()); + process.exit(127); + }); diff --git a/packages/angular/cli/models/architect-command.ts b/packages/angular/cli/models/architect-command.ts new file mode 100644 index 000000000000..729afd19966f --- /dev/null +++ b/packages/angular/cli/models/architect-command.ts @@ -0,0 +1,273 @@ +/** + * @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 { + Architect, + BuildEvent, + BuilderConfiguration, + TargetSpecifier, +} from '@angular-devkit/architect'; +import { experimental, json, schema, tags } from '@angular-devkit/core'; +import { NodeJsSyncHost, createConsoleLogger } from '@angular-devkit/core/node'; +import { from } from 'rxjs'; +import { concatMap, map, tap, toArray } from 'rxjs/operators'; +import { parseJsonSchemaToOptions } from '../utilities/json-schema'; +import { BaseCommandOptions, Command } from './command'; +import { Arguments } from './interface'; +import { parseArguments } from './parser'; +import { WorkspaceLoader } from './workspace-loader'; + +export interface ArchitectCommandOptions extends BaseCommandOptions { + project?: string; + configuration?: string; + prod?: boolean; + target?: string; +} + +export abstract class ArchitectCommand< + T extends ArchitectCommandOptions = ArchitectCommandOptions, +> extends Command { + private _host = new NodeJsSyncHost(); + protected _architect: Architect; + protected _workspace: experimental.workspace.Workspace; + protected _logger = createConsoleLogger(); + + protected _registry: json.schema.SchemaRegistry; + + // If this command supports running multiple targets. + protected multiTarget = false; + + target: string | undefined; + + public async initialize(options: ArchitectCommandOptions & Arguments): Promise { + await super.initialize(options); + + this._registry = new json.schema.CoreSchemaRegistry(); + this._registry.addPostTransform(json.schema.transforms.addUndefinedDefaults); + + await this._loadWorkspaceAndArchitect().toPromise(); + + if (!options.project && this.target) { + const projectNames = this.getProjectNamesByTarget(this.target); + const leftovers = options['--']; + if (projectNames.length > 1 && leftovers && leftovers.length > 0) { + // Verify that all builders are the same, otherwise error out (since the meaning of an + // option could vary from builder to builder). + + const builders: string[] = []; + for (const projectName of projectNames) { + const targetSpec: TargetSpecifier = this._makeTargetSpecifier(options); + const targetDesc = this._architect.getBuilderConfiguration({ + project: projectName, + target: targetSpec.target, + }); + + if (builders.indexOf(targetDesc.builder) == -1) { + builders.push(targetDesc.builder); + } + } + + if (builders.length > 1) { + throw new Error(tags.oneLine` + Architect commands with command line overrides cannot target different builders. The + '${this.target}' target would run on projects ${projectNames.join()} which have the + following builders: ${'\n ' + builders.join('\n ')} + `); + } + } + } + + const targetSpec: TargetSpecifier = this._makeTargetSpecifier(options); + + if (this.target && !targetSpec.project) { + const projects = this.getProjectNamesByTarget(this.target); + + if (projects.length === 1) { + // If there is a single target, use it to parse overrides. + targetSpec.project = projects[0]; + } + } + + if ((!targetSpec.project || !targetSpec.target) && !this.multiTarget) { + if (options.help) { + // This is a special case where we just return. + return; + } + + throw new Error('Cannot determine project or target for Architect command.'); + } + + if (this.target) { + // Add options IF there's only one builder of this kind. + const targetSpec: TargetSpecifier = this._makeTargetSpecifier(options); + const projectNames = targetSpec.project + ? [targetSpec.project] + : this.getProjectNamesByTarget(this.target); + + const builderConfigurations: BuilderConfiguration[] = []; + for (const projectName of projectNames) { + const targetDesc = this._architect.getBuilderConfiguration({ + project: projectName, + target: targetSpec.target, + }); + + if (!builderConfigurations.find(b => b.builder === targetDesc.builder)) { + builderConfigurations.push(targetDesc); + } + } + + if (builderConfigurations.length == 1) { + const builderConf = builderConfigurations[0]; + const builderDesc = await this._architect.getBuilderDescription(builderConf).toPromise(); + + this.description.options.push(...( + await parseJsonSchemaToOptions(this._registry, builderDesc.schema) + )); + } + } + } + + async run(options: ArchitectCommandOptions & Arguments) { + return await this.runArchitectTarget(options); + } + + protected async runSingleTarget(targetSpec: TargetSpecifier, options: string[]) { + // We need to build the builderSpec twice because architect does not understand + // overrides separately (getting the configuration builds the whole project, including + // overrides). + const builderConf = this._architect.getBuilderConfiguration(targetSpec); + const builderDesc = await this._architect.getBuilderDescription(builderConf).toPromise(); + const targetOptionArray = await parseJsonSchemaToOptions(this._registry, builderDesc.schema); + const overrides = parseArguments(options, targetOptionArray); + + if (overrides['--']) { + (overrides['--'] || []).forEach(additional => { + this.logger.warn(`Unknown option: '${additional.split(/=/)[0]}'`); + }); + + return 1; + } + const realBuilderConf = this._architect.getBuilderConfiguration({ ...targetSpec, overrides }); + + return this._architect.run(realBuilderConf, { logger: this._logger }).pipe( + map((buildEvent: BuildEvent) => buildEvent.success ? 0 : 1), + ).toPromise(); + } + + protected async runArchitectTarget( + options: ArchitectCommandOptions & Arguments, + ): Promise { + const extra = options['--'] || []; + + try { + const targetSpec = this._makeTargetSpecifier(options); + if (!targetSpec.project && this.target) { + // This runs each target sequentially. + // Running them in parallel would jumble the log messages. + return await from(this.getProjectNamesByTarget(this.target)).pipe( + concatMap(project => from(this.runSingleTarget({ ...targetSpec, project }, extra))), + toArray(), + map(results => results.every(res => res === 0) ? 0 : 1), + ) + .toPromise(); + } else { + return await this.runSingleTarget(targetSpec, extra); + } + } catch (e) { + if (e instanceof schema.SchemaValidationException) { + const newErrors: schema.SchemaValidatorError[] = []; + for (const schemaError of e.errors) { + if (schemaError.keyword === 'additionalProperties') { + const unknownProperty = schemaError.params.additionalProperty; + if (unknownProperty in options) { + const dashes = unknownProperty.length === 1 ? '-' : '--'; + this.logger.fatal(`Unknown option: '${dashes}${unknownProperty}'`); + continue; + } + } + newErrors.push(schemaError); + } + + if (newErrors.length > 0) { + this.logger.error(new schema.SchemaValidationException(newErrors).message); + } + + return 1; + } else { + throw e; + } + } + } + + private getProjectNamesByTarget(targetName: string): string[] { + const allProjectsForTargetName = this._workspace.listProjectNames().map(projectName => + this._architect.listProjectTargets(projectName).includes(targetName) ? projectName : null, + ).filter(x => !!x) as string[]; + + if (this.multiTarget) { + // For multi target commands, we always list all projects that have the target. + return allProjectsForTargetName; + } else { + // For single target commands, we try the default project first, + // then the full list if it has a single project, then error out. + const maybeDefaultProject = this._workspace.getDefaultProjectName(); + if (maybeDefaultProject && allProjectsForTargetName.includes(maybeDefaultProject)) { + return [maybeDefaultProject]; + } + + if (allProjectsForTargetName.length === 1) { + return allProjectsForTargetName; + } + + throw new Error(`Could not determine a single project for the '${targetName}' target.`); + } + } + + private _loadWorkspaceAndArchitect() { + const workspaceLoader = new WorkspaceLoader(this._host); + + return workspaceLoader.loadWorkspace(this.workspace.root).pipe( + tap((workspace: experimental.workspace.Workspace) => this._workspace = workspace), + concatMap((workspace: experimental.workspace.Workspace) => { + return new Architect(workspace).loadArchitect(); + }), + tap((architect: Architect) => this._architect = architect), + ); + } + + private _makeTargetSpecifier(commandOptions: ArchitectCommandOptions): TargetSpecifier { + let project, target, configuration; + + if (commandOptions.target) { + [project, target, configuration] = commandOptions.target.split(':'); + + if (commandOptions.configuration) { + configuration = commandOptions.configuration; + } + } else { + project = commandOptions.project; + target = this.target; + configuration = commandOptions.configuration; + if (!configuration && commandOptions.prod) { + configuration = 'production'; + } + } + + if (!project) { + project = ''; + } + if (!target) { + target = ''; + } + + return { + project, + configuration, + target, + }; + } +} diff --git a/packages/angular/cli/models/command-runner.ts b/packages/angular/cli/models/command-runner.ts new file mode 100644 index 000000000000..a44c4f1a0755 --- /dev/null +++ b/packages/angular/cli/models/command-runner.ts @@ -0,0 +1,201 @@ +/** + * @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 { + JsonParseMode, + isJsonObject, + json, + logging, + schema, + strings, + tags, +} from '@angular-devkit/core'; +import { readFileSync } from 'fs'; +import { dirname, join, resolve } from 'path'; +import { of } from 'rxjs'; +import { findUp } from '../utilities/find-up'; +import { parseJsonSchemaToCommandDescription } from '../utilities/json-schema'; +import { Command } from './command'; +import { + CommandDescription, + CommandDescriptionMap, + CommandWorkspace, +} from './interface'; +import * as parser from './parser'; + + +export interface CommandMapOptions { + [key: string]: string; +} + +/** + * Run a command. + * @param args Raw unparsed arguments. + * @param logger The logger to use. + * @param workspace Workspace information. + * @param commands The map of supported commands. + */ +export async function runCommand( + args: string[], + logger: logging.Logger, + workspace: CommandWorkspace, + commands?: CommandMapOptions, +): Promise { + if (commands === undefined) { + const commandMapPath = findUp('commands.json', __dirname); + if (commandMapPath === null) { + throw new Error('Unable to find command map.'); + } + const cliDir = dirname(commandMapPath); + const commandsText = readFileSync(commandMapPath).toString('utf-8'); + const commandJson = json.parseJson( + commandsText, + JsonParseMode.Loose, + { path: commandMapPath }, + ); + if (!isJsonObject(commandJson)) { + throw Error('Invalid command.json'); + } + + commands = {}; + for (const commandName of Object.keys(commandJson)) { + const commandValue = commandJson[commandName]; + if (typeof commandValue == 'string') { + commands[commandName] = resolve(cliDir, commandValue); + } + } + } + + // This registry is exclusively used for flattening schemas, and not for validating. + const registry = new schema.CoreSchemaRegistry([]); + registry.registerUriHandler((uri: string) => { + if (uri.startsWith('ng-cli://')) { + const content = readFileSync(join(__dirname, '..', uri.substr('ng-cli://'.length)), 'utf-8'); + + return of(JSON.parse(content)); + } else { + return null; + } + }); + + // Normalize the commandMap + const commandMap: CommandDescriptionMap = {}; + for (const name of Object.keys(commands)) { + const schemaPath = commands[name]; + const schemaContent = readFileSync(schemaPath, 'utf-8'); + const schema = json.parseJson(schemaContent, JsonParseMode.Loose, { path: schemaPath }); + if (!isJsonObject(schema)) { + throw new Error('Invalid command JSON loaded from ' + JSON.stringify(schemaPath)); + } + + commandMap[name] = + await parseJsonSchemaToCommandDescription(name, schemaPath, registry, schema, logger); + } + + let commandName: string | undefined = undefined; + for (let i = 0; i < args.length; i++) { + const arg = args[i]; + + if (arg in commandMap) { + commandName = arg; + args.splice(i, 1); + break; + } else if (!arg.startsWith('-')) { + commandName = arg; + args.splice(i, 1); + break; + } + } + + // if no commands were found, use `help`. + if (commandName === undefined) { + if (args.length === 1 && args[0] === '--version') { + commandName = 'version'; + } else { + commandName = 'help'; + } + } + + let description: CommandDescription | null = null; + + if (commandName !== undefined) { + if (commandMap[commandName]) { + description = commandMap[commandName]; + } else { + Object.keys(commandMap).forEach(name => { + const commandDescription = commandMap[name]; + const aliases = commandDescription.aliases; + + let found = false; + if (aliases) { + if (aliases.some(alias => alias === commandName)) { + found = true; + } + } + + if (found) { + if (description) { + throw new Error('Found multiple commands with the same alias.'); + } + commandName = name; + description = commandDescription; + } + }); + } + } + + if (!commandName) { + logger.error(tags.stripIndent` + We could not find a command from the arguments and the help command seems to be disabled. + This is an issue with the CLI itself. If you see this comment, please report it and + provide your repository. + `); + + return 1; + } + + if (!description) { + const commandsDistance = {} as { [name: string]: number }; + const name = commandName; + const allCommands = Object.keys(commandMap).sort((a, b) => { + if (!(a in commandsDistance)) { + commandsDistance[a] = strings.levenshtein(a, name); + } + if (!(b in commandsDistance)) { + commandsDistance[b] = strings.levenshtein(b, name); + } + + return commandsDistance[a] - commandsDistance[b]; + }); + + logger.error(tags.stripIndent` + The specified command ("${commandName}") is invalid. For a list of available options, + run "ng help". + + Did you mean "${allCommands[0]}"? + `); + + return 1; + } + + try { + const parsedOptions = parser.parseArguments(args, description.options); + Command.setCommandMap(commandMap); + const command = new description.impl({ workspace }, description, logger); + + return await command.validateAndRun(parsedOptions); + } catch (e) { + if (e instanceof parser.ParseArgumentException) { + logger.fatal('Cannot parse arguments. See below for the reasons.'); + logger.fatal(' ' + e.comments.join('\n ')); + + return 1; + } else { + throw e; + } + } +} diff --git a/packages/angular/cli/models/command.ts b/packages/angular/cli/models/command.ts new file mode 100644 index 000000000000..da2079c149ea --- /dev/null +++ b/packages/angular/cli/models/command.ts @@ -0,0 +1,159 @@ +/** + * @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 + */ + +// tslint:disable:no-global-tslint-disable no-any +import { logging, strings, tags, terminal } from '@angular-devkit/core'; +import { getWorkspace } from '../utilities/config'; +import { + Arguments, + CommandContext, + CommandDescription, + CommandDescriptionMap, + CommandScope, + CommandWorkspace, + Option, SubCommandDescription, +} from './interface'; + +export interface BaseCommandOptions { + help?: boolean | string; +} + +export abstract class Command { + public allowMissingWorkspace = false; + public workspace: CommandWorkspace; + + protected static commandMap: CommandDescriptionMap; + static setCommandMap(map: CommandDescriptionMap) { + this.commandMap = map; + } + + constructor( + context: CommandContext, + public readonly description: CommandDescription, + protected readonly logger: logging.Logger, + ) { + this.workspace = context.workspace; + } + + async initialize(options: T & Arguments): Promise { + return; + } + + async printHelp(options: T & Arguments): Promise { + await this.printHelpUsage(); + await this.printHelpOptions(); + + return 0; + } + + async printJsonHelp(_options: T & Arguments): Promise { + this.logger.info(JSON.stringify(this.description)); + + return 0; + } + + protected async printHelpUsage() { + this.logger.info(this.description.description); + + const name = this.description.name; + const args = this.description.options.filter(x => x.positional !== undefined); + const opts = this.description.options.filter(x => x.positional === undefined); + + const argDisplay = args && args.length > 0 + ? ' ' + args.map(a => `<${a.name}>`).join(' ') + : ''; + const optionsDisplay = opts && opts.length > 0 + ? ` [options]` + : ``; + + this.logger.info(`usage: ng ${name}${argDisplay}${optionsDisplay}`); + this.logger.info(''); + } + + protected async printHelpSubcommand(subcommand: SubCommandDescription) { + this.logger.info(subcommand.description); + + await this.printHelpOptions(subcommand.options); + } + + protected async printHelpOptions(options: Option[] = this.description.options) { + const args = options.filter(opt => opt.positional !== undefined); + const opts = options.filter(opt => opt.positional === undefined); + + if (args.length > 0) { + this.logger.info(`arguments:`); + args.forEach(o => { + this.logger.info(` ${terminal.cyan(o.name)}`); + if (o.description) { + this.logger.info(` ${o.description}`); + } + }); + } + if (options.length > 0) { + if (args.length > 0) { + this.logger.info(''); + } + this.logger.info(`options:`); + opts + .filter(o => !o.hidden) + .sort((a, b) => a.name.localeCompare(b.name)) + .forEach(o => { + const aliases = o.aliases && o.aliases.length > 0 + ? '(' + o.aliases.map(a => `-${a}`).join(' ') + ')' + : ''; + this.logger.info(` ${terminal.cyan('--' + strings.dasherize(o.name))} ${aliases}`); + if (o.description) { + this.logger.info(` ${o.description}`); + } + }); + } + } + + async validateScope(scope?: CommandScope): Promise { + switch (scope === undefined ? this.description.scope : scope) { + case CommandScope.OutProject: + if (this.workspace.configFile) { + this.logger.fatal(tags.oneLine` + The ${this.description.name} command requires to be run outside of a project, but a + project definition was found at "${this.workspace.configFile}". + `); + throw 1; + } + break; + case CommandScope.InProject: + if (!this.workspace.configFile || getWorkspace('local') === null) { + this.logger.fatal(tags.oneLine` + The ${this.description.name} command requires to be run in an Angular project, but a + project definition could not be found. + `); + throw 1; + } + break; + case CommandScope.Everywhere: + // Can't miss this. + break; + } + } + + abstract async run(options: T & Arguments): Promise; + + async validateAndRun(options: T & Arguments): Promise { + if (!(options.help === true || options.help === 'json' || options.help === 'JSON')) { + await this.validateScope(); + } + await this.initialize(options); + + if (options.help === true) { + return this.printHelp(options); + } else if (options.help === 'json' || options.help === 'JSON') { + return this.printJsonHelp(options); + } else { + return await this.run(options); + } + } +} diff --git a/packages/angular/cli/models/error.ts b/packages/angular/cli/models/error.ts new file mode 100644 index 000000000000..5d9d323ed103 --- /dev/null +++ b/packages/angular/cli/models/error.ts @@ -0,0 +1,19 @@ +/** + * @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 + */ + +export class NgToolkitError extends Error { + constructor(message?: string) { + super(); + + if (message) { + this.message = message; + } else { + this.message = this.constructor.name; + } + } +} diff --git a/packages/angular/cli/models/interface.ts b/packages/angular/cli/models/interface.ts new file mode 100644 index 000000000000..26e88f4beb80 --- /dev/null +++ b/packages/angular/cli/models/interface.ts @@ -0,0 +1,227 @@ +/** + * @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 { json, logging } from '@angular-devkit/core'; + +/** + * Value type of arguments. + */ +export type Value = number | string | boolean | (number | string | boolean)[]; + +/** + * An object representing parsed arguments from the command line. + */ +export interface Arguments { + [argName: string]: Value | undefined; + + /** + * Extra arguments that were not parsed. Will be omitted if all arguments were parsed. + */ + '--'?: string[]; +} + +/** + * The base interface for Command, understood by the command runner. + */ +export interface CommandInterface { + printHelp(options: T): Promise; + printJsonHelp(options: T): Promise; + validateAndRun(options: T): Promise; +} + +/** + * Command constructor. + */ +export interface CommandConstructor { + new( + context: CommandContext, + description: CommandDescription, + logger: logging.Logger, + ): CommandInterface; +} + +/** + * A CLI workspace information. + */ +export interface CommandWorkspace { + root: string; + configFile?: string; +} + +/** + * A command runner context. + */ +export interface CommandContext { + workspace: CommandWorkspace; +} + +/** + * Value types of an Option. + */ +export enum OptionType { + Any = 'any', + Array = 'array', + Boolean = 'boolean', + Number = 'number', + String = 'string', +} + +/** + * An option description. This is exposed when using `ng --help=json`. + */ +export interface Option { + /** + * The name of the option. + */ + name: string; + + /** + * A short description of the option. + */ + description: string; + + /** + * The type of option value. If multiple types exist, this type will be the first one, and the + * types array will contain all types accepted. + */ + type: OptionType; + + /** + * {@see type} + */ + types?: OptionType[]; + + /** + * If this field is set, only values contained in this field are valid. This array can be mixed + * types (strings, numbers, boolean). For example, if this field is "enum: ['hello', true]", + * then "type" will be either string or boolean, types will be at least both, and the values + * accepted will only be either 'hello' or true (not false or any other string). + * This mean that prefixing with `no-` will not work on this field. + */ + enum?: Value[]; + + /** + * If this option maps to a subcommand in the parent command, will contain all the subcommands + * supported. There is a maximum of 1 subcommand Option per command, and the type of this + * option will always be "string" (no other types). The value of this option will map into + * this map and return the extra information. + */ + subcommands?: { + [name: string]: SubCommandDescription; + }; + + /** + * Aliases supported by this option. + */ + aliases: string[]; + + /** + * Whether this option is required or not. + */ + required?: boolean; + + /** + * Format field of this option. + */ + format?: string; + + /** + * Whether this option should be hidden from the help output. It will still show up in JSON help. + */ + hidden?: boolean; + + /** + * Default value of this option. + */ + default?: string | number | boolean; + + /** + * If this option can be used as an argument, the position of the argument. Otherwise omitted. + */ + positional?: number; + + /** + * Smart default object. + */ + $default?: OptionSmartDefault; +} + +/** + * Scope of the command. + */ +export enum CommandScope { + InProject = 'in', + OutProject = 'out', + Everywhere = 'all', + + Default = InProject, +} + +/** + * A description of a command and its options. + */ +export interface SubCommandDescription { + /** + * The name of the subcommand. + */ + name: string; + + /** + * Short description (1-2 lines) of this sub command. + */ + description: string; + + /** + * A long description of the sub command, in Markdown format. + */ + longDescription?: string; + + /** + * Additional notes about usage of this sub command, in Markdown format. + */ + usageNotes?: string; + + /** + * List of all supported options. + */ + options: Option[]; + + /** + * Aliases supported for this sub command. + */ + aliases: string[]; +} + +/** + * A description of a command, its metadata. + */ +export interface CommandDescription extends SubCommandDescription { + /** + * Scope of the command, whether it can be executed in a project, outside of a project or + * anywhere. + */ + scope: CommandScope; + + /** + * Whether this command should be hidden from a list of all commands. + */ + hidden: boolean; + + /** + * The constructor of the command, which should be extending the abstract Command<> class. + */ + impl: CommandConstructor; +} + +export interface OptionSmartDefault { + $source: string; + [key: string]: json.JsonValue; +} + +export interface CommandDescriptionMap { + [key: string]: CommandDescription; +} diff --git a/packages/angular/cli/models/parser.ts b/packages/angular/cli/models/parser.ts new file mode 100644 index 000000000000..9cba5e6355de --- /dev/null +++ b/packages/angular/cli/models/parser.ts @@ -0,0 +1,358 @@ +/** + * @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 { BaseException, strings } from '@angular-devkit/core'; +import { Arguments, Option, OptionType, Value } from './interface'; + + +export class ParseArgumentException extends BaseException { + constructor( + public readonly comments: string[], + public readonly parsed: Arguments, + public readonly ignored: string[], + ) { + super(`One or more errors occured while parsing arguments:\n ${comments.join('\n ')}`); + } +} + + +function _coerceType(str: string | undefined, type: OptionType, v?: Value): Value | undefined { + switch (type) { + case OptionType.Any: + if (Array.isArray(v)) { + return v.concat(str || ''); + } + + return _coerceType(str, OptionType.Boolean, v) !== undefined + ? _coerceType(str, OptionType.Boolean, v) + : _coerceType(str, OptionType.Number, v) !== undefined + ? _coerceType(str, OptionType.Number, v) + : _coerceType(str, OptionType.String, v); + + case OptionType.String: + return str || ''; + + case OptionType.Boolean: + switch (str) { + case 'false': + return false; + + case undefined: + case '': + case 'true': + return true; + + default: + return undefined; + } + + case OptionType.Number: + if (str === undefined) { + return 0; + } else if (str === '') { + return undefined; + } else if (Number.isFinite(+str)) { + return +str; + } else { + return undefined; + } + + case OptionType.Array: + return Array.isArray(v) ? v.concat(str || '') : [str || '']; + + default: + return undefined; + } +} + +function _coerce(str: string | undefined, o: Option | null, v?: Value): Value | undefined { + if (!o) { + return _coerceType(str, OptionType.Any, v); + } else { + const types = o.types || [o.type]; + + // Try all the types one by one and pick the first one that returns a value contained in the + // enum. If there's no enum, just return the first one that matches. + for (const type of types) { + const maybeResult = _coerceType(str, type, v); + if (maybeResult !== undefined) { + if (!o.enum || o.enum.includes(maybeResult)) { + return maybeResult; + } + } + } + + return undefined; + } +} + + +function _getOptionFromName(name: string, options: Option[]): Option | undefined { + const cName = strings.camelize(name); + + for (const option of options) { + if (option.name == name || option.name == cName) { + return option; + } + + if (option.aliases.some(x => x == name || x == cName)) { + return option; + } + } + + return undefined; +} + + +function _assignOption( + arg: string, + args: string[], + options: Option[], + parsedOptions: Arguments, + _positionals: string[], + leftovers: string[], + ignored: string[], + errors: string[], +) { + let key = arg.substr(2); + let option: Option | null = null; + let value = ''; + const i = arg.indexOf('='); + + // If flag is --no-abc AND there's no equal sign. + if (i == -1) { + if (key.startsWith('no-')) { + // Only use this key if the option matching the rest is a boolean. + const maybeOption = _getOptionFromName(key.substr(3), options); + if (maybeOption && maybeOption.type == 'boolean') { + value = 'false'; + option = maybeOption; + } + } else if (key.startsWith('no')) { + // Only use this key if the option matching the rest is a boolean. + const maybeOption = _getOptionFromName(key.substr(2), options); + if (maybeOption && maybeOption.type == 'boolean') { + value = 'false'; + option = maybeOption; + } + } + + if (option === null) { + // Set it to true if it's a boolean and the next argument doesn't match true/false. + const maybeOption = _getOptionFromName(key, options); + if (maybeOption) { + value = args[0]; + let shouldShift = true; + + if (value && value.startsWith('-')) { + // Verify if not having a value results in a correct parse, if so don't shift. + if (_coerce(undefined, maybeOption) !== undefined) { + shouldShift = false; + } + } + + // Only absorb it if it leads to a better value. + if (shouldShift && _coerce(value, maybeOption) !== undefined) { + args.shift(); + } else { + value = ''; + } + option = maybeOption; + } + } + } else { + key = arg.substring(0, i); + option = _getOptionFromName(key, options) || null; + if (option) { + value = arg.substring(i + 1); + } + } + if (option === null) { + if (args[0] && !args[0].startsWith('--')) { + leftovers.push(arg, args[0]); + args.shift(); + } else { + leftovers.push(arg); + } + } else { + const v = _coerce(value, option, parsedOptions[option.name]); + if (v !== undefined) { + parsedOptions[option.name] = v; + } else { + let error = `Argument ${key} could not be parsed using value ${JSON.stringify(value)}.`; + if (option.enum) { + error += ` Valid values are: ${option.enum.map(x => JSON.stringify(x)).join(', ')}.`; + } else { + error += `Valid type(s) is: ${(option.types || [option.type]).join(', ')}`; + } + + errors.push(error); + ignored.push(arg); + } + } +} + + +/** + * Parse the arguments in a consistent way, but without having any option definition. This tries + * to assess what the user wants in a free form. For example, using `--name=false` will set the + * name properties to a boolean type. + * This should only be used when there's no schema available or if a schema is "true" (anything is + * valid). + * + * @param args Argument list to parse. + * @returns An object that contains a property per flags from the args. + */ +export function parseFreeFormArguments(args: string[]): Arguments { + const parsedOptions: Arguments = {}; + const leftovers = []; + + for (let arg = args.shift(); arg !== undefined; arg = args.shift()) { + if (arg == '--') { + leftovers.push(...args); + break; + } + + if (arg.startsWith('--')) { + const eqSign = arg.indexOf('='); + let name: string; + let value: string | undefined; + if (eqSign !== -1) { + name = arg.substring(2, eqSign); + value = arg.substring(eqSign + 1); + } else { + name = arg.substr(2); + value = args.shift(); + } + + const v = _coerce(value, null, parsedOptions[name]); + if (v !== undefined) { + parsedOptions[name] = v; + } + } else if (arg.startsWith('-')) { + arg.split('').forEach(x => parsedOptions[x] = true); + } else { + leftovers.push(arg); + } + } + + parsedOptions['--'] = leftovers; + + return parsedOptions; +} + + +/** + * Parse the arguments in a consistent way, from a list of standardized options. + * The result object will have a key per option name, with the `_` key reserved for positional + * arguments, and `--` will contain everything that did not match. Any key that don't have an + * option will be pushed back in `--` and removed from the object. If you need to validate that + * there's no additionalProperties, you need to check the `--` key. + * + * @param args The argument array to parse. + * @param options List of supported options. {@see Option}. + * @returns An object that contains a property per option. + */ +export function parseArguments(args: string[], options: Option[] | null): Arguments { + if (options === null) { + options = []; + } + + const leftovers: string[] = []; + const positionals: string[] = []; + const parsedOptions: Arguments = {}; + + const ignored: string[] = []; + const errors: string[] = []; + + for (let arg = args.shift(); arg !== undefined; arg = args.shift()) { + if (arg == '--') { + // If we find a --, we're done. + leftovers.push(...args); + break; + } + + if (arg.startsWith('--')) { + _assignOption(arg, args, options, parsedOptions, positionals, leftovers, ignored, errors); + } else if (arg.startsWith('-')) { + // Argument is of form -abcdef. Starts at 1 because we skip the `-`. + for (let i = 1; i < arg.length; i++) { + const flag = arg[i]; + // If the next character is an '=', treat it as a long flag. + if (arg[i + 1] == '=') { + const f = '--' + flag + arg.slice(i + 1); + _assignOption(f, args, options, parsedOptions, positionals, leftovers, ignored, errors); + break; + } + // Treat the last flag as `--a` (as if full flag but just one letter). We do this in + // the loop because it saves us a check to see if the arg is just `-`. + if (i == arg.length - 1) { + const arg = '--' + flag; + _assignOption(arg, args, options, parsedOptions, positionals, leftovers, ignored, errors); + } else { + const maybeOption = _getOptionFromName(flag, options); + if (maybeOption) { + const v = _coerce(undefined, maybeOption, parsedOptions[maybeOption.name]); + if (v !== undefined) { + parsedOptions[maybeOption.name] = v; + } + } + } + } + } else { + positionals.push(arg); + } + } + + // Deal with positionals. + // TODO(hansl): this is by far the most complex piece of code in this file. Try to refactor it + // simpler. + if (positionals.length > 0) { + let pos = 0; + for (let i = 0; i < positionals.length;) { + let found = false; + let incrementPos = false; + let incrementI = true; + + // We do this with a found flag because more than 1 option could have the same positional. + for (const option of options) { + // If any option has this positional and no value, AND fit the type, we need to remove it. + if (option.positional === pos) { + const coercedValue = _coerce(positionals[i], option, parsedOptions[option.name]); + if (parsedOptions[option.name] === undefined && coercedValue !== undefined) { + parsedOptions[option.name] = coercedValue; + found = true; + } else { + incrementI = false; + } + incrementPos = true; + } + } + + if (found) { + positionals.splice(i--, 1); + } + if (incrementPos) { + pos++; + } + if (incrementI) { + i++; + } + } + } + + if (positionals.length > 0 || leftovers.length > 0) { + parsedOptions['--'] = [...positionals, ...leftovers]; + } + + if (errors.length > 0) { + throw new ParseArgumentException(errors, parsedOptions, ignored); + } + + return parsedOptions; +} diff --git a/packages/angular/cli/models/parser_spec.ts b/packages/angular/cli/models/parser_spec.ts new file mode 100644 index 000000000000..dbec3d2712d6 --- /dev/null +++ b/packages/angular/cli/models/parser_spec.ts @@ -0,0 +1,152 @@ +/** + * @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 { Arguments, Option, OptionType } from './interface'; +import { ParseArgumentException, parseArguments } from './parser'; + +describe('parseArguments', () => { + const options: Option[] = [ + { name: 'bool', aliases: [ 'b' ], type: OptionType.Boolean, description: '' }, + { name: 'num', aliases: [ 'n' ], type: OptionType.Number, description: '' }, + { name: 'str', aliases: [ 's' ], type: OptionType.String, description: '' }, + { name: 'helloWorld', aliases: [], type: OptionType.String, description: '' }, + { name: 'helloBool', aliases: [], type: OptionType.Boolean, description: '' }, + { name: 'arr', aliases: [ 'a' ], type: OptionType.Array, description: '' }, + { name: 'p1', positional: 0, aliases: [], type: OptionType.String, description: '' }, + { name: 'p2', positional: 1, aliases: [], type: OptionType.String, description: '' }, + { name: 'p3', positional: 2, aliases: [], type: OptionType.Number, description: '' }, + { name: 't1', aliases: [], type: OptionType.Boolean, + types: [OptionType.Boolean, OptionType.String], description: '' }, + { name: 't2', aliases: [], type: OptionType.Boolean, + types: [OptionType.Boolean, OptionType.Number], description: '' }, + { name: 't3', aliases: [], type: OptionType.Number, + types: [OptionType.Number, OptionType.Any], description: '' }, + { name: 'e1', aliases: [], type: OptionType.String, enum: ['hello', 'world'], description: '' }, + { name: 'e2', aliases: [], type: OptionType.String, enum: ['hello', ''], description: '' }, + { name: 'e3', aliases: [], type: OptionType.Boolean, + types: [OptionType.Boolean, OptionType.String], enum: ['json', true, false], + description: '' }, + ]; + + const tests: { [test: string]: Partial | ['!!!', Partial, string[]] } = { + '--bool': { bool: true }, + '--bool=1': ['!!!', {}, ['--bool=1']], + '--bool ': { bool: true, p1: '' }, + '-- --bool=1': { '--': ['--bool=1'] }, + '--bool=yellow': ['!!!', {}, ['--bool=yellow']], + '--bool=true': { bool: true }, + '--bool=false': { bool: false }, + '--no-bool': { bool: false }, + '--no-bool=true': { '--': ['--no-bool=true'] }, + '--b=true': { bool: true }, + '--b=false': { bool: false }, + '--b true': { bool: true }, + '--b false': { bool: false }, + '--bool --num': { bool: true, num: 0 }, + '--bool --num=true': ['!!!', { bool: true }, ['--num=true']], + '-- --bool --num=true': { '--': ['--bool', '--num=true'] }, + '--bool=true --num': { bool: true, num: 0 }, + '--bool true --num': { bool: true, num: 0 }, + '--bool=false --num': { bool: false, num: 0 }, + '--bool false --num': { bool: false, num: 0 }, + '--str false --num': { str: 'false', num: 0 }, + '--str=false --num': { str: 'false', num: 0 }, + '--str=false --num1': { str: 'false', '--': ['--num1'] }, + '--str=false val1 --num1': { str: 'false', p1: 'val1', '--': ['--num1'] }, + '--str=false val1 val2': { str: 'false', p1: 'val1', p2: 'val2' }, + '--str=false val1 val2 --num1': { str: 'false', p1: 'val1', p2: 'val2', '--': ['--num1'] }, + '--str=false val1 --num1 val2': { str: 'false', p1: 'val1', '--': ['--num1', 'val2'] }, + 'val1 --num=1 val2': { num: 1, p1: 'val1', p2: 'val2' }, + '--p1=val1 --num=1 val2': { num: 1, p1: 'val1', p2: 'val2' }, + '--p1=val1 --num=1 --p2=val2 val3': { num: 1, p1: 'val1', p2: 'val2', '--': ['val3'] }, + '--bool val1 --etc --num val2 --v': [ + '!!!', + { bool: true, p1: 'val1', p2: 'val2', '--': ['--etc', '--v'] }, + ['--num' ], + ], + '--bool val1 --etc --num=1 val2 --v': { bool: true, num: 1, p1: 'val1', p2: 'val2', + '--': ['--etc', '--v'] }, + '--arr=a --arr=b --arr c d': { arr: ['a', 'b', 'c'], p1: 'd' }, + '--arr=1 --arr --arr c d': { arr: ['1', '', 'c'], p1: 'd' }, + '--arr=1 --arr --arr c d e': { arr: ['1', '', 'c'], p1: 'd', p2: 'e' }, + '--str=1': { str: '1' }, + '--str=': { str: '' }, + '--str ': { str: '' }, + '--str ': { str: '', p1: '' }, + '--str ': { str: '', p1: '', p2: '', '--': [''] }, + '--hello-world=1': { helloWorld: '1' }, + '--hello-bool': { helloBool: true }, + '--helloBool': { helloBool: true }, + '--no-helloBool': { helloBool: false }, + '--noHelloBool': { helloBool: false }, + '--noBool': { bool: false }, + '-b': { bool: true }, + '-b=true': { bool: true }, + '-sb': { bool: true, str: '' }, + '-s=b': { str: 'b' }, + '-bs': { bool: true, str: '' }, + '--t1=true': { t1: true }, + '--t1': { t1: true }, + '--t1 --num': { t1: true, num: 0 }, + '--no-t1': { t1: false }, + '--t1=yellow': { t1: 'yellow' }, + '--no-t1=true': { '--': ['--no-t1=true'] }, + '--t1=123': { t1: '123' }, + '--t2=true': { t2: true }, + '--t2': { t2: true }, + '--no-t2': { t2: false }, + '--t2=yellow': ['!!!', {}, ['--t2=yellow']], + '--no-t2=true': { '--': ['--no-t2=true'] }, + '--t2=123': { t2: 123 }, + '--t3=a': { t3: 'a' }, + '--t3': { t3: 0 }, + '--t3 true': { t3: true }, + '--e1 hello': { e1: 'hello' }, + '--e1=hello': { e1: 'hello' }, + '--e1 yellow': ['!!!', { p1: 'yellow' }, ['--e1']], + '--e1=yellow': ['!!!', {}, ['--e1=yellow']], + '--e1': ['!!!', {}, ['--e1']], + '--e1 true': ['!!!', { p1: 'true' }, ['--e1']], + '--e1=true': ['!!!', {}, ['--e1=true']], + '--e2 hello': { e2: 'hello' }, + '--e2=hello': { e2: 'hello' }, + '--e2 yellow': { p1: 'yellow', e2: '' }, + '--e2=yellow': ['!!!', {}, ['--e2=yellow']], + '--e2': { e2: '' }, + '--e2 true': { p1: 'true', e2: '' }, + '--e2=true': ['!!!', {}, ['--e2=true']], + '--e3 json': { e3: 'json' }, + '--e3=json': { e3: 'json' }, + '--e3 yellow': { p1: 'yellow', e3: true }, + '--e3=yellow': ['!!!', {}, ['--e3=yellow']], + '--e3': { e3: true }, + '--e3 true': { e3: true }, + '--e3=true': { e3: true }, + 'a b c 1': { p1: 'a', p2: 'b', '--': ['c', '1'] }, + }; + + Object.entries(tests).forEach(([str, expected]) => { + it(`works for ${str}`, () => { + try { + const actual = parseArguments(str.split(' '), options); + + expect(Array.isArray(expected)).toBe(false); + expect(actual).toEqual(expected as Arguments); + } catch (e) { + if (!(e instanceof ParseArgumentException)) { + throw e; + } + + // The expected values are an array. + expect(Array.isArray(expected)).toBe(true); + expect(e.parsed).toEqual(expected[1] as Arguments); + expect(e.ignored).toEqual(expected[2] as string[]); + } + }); + }); +}); diff --git a/packages/angular/cli/models/schematic-command.ts b/packages/angular/cli/models/schematic-command.ts new file mode 100644 index 000000000000..1b52865ee85c --- /dev/null +++ b/packages/angular/cli/models/schematic-command.ts @@ -0,0 +1,564 @@ +/** + * @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 { + experimental, + json, + logging, + normalize, + schema, + strings, + tags, + terminal, + virtualFs, +} from '@angular-devkit/core'; +import { NodeJsSyncHost } from '@angular-devkit/core/node'; +import { + DryRunEvent, + Engine, + SchematicEngine, + UnsuccessfulWorkflowExecution, + workflow, +} from '@angular-devkit/schematics'; +import { + FileSystemCollection, + FileSystemCollectionDesc, + FileSystemEngineHostBase, + FileSystemSchematic, + FileSystemSchematicDesc, + NodeModulesEngineHost, + NodeWorkflow, + validateOptionsWithSchema, +} from '@angular-devkit/schematics/tools'; +import * as inquirer from 'inquirer'; +import * as systemPath from 'path'; +import { take } from 'rxjs/operators'; +import { WorkspaceLoader } from '../models/workspace-loader'; +import { + getPackageManager, + getProjectByCwd, + getSchematicDefaults, + getWorkspace, + getWorkspaceRaw, +} from '../utilities/config'; +import { parseJsonSchemaToOptions } from '../utilities/json-schema'; +import { BaseCommandOptions, Command } from './command'; +import { Arguments, CommandContext, CommandDescription, Option } from './interface'; +import { parseArguments, parseFreeFormArguments } from './parser'; + + +export interface BaseSchematicSchema { + debug?: boolean; + dryRun?: boolean; + force?: boolean; + interactive?: boolean; + defaults?: boolean; +} + +export interface RunSchematicOptions extends BaseSchematicSchema { + collectionName: string; + schematicName: string; + + schematicOptions?: string[]; + showNothingDone?: boolean; +} + + +export class UnknownCollectionError extends Error { + constructor(collectionName: string) { + super(`Invalid collection (${collectionName}).`); + } +} + +export abstract class SchematicCommand< + T extends (BaseSchematicSchema & BaseCommandOptions), +> extends Command { + readonly allowPrivateSchematics: boolean = false; + private _host = new NodeJsSyncHost(); + private _workspace: experimental.workspace.Workspace; + private readonly _engine: Engine; + protected _workflow: workflow.BaseWorkflow; + + protected collectionName = '@schematics/angular'; + protected schematicName?: string; + + constructor( + context: CommandContext, + description: CommandDescription, + logger: logging.Logger, + private readonly _engineHost: FileSystemEngineHostBase = new NodeModulesEngineHost(), + ) { + super(context, description, logger); + this._engine = new SchematicEngine(this._engineHost); + } + + public async initialize(options: T & Arguments) { + this._loadWorkspace(); + this.createWorkflow(options); + + if (this.schematicName) { + // Set the options. + const collection = this.getCollection(this.collectionName); + const schematic = this.getSchematic(collection, this.schematicName, true); + const options = await parseJsonSchemaToOptions( + this._workflow.registry, + schematic.description.schemaJson || {}, + ); + + this.description.options.push(...options.filter(x => !x.hidden)); + } + } + + public async printHelp(options: T & Arguments) { + await super.printHelp(options); + this.logger.info(''); + + const subCommandOption = this.description.options.filter(x => x.subcommands)[0]; + + if (!subCommandOption || !subCommandOption.subcommands) { + return 0; + } + + const schematicNames = Object.keys(subCommandOption.subcommands); + + if (schematicNames.length > 1) { + this.logger.info('Available Schematics:'); + + const namesPerCollection: { [c: string]: string[] } = {}; + schematicNames.forEach(name => { + let [collectionName, schematicName] = name.split(/:/, 2); + if (!schematicName) { + schematicName = collectionName; + collectionName = this.collectionName; + } + + if (!namesPerCollection[collectionName]) { + namesPerCollection[collectionName] = []; + } + + namesPerCollection[collectionName].push(schematicName); + }); + + const defaultCollection = this.getDefaultSchematicCollection(); + Object.keys(namesPerCollection).forEach(collectionName => { + const isDefault = defaultCollection == collectionName; + this.logger.info( + ` Collection "${collectionName}"${isDefault ? ' (default)' : ''}:`, + ); + + namesPerCollection[collectionName].forEach(schematicName => { + this.logger.info(` ${schematicName}`); + }); + }); + } else if (schematicNames.length == 1) { + this.logger.info('Help for schematic ' + schematicNames[0]); + await this.printHelpSubcommand(subCommandOption.subcommands[schematicNames[0]]); + } + + return 0; + } + + async printHelpUsage() { + const subCommandOption = this.description.options.filter(x => x.subcommands)[0]; + + if (!subCommandOption || !subCommandOption.subcommands) { + return; + } + + const schematicNames = Object.keys(subCommandOption.subcommands); + if (schematicNames.length == 1) { + this.logger.info(this.description.description); + + const opts = this.description.options.filter(x => x.positional === undefined); + const [collectionName, schematicName] = schematicNames[0].split(/:/)[0]; + + // Display if this is not the default collectionName, + // otherwise just show the schematicName. + const displayName = collectionName == this.getDefaultSchematicCollection() + ? schematicName + : schematicNames[0]; + + const schematicOptions = subCommandOption.subcommands[schematicNames[0]].options; + const schematicArgs = schematicOptions.filter(x => x.positional !== undefined); + const argDisplay = schematicArgs.length > 0 + ? ' ' + schematicArgs.map(a => `<${strings.dasherize(a.name)}>`).join(' ') + : ''; + + this.logger.info(tags.oneLine` + usage: ng ${this.description.name} ${displayName}${argDisplay} + ${opts.length > 0 ? `[options]` : ``} + `); + this.logger.info(''); + } else { + await super.printHelpUsage(); + } + } + + protected getEngineHost() { + return this._engineHost; + } + protected getEngine(): + Engine { + return this._engine; + } + + protected getCollection(collectionName: string): FileSystemCollection { + const engine = this.getEngine(); + const collection = engine.createCollection(collectionName); + + if (collection === null) { + throw new UnknownCollectionError(collectionName); + } + + return collection; + } + + protected getSchematic( + collection: FileSystemCollection, + schematicName: string, + allowPrivate?: boolean, + ): FileSystemSchematic { + return collection.createSchematic(schematicName, allowPrivate); + } + + protected setPathOptions(options: Option[], workingDir: string) { + if (workingDir === '') { + return {}; + } + + return options + .filter(o => o.format === 'path') + .map(o => o.name) + .reduce((acc, curr) => { + acc[curr] = workingDir; + + return acc; + }, {} as { [name: string]: string }); + } + + /* + * Runtime hook to allow specifying customized workflow + */ + protected createWorkflow(options: BaseSchematicSchema): workflow.BaseWorkflow { + if (this._workflow) { + return this._workflow; + } + + const { force, dryRun } = options; + const fsHost = new virtualFs.ScopedHost(new NodeJsSyncHost(), normalize(this.workspace.root)); + + const workflow = new NodeWorkflow( + fsHost, + { + force, + dryRun, + packageManager: getPackageManager(), + root: normalize(this.workspace.root), + }, + ); + + this._engineHost.registerOptionsTransform(validateOptionsWithSchema(workflow.registry)); + + if (options.defaults) { + workflow.registry.addPreTransform(schema.transforms.addUndefinedDefaults); + } else { + workflow.registry.addPostTransform(schema.transforms.addUndefinedDefaults); + } + + workflow.registry.addSmartDefaultProvider('projectName', () => { + if (this._workspace) { + try { + return this._workspace.getProjectByPath(normalize(process.cwd())) + || this._workspace.getDefaultProjectName(); + } catch (e) { + if (e instanceof experimental.workspace.AmbiguousProjectPathException) { + this.logger.warn(tags.oneLine` + Two or more projects are using identical roots. + Unable to determine project using current working directory. + Using default workspace project instead. + `); + + return this._workspace.getDefaultProjectName(); + } + throw e; + } + } + + return undefined; + }); + + if (options.interactive !== false && process.stdout.isTTY) { + workflow.registry.usePromptProvider((definitions: Array) => { + const questions: inquirer.Questions = definitions.map(definition => { + const question: inquirer.Question = { + name: definition.id, + message: definition.message, + default: definition.default, + }; + + const validator = definition.validator; + if (validator) { + question.validate = input => validator(input); + } + + switch (definition.type) { + case 'confirmation': + question.type = 'confirm'; + break; + case 'list': + question.type = 'list'; + question.choices = definition.items && definition.items.map(item => { + if (typeof item == 'string') { + return item; + } else { + return { + name: item.label, + value: item.value, + }; + } + }); + break; + default: + question.type = definition.type; + break; + } + + return question; + }); + + return inquirer.prompt(questions); + }); + } + + return this._workflow = workflow; + } + + protected getDefaultSchematicCollection(): string { + let workspace = getWorkspace('local'); + + if (workspace) { + const project = getProjectByCwd(workspace); + if (project && workspace.getProjectCli(project)) { + const value = workspace.getProjectCli(project)['defaultCollection']; + if (typeof value == 'string') { + return value; + } + } + if (workspace.getCli()) { + const value = workspace.getCli()['defaultCollection']; + if (typeof value == 'string') { + return value; + } + } + } + + workspace = getWorkspace('global'); + if (workspace && workspace.getCli()) { + const value = workspace.getCli()['defaultCollection']; + if (typeof value == 'string') { + return value; + } + } + + return this.collectionName; + } + + protected async runSchematic(options: RunSchematicOptions) { + const { schematicOptions, debug, dryRun } = options; + let { collectionName, schematicName } = options; + + let nothingDone = true; + let loggingQueue: string[] = []; + let error = false; + + const workflow = this._workflow; + + const workingDir = normalize(systemPath.relative(this.workspace.root, process.cwd())); + + // Get the option object from the schematic schema. + const schematic = this.getSchematic( + this.getCollection(collectionName), + schematicName, + this.allowPrivateSchematics, + ); + // Update the schematic and collection name in case they're not the same as the ones we + // received in our options, e.g. after alias resolution or extension. + collectionName = schematic.collection.description.name; + schematicName = schematic.description.name; + + // TODO: Remove warning check when 'targets' is default + if (collectionName !== this.collectionName) { + const [ast, configPath] = getWorkspaceRaw('local'); + if (ast) { + const projectsKeyValue = ast.properties.find(p => p.key.value === 'projects'); + if (!projectsKeyValue || projectsKeyValue.value.kind !== 'object') { + return; + } + + const positions: json.Position[] = []; + for (const projectKeyValue of projectsKeyValue.value.properties) { + const projectNode = projectKeyValue.value; + if (projectNode.kind !== 'object') { + continue; + } + const targetsKeyValue = projectNode.properties.find(p => p.key.value === 'targets'); + if (targetsKeyValue) { + positions.push(targetsKeyValue.start); + } + } + + if (positions.length > 0) { + const warning = tags.oneLine` + WARNING: This command may not execute successfully. + The package/collection may not support the 'targets' field within '${configPath}'. + This can be corrected by renaming the following 'targets' fields to 'architect': + `; + + const locations = positions + .map((p, i) => `${i + 1}) Line: ${p.line + 1}; Column: ${p.character + 1}`) + .join('\n'); + + this.logger.warn(warning + '\n' + locations + '\n'); + } + } + } + + // Set the options of format "path". + let o: Option[] | null = null; + let args: Arguments; + + if (!schematic.description.schemaJson) { + args = await this.parseFreeFormArguments(schematicOptions || []); + } else { + o = await parseJsonSchemaToOptions(workflow.registry, schematic.description.schemaJson); + args = await this.parseArguments(schematicOptions || [], o); + } + + const pathOptions = o ? this.setPathOptions(o, workingDir) : {}; + let input = Object.assign(pathOptions, args); + + // Read the default values from the workspace. + const projectName = input.project !== undefined ? '' + input.project : null; + const defaults = getSchematicDefaults(collectionName, schematicName, projectName); + input = Object.assign<{}, {}, typeof input>({}, defaults, input); + + workflow.reporter.subscribe((event: DryRunEvent) => { + nothingDone = false; + + // Strip leading slash to prevent confusion. + const eventPath = event.path.startsWith('/') ? event.path.substr(1) : event.path; + + switch (event.kind) { + case 'error': + error = true; + const desc = event.description == 'alreadyExist' ? 'already exists' : 'does not exist.'; + this.logger.warn(`ERROR! ${eventPath} ${desc}.`); + break; + case 'update': + loggingQueue.push(tags.oneLine` + ${terminal.white('UPDATE')} ${eventPath} (${event.content.length} bytes) + `); + break; + case 'create': + loggingQueue.push(tags.oneLine` + ${terminal.green('CREATE')} ${eventPath} (${event.content.length} bytes) + `); + break; + case 'delete': + loggingQueue.push(`${terminal.yellow('DELETE')} ${eventPath}`); + break; + case 'rename': + loggingQueue.push(`${terminal.blue('RENAME')} ${eventPath} => ${event.to}`); + break; + } + }); + + workflow.lifeCycle.subscribe(event => { + if (event.kind == 'end' || event.kind == 'post-tasks-start') { + if (!error) { + // Output the logging queue, no error happened. + loggingQueue.forEach(log => this.logger.info(log)); + } + + loggingQueue = []; + error = false; + } + }); + + return new Promise((resolve) => { + workflow.execute({ + collection: collectionName, + schematic: schematicName, + options: input, + debug: debug, + logger: this.logger, + allowPrivate: this.allowPrivateSchematics, + }) + .subscribe({ + error: (err: Error) => { + // In case the workflow was not successful, show an appropriate error message. + if (err instanceof UnsuccessfulWorkflowExecution) { + // "See above" because we already printed the error. + this.logger.fatal('The Schematic workflow failed. See above.'); + } else if (debug) { + this.logger.fatal(`An error occured:\n${err.message}\n${err.stack}`); + } else { + this.logger.fatal(err.message); + } + + resolve(1); + }, + complete: () => { + const showNothingDone = !(options.showNothingDone === false); + if (nothingDone && showNothingDone) { + this.logger.info('Nothing to be done.'); + } + if (dryRun) { + this.logger.warn(`\nNOTE: The "dryRun" flag means no changes were made.`); + } + resolve(); + }, + }); + }); + } + + protected async parseFreeFormArguments(schematicOptions: string[]) { + return parseFreeFormArguments(schematicOptions); + } + + protected async parseArguments( + schematicOptions: string[], + options: Option[] | null, + ): Promise { + return parseArguments(schematicOptions, options); + } + + private _loadWorkspace() { + if (this._workspace) { + return; + } + const workspaceLoader = new WorkspaceLoader(this._host); + + try { + workspaceLoader.loadWorkspace(this.workspace.root).pipe(take(1)) + .subscribe( + (workspace: experimental.workspace.Workspace) => this._workspace = workspace, + (err: Error) => { + if (!this.allowMissingWorkspace) { + // Ignore missing workspace + throw err; + } + }, + ); + } catch (err) { + if (!this.allowMissingWorkspace) { + // Ignore missing workspace + throw err; + } + } + } +} diff --git a/packages/angular/cli/models/workspace-loader.ts b/packages/angular/cli/models/workspace-loader.ts new file mode 100644 index 000000000000..e8785f7dc209 --- /dev/null +++ b/packages/angular/cli/models/workspace-loader.ts @@ -0,0 +1,92 @@ +/** + * @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 { + Path, + basename, + dirname, + experimental, + join, + normalize, + virtualFs, +} from '@angular-devkit/core'; +import * as fs from 'fs'; +import { homedir } from 'os'; +import { Observable, of } from 'rxjs'; +import { concatMap, tap } from 'rxjs/operators'; +import { findUp } from '../utilities/find-up'; + + +// TODO: error out instead of returning null when workspace cannot be found. +export class WorkspaceLoader { + private _workspaceCacheMap = new Map(); + // TODO: add remaining fallbacks. + private _configFileNames = [ + normalize('.angular.json'), + normalize('angular.json'), + ]; + constructor(private _host: virtualFs.Host) { } + + loadGlobalWorkspace(): Observable { + return this._getGlobalWorkspaceFilePath().pipe( + concatMap(globalWorkspacePath => this._loadWorkspaceFromPath(globalWorkspacePath)), + ); + } + + loadWorkspace(projectPath?: string): Observable { + return this._getProjectWorkspaceFilePath(projectPath).pipe( + concatMap(globalWorkspacePath => this._loadWorkspaceFromPath(globalWorkspacePath)), + ); + } + + // TODO: do this with the host instead of fs. + private _getProjectWorkspaceFilePath(projectPath?: string): Observable { + // Find the workspace file, either where specified, in the Angular CLI project + // (if it's in node_modules) or from the current process. + const workspaceFilePath = (projectPath && findUp(this._configFileNames, projectPath)) + || findUp(this._configFileNames, process.cwd()) + || findUp(this._configFileNames, __dirname); + + if (workspaceFilePath) { + return of(normalize(workspaceFilePath)); + } else { + throw new Error(`Local workspace file ('angular.json') could not be found.`); + } + } + + // TODO: do this with the host instead of fs. + private _getGlobalWorkspaceFilePath(): Observable { + for (const fileName of this._configFileNames) { + const workspaceFilePath = join(normalize(homedir()), fileName); + + if (fs.existsSync(workspaceFilePath)) { + return of(normalize(workspaceFilePath)); + } + } + + return of(null); + } + + private _loadWorkspaceFromPath(workspacePath: Path | null) { + if (!workspacePath) { + return of(null); + } + + if (this._workspaceCacheMap.has(workspacePath)) { + return of(this._workspaceCacheMap.get(workspacePath) || null); + } + + const workspaceRoot = dirname(workspacePath); + const workspaceFileName = basename(workspacePath); + const workspace = new experimental.workspace.Workspace(workspaceRoot, this._host); + + return workspace.loadWorkspaceFromHost(workspaceFileName).pipe( + tap(workspace => this._workspaceCacheMap.set(workspacePath, workspace)), + ); + } +} diff --git a/packages/angular/cli/package.json b/packages/angular/cli/package.json new file mode 100644 index 000000000000..30f604f522d9 --- /dev/null +++ b/packages/angular/cli/package.json @@ -0,0 +1,43 @@ +{ + "name": "@angular/cli", + "version": "0.0.0", + "description": "CLI tool for Angular", + "main": "lib/cli/index.js", + "trackingCode": "UA-8594346-19", + "bin": { + "ng": "./bin/ng" + }, + "keywords": [ + "angular", + "angular-cli", + "Angular CLI" + ], + "scripts": { + "postinstall": "node ./bin/ng-update-message.js" + }, + "repository": { + "type": "git", + "url": "https://github.com/angular/angular-cli.git" + }, + "author": "Angular Authors", + "license": "MIT", + "bugs": { + "url": "https://github.com/angular/angular-cli/issues" + }, + "homepage": "https://github.com/angular/angular-cli", + "dependencies": { + "@angular-devkit/architect": "0.0.0", + "@angular-devkit/core": "0.0.0", + "@angular-devkit/schematics": "0.0.0", + "@schematics/angular": "0.0.0", + "@schematics/update": "0.0.0", + "inquirer": "6.2.0", + "opn": "5.3.0", + "rxjs": "6.3.3", + "semver": "5.5.1", + "symbol-observable": "1.2.0" + }, + "ng-update": { + "migrations": "@schematics/angular/migrations/migration-collection.json" + } +} diff --git a/packages/angular/cli/plugins/karma.js b/packages/angular/cli/plugins/karma.js new file mode 100644 index 000000000000..821352a15b43 --- /dev/null +++ b/packages/angular/cli/plugins/karma.js @@ -0,0 +1,4 @@ +throw new Error( + 'In Angular CLI >6.0 the Karma plugin is now exported by "@angular-devkit/build-angular" instead.\n' + + 'Please replace "@angular/cli" with "@angular-devkit/build-angular" in your "karma.conf.js" file.' +); diff --git a/packages/angular/cli/tasks/npm-install.ts b/packages/angular/cli/tasks/npm-install.ts new file mode 100644 index 000000000000..243587054b88 --- /dev/null +++ b/packages/angular/cli/tasks/npm-install.ts @@ -0,0 +1,80 @@ +/** + * @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 { logging, terminal } from '@angular-devkit/core'; +import { ModuleNotFoundException, resolve } from '@angular-devkit/core/node'; +import { spawn } from 'child_process'; + + +export type NpmInstall = (packageName: string, + logger: logging.Logger, + packageManager: string, + projectRoot: string, + save?: boolean) => Promise; + +export default async function (packageName: string, + logger: logging.Logger, + packageManager: string, + projectRoot: string, + save = true) { + const installArgs: string[] = []; + switch (packageManager) { + case 'cnpm': + case 'npm': + installArgs.push('install', '--quiet'); + break; + + case 'yarn': + installArgs.push('add'); + break; + + default: + packageManager = 'npm'; + installArgs.push('install', '--quiet'); + break; + } + + logger.info(terminal.green(`Installing packages for tooling via ${packageManager}.`)); + + if (packageName) { + try { + // Verify if we need to install the package (it might already be there). + // If it's available and we shouldn't save, simply return. Nothing to be done. + resolve(packageName, { checkLocal: true, basedir: projectRoot }); + + return; + } catch (e) { + if (!(e instanceof ModuleNotFoundException)) { + throw e; + } + } + installArgs.push(packageName); + } + + if (!save) { + installArgs.push('--no-save'); + } + const installOptions = { + stdio: 'inherit', + shell: true, + }; + + await new Promise((resolve, reject) => { + spawn(packageManager, installArgs, installOptions) + .on('close', (code: number) => { + if (code === 0) { + logger.info(terminal.green(`Installed packages for tooling via ${packageManager}.`)); + resolve(); + } else { + const message = 'Package install failed, see above.'; + logger.info(terminal.red(message)); + reject(message); + } + }); + }); +} diff --git a/packages/angular/cli/upgrade/version.ts b/packages/angular/cli/upgrade/version.ts new file mode 100644 index 000000000000..89e013a0f795 --- /dev/null +++ b/packages/angular/cli/upgrade/version.ts @@ -0,0 +1,176 @@ +/** + * @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 { tags, terminal } from '@angular-devkit/core'; +import { resolve } from '@angular-devkit/core/node'; +import * as path from 'path'; +import { SemVer, satisfies } from 'semver'; +import { isWarningEnabled } from '../utilities/config'; + + +export class Version { + private _semver: SemVer | null = null; + constructor(private _version: string | null = null) { + this._semver = _version ? new SemVer(_version) : null; + } + + isAlpha() { return this.qualifier == 'alpha'; } + isBeta() { return this.qualifier == 'beta'; } + isReleaseCandidate() { return this.qualifier == 'rc'; } + isKnown() { return this._version !== null; } + + isLocal() { return this.isKnown() && this._version && path.isAbsolute(this._version); } + isGreaterThanOrEqualTo(other: SemVer) { + return this._semver !== null && this._semver.compare(other) >= 0; + } + + get major() { return this._semver ? this._semver.major : 0; } + get minor() { return this._semver ? this._semver.minor : 0; } + get patch() { return this._semver ? this._semver.patch : 0; } + get qualifier() { return this._semver ? this._semver.prerelease[0] : ''; } + get extra() { return this._semver ? this._semver.prerelease[1] : ''; } + + toString() { return this._version; } + + static assertCompatibleAngularVersion(projectRoot: string) { + let angularPkgJson; + let rxjsPkgJson; + + try { + const resolveOptions = { + basedir: projectRoot, + checkGlobal: false, + checkLocal: true, + }; + const angularPackagePath = resolve('@angular/core/package.json', resolveOptions); + const rxjsPackagePath = resolve('rxjs/package.json', resolveOptions); + + angularPkgJson = require(angularPackagePath); + rxjsPkgJson = require(rxjsPackagePath); + } catch { + console.error(terminal.bold(terminal.red(tags.stripIndents` + You seem to not be depending on "@angular/core" and/or "rxjs". This is an error. + `))); + process.exit(2); + } + + if (!(angularPkgJson && angularPkgJson['version'] && rxjsPkgJson && rxjsPkgJson['version'])) { + console.error(terminal.bold(terminal.red(tags.stripIndents` + Cannot determine versions of "@angular/core" and/or "rxjs". + This likely means your local installation is broken. Please reinstall your packages. + `))); + process.exit(2); + } + + const angularVersion = new Version(angularPkgJson['version']); + const rxjsVersion = new Version(rxjsPkgJson['version']); + + if (angularVersion.isLocal()) { + console.error(terminal.yellow('Using a local version of angular. Proceeding with care...')); + + return; + } + + if (!angularVersion.isGreaterThanOrEqualTo(new SemVer('5.0.0'))) { + console.error(terminal.bold(terminal.red(tags.stripIndents` + This version of CLI is only compatible with Angular version 5.0.0 or higher. + + Please visit the link below to find instructions on how to update Angular. + https://angular-update-guide.firebaseapp.com/ + ` + '\n'))); + process.exit(3); + } else if ( + angularVersion.isGreaterThanOrEqualTo(new SemVer('6.0.0-rc.0')) + && !rxjsVersion.isGreaterThanOrEqualTo(new SemVer('5.6.0-forward-compat.0')) + && !rxjsVersion.isGreaterThanOrEqualTo(new SemVer('6.0.0-beta.0')) + ) { + console.error(terminal.bold(terminal.red(tags.stripIndents` + This project uses version ${rxjsVersion} of RxJs, which is not supported by Angular v6. + The official RxJs version that is supported is 5.6.0-forward-compat.0 and greater. + + Please visit the link below to find instructions on how to update RxJs. + https://docs.google.com/document/d/12nlLt71VLKb-z3YaSGzUfx6mJbc34nsMXtByPUN35cg/edit# + ` + '\n'))); + process.exit(3); + } else if ( + angularVersion.isGreaterThanOrEqualTo(new SemVer('6.0.0-rc.0')) + && !rxjsVersion.isGreaterThanOrEqualTo(new SemVer('6.0.0-beta.0')) + ) { + console.warn(terminal.bold(terminal.red(tags.stripIndents` + This project uses a temporary compatibility version of RxJs (${rxjsVersion}). + + Please visit the link below to find instructions on how to update RxJs. + https://docs.google.com/document/d/12nlLt71VLKb-z3YaSGzUfx6mJbc34nsMXtByPUN35cg/edit# + ` + '\n'))); + } + } + + static assertTypescriptVersion(projectRoot: string) { + if (!isWarningEnabled('typescriptMismatch')) { + return; + } + + let compilerVersion: string; + let tsVersion: string; + let compilerTypeScriptPeerVersion: string; + try { + const resolveOptions = { + basedir: projectRoot, + checkGlobal: false, + checkLocal: true, + }; + const compilerPackagePath = resolve('@angular/compiler-cli/package.json', resolveOptions); + const typescriptProjectPath = resolve('typescript', resolveOptions); + const compilerPackageInfo = require(compilerPackagePath); + + compilerVersion = compilerPackageInfo['version']; + compilerTypeScriptPeerVersion = compilerPackageInfo['peerDependencies']['typescript']; + tsVersion = require(typescriptProjectPath).version; + } catch { + console.error(terminal.bold(terminal.red(tags.stripIndents` + Versions of @angular/compiler-cli and typescript could not be determined. + The most common reason for this is a broken npm install. + + Please make sure your package.json contains both @angular/compiler-cli and typescript in + devDependencies, then delete node_modules and package-lock.json (if you have one) and + run npm install again. + `))); + process.exit(2); + + return; + } + + // These versions do not have accurate typescript peer dependencies + const versionCombos = [ + { compiler: '>=2.3.1 <3.0.0', typescript: '>=2.0.2 <2.3.0' }, + { compiler: '>=4.0.0-beta.0 <5.0.0', typescript: '>=2.1.0 <2.4.0' }, + { compiler: '5.0.0-beta.0 - 5.0.0-rc.2', typescript: '>=2.4.2 <2.5.0' }, + ]; + + let currentCombo = versionCombos.find((combo) => satisfies(compilerVersion, combo.compiler)); + if (!currentCombo && compilerTypeScriptPeerVersion) { + currentCombo = { compiler: compilerVersion, typescript: compilerTypeScriptPeerVersion }; + } + + if (currentCombo && !satisfies(tsVersion, currentCombo.typescript)) { + // First line of warning looks weird being split in two, disable tslint for it. + console.error((terminal.yellow('\n' + tags.stripIndent` + @angular/compiler-cli@${compilerVersion} requires typescript@'${ + currentCombo.typescript}' but ${tsVersion} was found instead. + Using this version can result in undefined behaviour and difficult to debug problems. + + Please run the following command to install a compatible version of TypeScript. + + npm install typescript@"${currentCombo.typescript}" + + To disable this warning run "ng config cli.warnings.typescriptMismatch false". + ` + '\n'))); + } + } + +} diff --git a/packages/@angular/cli/utilities/INITIAL_COMMIT_MESSAGE.txt b/packages/angular/cli/utilities/INITIAL_COMMIT_MESSAGE.txt similarity index 100% rename from packages/@angular/cli/utilities/INITIAL_COMMIT_MESSAGE.txt rename to packages/angular/cli/utilities/INITIAL_COMMIT_MESSAGE.txt diff --git a/packages/angular/cli/utilities/check-package-manager.ts b/packages/angular/cli/utilities/check-package-manager.ts new file mode 100644 index 000000000000..b62c89a1fbe2 --- /dev/null +++ b/packages/angular/cli/utilities/check-package-manager.ts @@ -0,0 +1,53 @@ +/** + * @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 { terminal } from '@angular-devkit/core'; +import { exec } from 'child_process'; +import { promisify } from 'util'; +import { getPackageManager } from './config'; + +const execPromise = promisify(exec); +const packageManager = getPackageManager(); + + +export function checkYarnOrCNPM() { + + // Don't show messages if user has already changed the default. + if (packageManager !== 'default') { + return Promise.resolve(); + } + + return Promise + .all([checkYarn(), checkCNPM()]) + .then((data: Array) => { + const [isYarnInstalled, isCNPMInstalled] = data; + if (isYarnInstalled && isCNPMInstalled) { + console.error(terminal.yellow('You can `ng config -g cli.packageManager yarn` ' + + 'or `ng config -g cli.packageManager cnpm`.')); + } else if (isYarnInstalled) { + console.error(terminal.yellow('You can `ng config -g cli.packageManager yarn`.')); + } else if (isCNPMInstalled) { + console.error(terminal.yellow('You can `ng config -g cli.packageManager cnpm`.')); + } else { + if (packageManager !== 'default' && packageManager !== 'npm') { + console.error(terminal.yellow(`Seems that ${packageManager} is not installed.`)); + console.error(terminal.yellow('You can `ng config -g cli.packageManager npm`.')); + } + } + }); +} + +function checkYarn() { + return execPromise('yarn --version') + .then(() => true, () => false); +} + +function checkCNPM() { + return execPromise('cnpm --version') + .then(() => true, () => false); +} diff --git a/packages/angular/cli/utilities/config.ts b/packages/angular/cli/utilities/config.ts new file mode 100644 index 000000000000..abad429d7b1f --- /dev/null +++ b/packages/angular/cli/utilities/config.ts @@ -0,0 +1,356 @@ +/** + * @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 { + JsonAstObject, + JsonObject, + JsonParseMode, + experimental, + normalize, + parseJson, + parseJsonAst, + virtualFs, +} from '@angular-devkit/core'; +import { NodeJsSyncHost } from '@angular-devkit/core/node'; +import { existsSync, readFileSync, writeFileSync } from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { findUp } from './find-up'; + +function getSchemaLocation(): string { + return path.join(__dirname, '../lib/config/schema.json'); +} + +export const workspaceSchemaPath = getSchemaLocation(); + +const configNames = [ 'angular.json', '.angular.json' ]; +const globalFileName = '.angular-config.json'; + +function projectFilePath(projectPath?: string): string | null { + // Find the configuration, either where specified, in the Angular CLI project + // (if it's in node_modules) or from the current process. + return (projectPath && findUp(configNames, projectPath)) + || findUp(configNames, process.cwd()) + || findUp(configNames, __dirname); +} + +function globalFilePath(): string | null { + const home = os.homedir(); + if (!home) { + return null; + } + + const p = path.join(home, globalFileName); + if (existsSync(p)) { + return p; + } + + return null; +} + +const cachedWorkspaces = new Map(); + +export function getWorkspace( + level: 'local' | 'global' = 'local', +): experimental.workspace.Workspace | null { + const cached = cachedWorkspaces.get(level); + if (cached != undefined) { + return cached; + } + + const configPath = level === 'local' ? projectFilePath() : globalFilePath(); + + if (!configPath) { + cachedWorkspaces.set(level, null); + + return null; + } + + const root = normalize(path.dirname(configPath)); + const file = normalize(path.basename(configPath)); + const workspace = new experimental.workspace.Workspace( + root, + new NodeJsSyncHost(), + ); + + workspace.loadWorkspaceFromHost(file).subscribe(); + cachedWorkspaces.set(level, workspace); + + return workspace; +} + +export function createGlobalSettings(): string { + const home = os.homedir(); + if (!home) { + throw new Error('No home directory found.'); + } + + const globalPath = path.join(home, globalFileName); + writeFileSync(globalPath, JSON.stringify({ version: 1 })); + + return globalPath; +} + +export function getWorkspaceRaw( + level: 'local' | 'global' = 'local', +): [JsonAstObject | null, string | null] { + let configPath = level === 'local' ? projectFilePath() : globalFilePath(); + + if (!configPath) { + if (level === 'global') { + configPath = createGlobalSettings(); + } else { + return [null, null]; + } + } + + let content = ''; + new NodeJsSyncHost().read(normalize(configPath)) + .subscribe(data => content = virtualFs.fileBufferToString(data)); + + const ast = parseJsonAst(content, JsonParseMode.Loose); + + if (ast.kind != 'object') { + throw new Error('Invalid JSON'); + } + + return [ast, configPath]; +} + +export function validateWorkspace(json: JsonObject) { + const workspace = new experimental.workspace.Workspace( + normalize('.'), + new NodeJsSyncHost(), + ); + + let error; + workspace.loadWorkspaceFromJson(json).subscribe({ + error: e => error = e, + }); + + if (error) { + throw error; + } + + return true; +} + +export function getProjectByCwd(workspace: experimental.workspace.Workspace): string | null { + try { + return workspace.getProjectByPath(normalize(process.cwd())); + } catch (e) { + if (e instanceof experimental.workspace.AmbiguousProjectPathException) { + return workspace.getDefaultProjectName(); + } + throw e; + } +} + +export function getPackageManager(): string { + let workspace = getWorkspace('local'); + + if (workspace) { + const project = getProjectByCwd(workspace); + if (project && workspace.getProjectCli(project)) { + const value = workspace.getProjectCli(project)['packageManager']; + if (typeof value == 'string') { + return value; + } + } + if (workspace.getCli()) { + const value = workspace.getCli()['packageManager']; + if (typeof value == 'string') { + return value; + } + } + } + + workspace = getWorkspace('global'); + if (workspace && workspace.getCli()) { + const value = workspace.getCli()['packageManager']; + if (typeof value == 'string') { + return value; + } + } + + // Only check legacy if updated workspace is not found. + if (!workspace) { + const legacyPackageManager = getLegacyPackageManager(); + if (legacyPackageManager !== null) { + return legacyPackageManager; + } + } + + return 'npm'; +} + +export function migrateLegacyGlobalConfig(): boolean { + const homeDir = os.homedir(); + if (homeDir) { + const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json'); + if (existsSync(legacyGlobalConfigPath)) { + const content = readFileSync(legacyGlobalConfigPath, 'utf-8'); + const legacy = parseJson(content, JsonParseMode.Loose); + if (!legacy || typeof legacy != 'object' || Array.isArray(legacy)) { + return false; + } + + const cli: JsonObject = {}; + + if (legacy.packageManager && typeof legacy.packageManager == 'string' + && legacy.packageManager !== 'default') { + cli['packageManager'] = legacy.packageManager; + } + + if (legacy.defaults && typeof legacy.defaults == 'object' && !Array.isArray(legacy.defaults) + && legacy.defaults.schematics && typeof legacy.defaults.schematics == 'object' + && !Array.isArray(legacy.defaults.schematics) + && typeof legacy.defaults.schematics.collection == 'string') { + cli['defaultCollection'] = legacy.defaults.schematics.collection; + } + + if (legacy.warnings && typeof legacy.warnings == 'object' + && !Array.isArray(legacy.warnings)) { + + const warnings: JsonObject = {}; + if (typeof legacy.warnings.versionMismatch == 'boolean') { + warnings['versionMismatch'] = legacy.warnings.versionMismatch; + } + if (typeof legacy.warnings.typescriptMismatch == 'boolean') { + warnings['typescriptMismatch'] = legacy.warnings.typescriptMismatch; + } + + if (Object.getOwnPropertyNames(warnings).length > 0) { + cli['warnings'] = warnings; + } + } + + if (Object.getOwnPropertyNames(cli).length > 0) { + const globalPath = path.join(homeDir, globalFileName); + writeFileSync(globalPath, JSON.stringify({ version: 1, cli }, null, 2)); + + return true; + } + } + } + + return false; +} + +// Fallback, check for packageManager in config file in v1.* global config. +function getLegacyPackageManager(): string | null { + const homeDir = os.homedir(); + if (homeDir) { + const legacyGlobalConfigPath = path.join(homeDir, '.angular-cli.json'); + if (existsSync(legacyGlobalConfigPath)) { + const content = readFileSync(legacyGlobalConfigPath, 'utf-8'); + + const legacy = parseJson(content, JsonParseMode.Loose); + if (!legacy || typeof legacy != 'object' || Array.isArray(legacy)) { + return null; + } + + if (legacy.packageManager && typeof legacy.packageManager === 'string' + && legacy.packageManager !== 'default') { + return legacy.packageManager; + } + } + } + + return null; +} + +export function getSchematicDefaults( + collection: string, + schematic: string, + project?: string | null, +): {} { + let result = {}; + const fullName = `${collection}:${schematic}`; + + let workspace = getWorkspace('global'); + if (workspace && workspace.getSchematics()) { + const schematicObject = workspace.getSchematics()[fullName]; + if (schematicObject) { + result = { ...result, ...(schematicObject as {}) }; + } + const collectionObject = workspace.getSchematics()[collection]; + if (typeof collectionObject == 'object' && !Array.isArray(collectionObject)) { + result = { ...result, ...(collectionObject[schematic] as {}) }; + } + + } + + workspace = getWorkspace('local'); + + if (workspace) { + if (workspace.getSchematics()) { + const schematicObject = workspace.getSchematics()[fullName]; + if (schematicObject) { + result = { ...result, ...(schematicObject as {}) }; + } + const collectionObject = workspace.getSchematics()[collection]; + if (typeof collectionObject == 'object' && !Array.isArray(collectionObject)) { + result = { ...result, ...(collectionObject[schematic] as {}) }; + } + } + + project = project || getProjectByCwd(workspace); + if (project && workspace.getProjectSchematics(project)) { + const schematicObject = workspace.getProjectSchematics(project)[fullName]; + if (schematicObject) { + result = { ...result, ...(schematicObject as {}) }; + } + const collectionObject = workspace.getProjectSchematics(project)[collection]; + if (typeof collectionObject == 'object' && !Array.isArray(collectionObject)) { + result = { ...result, ...(collectionObject[schematic] as {}) }; + } + } + } + + return result; +} + +export function isWarningEnabled(warning: string): boolean { + let workspace = getWorkspace('local'); + + if (workspace) { + const project = getProjectByCwd(workspace); + if (project && workspace.getProjectCli(project)) { + const warnings = workspace.getProjectCli(project)['warnings']; + if (typeof warnings == 'object' && !Array.isArray(warnings)) { + const value = warnings[warning]; + if (typeof value == 'boolean') { + return value; + } + } + } + if (workspace.getCli()) { + const warnings = workspace.getCli()['warnings']; + if (typeof warnings == 'object' && !Array.isArray(warnings)) { + const value = warnings[warning]; + if (typeof value == 'boolean') { + return value; + } + } + } + } + + workspace = getWorkspace('global'); + if (workspace && workspace.getCli()) { + const warnings = workspace.getCli()['warnings']; + if (typeof warnings == 'object' && !Array.isArray(warnings)) { + const value = warnings[warning]; + if (typeof value == 'boolean') { + return value; + } + } + } + + return true; +} diff --git a/packages/angular/cli/utilities/find-up.ts b/packages/angular/cli/utilities/find-up.ts new file mode 100644 index 000000000000..81891a96e565 --- /dev/null +++ b/packages/angular/cli/utilities/find-up.ts @@ -0,0 +1,31 @@ +/** + * @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 { existsSync } from 'fs'; +import * as path from 'path'; + +export function findUp(names: string | string[], from: string) { + if (!Array.isArray(names)) { + names = [names]; + } + const root = path.parse(from).root; + + let currentDir = from; + while (currentDir && currentDir !== root) { + for (const name of names) { + const p = path.join(currentDir, name); + if (existsSync(p)) { + return p; + } + } + + currentDir = path.dirname(currentDir); + } + + return null; +} diff --git a/packages/angular/cli/utilities/json-schema.ts b/packages/angular/cli/utilities/json-schema.ts new file mode 100644 index 000000000000..40714c90651e --- /dev/null +++ b/packages/angular/cli/utilities/json-schema.ts @@ -0,0 +1,279 @@ +/** + * @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 { json, logging } from '@angular-devkit/core'; +import { ExportStringRef } from '@angular-devkit/schematics/tools'; +import { readFileSync } from 'fs'; +import { dirname, resolve } from 'path'; +import { + CommandConstructor, + CommandDescription, + CommandScope, + Option, + OptionType, + SubCommandDescription, + Value, +} from '../models/interface'; + +function _getEnumFromValue( + value: json.JsonValue, + enumeration: E, + defaultValue: T, +): T { + if (typeof value !== 'string') { + return defaultValue; + } + + if (Object.values(enumeration).indexOf(value) !== -1) { + return value as unknown as T; + } + + return defaultValue; +} + +export async function parseJsonSchemaToSubCommandDescription( + name: string, + jsonPath: string, + registry: json.schema.SchemaRegistry, + schema: json.JsonObject, + logger: logging.Logger, +): Promise { + const options = await parseJsonSchemaToOptions(registry, schema); + + const aliases: string[] = []; + if (json.isJsonArray(schema.$aliases)) { + schema.$aliases.forEach(value => { + if (typeof value == 'string') { + aliases.push(value); + } + }); + } + if (json.isJsonArray(schema.aliases)) { + schema.aliases.forEach(value => { + if (typeof value == 'string') { + aliases.push(value); + } + }); + } + if (typeof schema.alias == 'string') { + aliases.push(schema.alias); + } + + let longDescription = ''; + if (typeof schema.$longDescription == 'string' && schema.$longDescription) { + const ldPath = resolve(dirname(jsonPath), schema.$longDescription); + try { + longDescription = readFileSync(ldPath, 'utf-8'); + } catch (e) { + logger.warn(`File ${ldPath} was not found while constructing the subcommand ${name}.`); + } + } + let usageNotes = ''; + if (typeof schema.$usageNotes == 'string' && schema.$usageNotes) { + const unPath = resolve(dirname(jsonPath), schema.$usageNotes); + try { + usageNotes = readFileSync(unPath, 'utf-8'); + } catch (e) { + logger.warn(`File ${unPath} was not found while constructing the subcommand ${name}.`); + } + } + + const description = '' + (schema.description === undefined ? '' : schema.description); + + return { + name, + description, + ...(longDescription ? { longDescription } : {}), + ...(usageNotes ? { usageNotes } : {}), + options, + aliases, + }; +} + +export async function parseJsonSchemaToCommandDescription( + name: string, + jsonPath: string, + registry: json.schema.SchemaRegistry, + schema: json.JsonObject, + logger: logging.Logger, +): Promise { + const subcommand = + await parseJsonSchemaToSubCommandDescription(name, jsonPath, registry, schema, logger); + + // Before doing any work, let's validate the implementation. + if (typeof schema.$impl != 'string') { + throw new Error(`Command ${name} has an invalid implementation.`); + } + const ref = new ExportStringRef(schema.$impl, dirname(jsonPath)); + const impl = ref.ref; + + if (impl === undefined || typeof impl !== 'function') { + throw new Error(`Command ${name} has an invalid implementation.`); + } + + const scope = _getEnumFromValue(schema.$scope, CommandScope, CommandScope.Default); + const hidden = !!schema.$hidden; + + return { + ...subcommand, + scope, + hidden, + impl, + }; +} + +export async function parseJsonSchemaToOptions( + registry: json.schema.SchemaRegistry, + schema: json.JsonObject, +): Promise { + const options: Option[] = []; + + function visitor( + current: json.JsonObject | json.JsonArray, + pointer: json.schema.JsonPointer, + parentSchema?: json.JsonObject | json.JsonArray, + ) { + if (!parentSchema) { + // Ignore root. + return; + } else if (pointer.split(/\/(?:properties|items|definitions)\//g).length > 2) { + // Ignore subitems (objects or arrays). + return; + } else if (json.isJsonArray(current)) { + return; + } + + if (pointer.indexOf('/not/') != -1) { + // We don't support anyOf/not. + throw new Error('The "not" keyword is not supported in JSON Schema.'); + } + + const ptr = json.schema.parseJsonPointer(pointer); + const name = ptr[ptr.length - 1]; + + if (ptr[ptr.length - 2] != 'properties') { + // Skip any non-property items. + return; + } + + const typeSet = json.schema.getTypesOfSchema(current); + + if (typeSet.size == 0) { + throw new Error('Cannot find type of schema.'); + } + + // We only support number, string or boolean (or array of those), so remove everything else. + const types = [...typeSet].filter(x => { + switch (x) { + case 'boolean': + case 'number': + case 'string': + return true; + + case 'array': + // Only include arrays if they're boolean, string or number. + if (json.isJsonObject(current.items) + && typeof current.items.type == 'string' + && ['boolean', 'number', 'string'].includes(current.items.type)) { + return true; + } + + return false; + + default: + return false; + } + }).map(x => _getEnumFromValue(x, OptionType, OptionType.String)); + + if (types.length == 0) { + // This means it's not usable on the command line. e.g. an Object. + return; + } + + // Only keep enum values we support (booleans, numbers and strings). + const enumValues = (json.isJsonArray(current.enum) && current.enum || []).filter(x => { + switch (typeof x) { + case 'boolean': + case 'number': + case 'string': + return true; + + default: + return false; + } + }) as Value[]; + + let defaultValue: string | number | boolean | undefined = undefined; + if (current.default !== undefined) { + switch (types[0]) { + case 'string': + if (typeof current.default == 'string') { + defaultValue = current.default; + } + break; + case 'number': + if (typeof current.default == 'number') { + defaultValue = current.default; + } + break; + case 'boolean': + if (typeof current.default == 'boolean') { + defaultValue = current.default; + } + break; + } + } + + const type = types[0]; + const $default = current.$default; + const $defaultIndex = (json.isJsonObject($default) && $default['$source'] == 'argv') + ? $default['index'] : undefined; + const positional: number | undefined = typeof $defaultIndex == 'number' + ? $defaultIndex : undefined; + + const required = json.isJsonArray(current.required) + ? current.required.indexOf(name) != -1 : false; + const aliases = json.isJsonArray(current.aliases) ? [...current.aliases].map(x => '' + x) + : current.alias ? ['' + current.alias] : []; + const format = typeof current.format == 'string' ? current.format : undefined; + const visible = current.visible === undefined || current.visible === true; + const hidden = !!current.hidden || !visible; + + const option: Option = { + name, + description: '' + (current.description === undefined ? '' : current.description), + ...types.length == 1 ? { type } : { type, types }, + ...defaultValue !== undefined ? { default: defaultValue } : {}, + ...enumValues && enumValues.length > 0 ? { enum: enumValues } : {}, + required, + aliases, + ...format !== undefined ? { format } : {}, + hidden, + ...positional !== undefined ? { positional } : {}, + }; + + options.push(option); + } + + const flattenedSchema = await registry.flatten(schema).toPromise(); + json.schema.visitJsonSchema(flattenedSchema, visitor); + + // Sort by positional. + return options.sort((a, b) => { + if (a.positional) { + if (b.positional) { + return a.positional - b.positional; + } else { + return 1; + } + } else if (b.positional) { + return -1; + } else { + return 0; + } + }); +} diff --git a/packages/angular/cli/utilities/project.ts b/packages/angular/cli/utilities/project.ts new file mode 100644 index 000000000000..0ec8749d9886 --- /dev/null +++ b/packages/angular/cli/utilities/project.ts @@ -0,0 +1,71 @@ +/** + * @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 + */ + +// tslint:disable:no-global-tslint-disable no-any +import { normalize } from '@angular-devkit/core'; +import * as fs from 'fs'; +import * as os from 'os'; +import * as path from 'path'; +import { CommandWorkspace } from '../models/interface'; +import { findUp } from './find-up'; + +export function insideWorkspace(): boolean { + return getWorkspaceDetails() !== null; +} + +export function getWorkspaceDetails(): CommandWorkspace | null { + const currentDir = process.cwd(); + const possibleConfigFiles = [ + 'angular.json', + '.angular.json', + 'angular-cli.json', + '.angular-cli.json', + ]; + const configFilePath = findUp(possibleConfigFiles, currentDir); + if (configFilePath === null) { + return null; + } + const configFileName = path.basename(configFilePath); + + const possibleDir = path.dirname(configFilePath); + + const homedir = os.homedir(); + if (normalize(possibleDir) === normalize(homedir)) { + const packageJsonPath = path.join(possibleDir, 'package.json'); + if (!fs.existsSync(packageJsonPath)) { + // No package.json + return null; + } + const packageJsonBuffer = fs.readFileSync(packageJsonPath); + const packageJsonText = packageJsonBuffer === null ? '{}' : packageJsonBuffer.toString(); + const packageJson = JSON.parse(packageJsonText); + if (!containsCliDep(packageJson)) { + // No CLI dependency + return null; + } + } + + return { + root: possibleDir, + configFile: configFileName, + }; +} + +function containsCliDep(obj: any): boolean { + const pkgName = '@angular/cli'; + if (obj) { + if (obj.dependencies && obj.dependencies[pkgName]) { + return true; + } + if (obj.devDependencies && obj.devDependencies[pkgName]) { + return true; + } + } + + return false; +} diff --git a/packages/angular/pwa/BUILD b/packages/angular/pwa/BUILD new file mode 100644 index 000000000000..84fbbcf1d5cf --- /dev/null +++ b/packages/angular/pwa/BUILD @@ -0,0 +1,40 @@ +# 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 + +licenses(["notice"]) # MIT + +load("@build_bazel_rules_typescript//:defs.bzl", "ts_library") +load("//tools:ts_json_schema.bzl", "ts_json_schema") + +package(default_visibility = ["//visibility:public"]) + +ts_library( + name = "pwa", + srcs = glob( + ["**/*.ts"], + # Currently, this library is used only with the rollup plugin. + # To make it simpler for downstream repositories to compile this, we + # neither provide compile-time deps as an `npm_install` rule, nor do we + # expect the downstream repository to install @types/webpack[-*] + # So we exclude files that depend on webpack typings. + exclude = [ + "pwa/files/**/*", + "**/*_spec.ts", + "**/*_spec_large.ts", + ], + ), + deps = [ + ":pwa_schema", + "//packages/angular_devkit/core", + "//packages/angular_devkit/schematics", + "@rxjs", + # @typings: node + ], +) + +ts_json_schema( + name = "pwa_schema", + src = "pwa/schema.json", +) diff --git a/packages/angular/pwa/collection.json b/packages/angular/pwa/collection.json new file mode 100644 index 000000000000..f0fc0030d59a --- /dev/null +++ b/packages/angular/pwa/collection.json @@ -0,0 +1,11 @@ +{ + "schematics": { + "ng-add": { + "factory": "./pwa", + "description": "Update an application with PWA defaults.", + "schema": "./pwa/schema.json", + "private": true, + "hidden": true + } + } +} diff --git a/packages/angular/pwa/package.json b/packages/angular/pwa/package.json new file mode 100644 index 000000000000..b195accf5388 --- /dev/null +++ b/packages/angular/pwa/package.json @@ -0,0 +1,18 @@ +{ + "name": "@angular/pwa", + "version": "0.0.0", + "description": "PWA schematics for Angular", + "keywords": [ + "blueprints", + "code generation", + "schematics" + ], + "schematics": "./collection.json", + "dependencies": { + "@angular-devkit/core": "0.0.0", + "@angular-devkit/schematics": "0.0.0", + "@schematics/angular": "0.0.0", + "parse5-html-rewriting-stream": "5.1.0", + "rxjs": "6.3.3" + } +} \ No newline at end of file diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-128x128.png b/packages/angular/pwa/pwa/files/assets/icons/icon-128x128.png new file mode 100644 index 000000000000..9f9241f0be40 Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-128x128.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-144x144.png b/packages/angular/pwa/pwa/files/assets/icons/icon-144x144.png new file mode 100644 index 000000000000..4a5f8c16389c Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-144x144.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-152x152.png b/packages/angular/pwa/pwa/files/assets/icons/icon-152x152.png new file mode 100644 index 000000000000..34a1a8d64587 Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-152x152.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-192x192.png b/packages/angular/pwa/pwa/files/assets/icons/icon-192x192.png new file mode 100644 index 000000000000..9172e5dd29e4 Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-192x192.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-384x384.png b/packages/angular/pwa/pwa/files/assets/icons/icon-384x384.png new file mode 100644 index 000000000000..e54e8d3eafe5 Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-384x384.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-512x512.png b/packages/angular/pwa/pwa/files/assets/icons/icon-512x512.png new file mode 100644 index 000000000000..51ee297df1cb Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-512x512.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-72x72.png b/packages/angular/pwa/pwa/files/assets/icons/icon-72x72.png new file mode 100644 index 000000000000..2814a3f30caf Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-72x72.png differ diff --git a/packages/angular/pwa/pwa/files/assets/icons/icon-96x96.png b/packages/angular/pwa/pwa/files/assets/icons/icon-96x96.png new file mode 100644 index 000000000000..d271025c4f22 Binary files /dev/null and b/packages/angular/pwa/pwa/files/assets/icons/icon-96x96.png differ diff --git a/packages/angular/pwa/pwa/files/root/manifest.json b/packages/angular/pwa/pwa/files/root/manifest.json new file mode 100644 index 000000000000..37cf5fae506f --- /dev/null +++ b/packages/angular/pwa/pwa/files/root/manifest.json @@ -0,0 +1,51 @@ +{ + "name": "<%= title %>", + "short_name": "<%= title %>", + "theme_color": "#1976d2", + "background_color": "#fafafa", + "display": "standalone", + "scope": "/", + "start_url": "/", + "icons": [ + { + "src": "assets/icons/icon-72x72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "assets/icons/icon-96x96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "assets/icons/icon-128x128.png", + "sizes": "128x128", + "type": "image/png" + }, + { + "src": "assets/icons/icon-144x144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "assets/icons/icon-152x152.png", + "sizes": "152x152", + "type": "image/png" + }, + { + "src": "assets/icons/icon-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "assets/icons/icon-384x384.png", + "sizes": "384x384", + "type": "image/png" + }, + { + "src": "assets/icons/icon-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} \ No newline at end of file diff --git a/packages/angular/pwa/pwa/index.ts b/packages/angular/pwa/pwa/index.ts new file mode 100644 index 000000000000..9eb869c7c5cf --- /dev/null +++ b/packages/angular/pwa/pwa/index.ts @@ -0,0 +1,215 @@ +/** +* @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 { + JsonParseMode, + experimental, + getSystemPath, + join, + normalize, + parseJson, +} from '@angular-devkit/core'; +import { + Rule, + SchematicContext, + SchematicsException, + Tree, + apply, + chain, + externalSchematic, + mergeWith, + move, + template, + url, +} from '@angular-devkit/schematics'; +import { Observable } from 'rxjs'; +import { Readable, Writable } from 'stream'; +import { Schema as PwaOptions } from './schema'; + +const RewritingStream = require('parse5-html-rewriting-stream'); + + +function getWorkspace( + host: Tree, +): { path: string, workspace: experimental.workspace.WorkspaceSchema } { + const possibleFiles = [ '/angular.json', '/.angular.json' ]; + const path = possibleFiles.filter(path => host.exists(path))[0]; + + const configBuffer = host.read(path); + if (configBuffer === null) { + throw new SchematicsException(`Could not find (${path})`); + } + const content = configBuffer.toString(); + + return { + path, + workspace: parseJson( + content, + JsonParseMode.Loose, + ) as {} as experimental.workspace.WorkspaceSchema, + }; +} + +function updateIndexFile(path: string): Rule { + return (host: Tree) => { + const buffer = host.read(path); + if (buffer === null) { + throw new SchematicsException(`Could not read index file: ${path}`); + } + + const rewriter = new RewritingStream(); + + let needsNoScript = true; + rewriter.on('startTag', (startTag: { tagName: string }) => { + if (startTag.tagName === 'noscript') { + needsNoScript = false; + } + + rewriter.emitStartTag(startTag); + }); + + rewriter.on('endTag', (endTag: { tagName: string }) => { + if (endTag.tagName === 'head') { + rewriter.emitRaw(' \n'); + rewriter.emitRaw(' \n'); + } else if (endTag.tagName === 'body' && needsNoScript) { + rewriter.emitRaw( + ' \n', + ); + } + + rewriter.emitEndTag(endTag); + }); + + return new Observable(obs => { + const input = new Readable({ + encoding: 'utf8', + read(): void { + this.push(buffer); + this.push(null); + }, + }); + + const chunks: Array = []; + const output = new Writable({ + write(chunk: string | Buffer, encoding: string, callback: Function): void { + chunks.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk); + callback(); + }, + final(callback: (error?: Error) => void): void { + const full = Buffer.concat(chunks); + host.overwrite(path, full.toString()); + callback(); + obs.next(host); + obs.complete(); + }, + }); + + input.pipe(rewriter).pipe(output); + }); + }; +} + +export default function (options: PwaOptions): Rule { + return (host: Tree, context: SchematicContext) => { + if (!options.title) { + options.title = options.project; + } + const {path: workspacePath, workspace } = getWorkspace(host); + + if (!options.project) { + throw new SchematicsException('Option "project" is required.'); + } + + const project = workspace.projects[options.project]; + if (!project) { + throw new SchematicsException(`Project is not defined in this workspace.`); + } + + if (project.projectType !== 'application') { + throw new SchematicsException(`PWA requires a project type of "application".`); + } + + // Find all the relevant targets for the project + const projectTargets = project.targets || project.architect; + if (!projectTargets || Object.keys(projectTargets).length === 0) { + throw new SchematicsException(`Targets are not defined for this project.`); + } + + const buildTargets = []; + const testTargets = []; + for (const targetName in projectTargets) { + const target = projectTargets[targetName]; + if (!target) { + continue; + } + + if (target.builder === '@angular-devkit/build-angular:browser') { + buildTargets.push(target); + } else if (target.builder === '@angular-devkit/build-angular:karma') { + testTargets.push(target); + } + } + + // Add manifest to asset configuration + const assetEntry = join(normalize(project.root), 'src', 'manifest.json'); + for (const target of [...buildTargets, ...testTargets]) { + if (target.options) { + if (target.options.assets) { + target.options.assets.push(assetEntry); + } else { + target.options.assets = [ assetEntry ]; + } + } else { + target.options = { assets: [ assetEntry ] }; + } + } + host.overwrite(workspacePath, JSON.stringify(workspace, null, 2)); + + // Find all index.html files in build targets + const indexFiles = new Set(); + for (const target of buildTargets) { + if (target.options && target.options.index) { + indexFiles.add(target.options.index); + } + + if (!target.configurations) { + continue; + } + for (const configName in target.configurations) { + const configuration = target.configurations[configName]; + if (configuration && configuration.index) { + indexFiles.add(configuration.index); + } + } + } + + // Setup sources for the assets files to add to the project + const sourcePath = join(normalize(project.root), 'src'); + const assetsPath = join(sourcePath, 'assets'); + const rootTemplateSource = apply(url('./files/root'), [ + template({ ...options }), + move(getSystemPath(sourcePath)), + ]); + const assetsTemplateSource = apply(url('./files/assets'), [ + template({ ...options }), + move(getSystemPath(assetsPath)), + ]); + + // Setup service worker schematic options + const swOptions = { ...options }; + delete swOptions.title; + + // Chain the rules and return + return chain([ + externalSchematic('@schematics/angular', 'service-worker', swOptions), + mergeWith(rootTemplateSource), + mergeWith(assetsTemplateSource), + ...[...indexFiles].map(path => updateIndexFile(path)), + ])(host, context); + }; +} diff --git a/packages/angular/pwa/pwa/index_spec.ts b/packages/angular/pwa/pwa/index_spec.ts new file mode 100644 index 000000000000..f716847f47ff --- /dev/null +++ b/packages/angular/pwa/pwa/index_spec.ts @@ -0,0 +1,142 @@ +/** + * @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 { SchematicTestRunner, UnitTestTree } from '@angular-devkit/schematics/testing'; +import * as path from 'path'; +import { Schema as PwaOptions } from './schema'; + + +// tslint:disable:max-line-length +describe('PWA Schematic', () => { + const schematicRunner = new SchematicTestRunner( + '@angular/pwa', + path.join(__dirname, '../collection.json'), + ); + const defaultOptions: PwaOptions = { + project: 'bar', + target: 'build', + configuration: 'production', + title: 'Fake Title', + }; + + let appTree: UnitTestTree; + + // tslint:disable-next-line:no-any + const workspaceOptions: any = { + name: 'workspace', + newProjectRoot: 'projects', + version: '6.0.0', + }; + + // tslint:disable-next-line:no-any + const appOptions: any = { + name: 'bar', + inlineStyle: false, + inlineTemplate: false, + routing: false, + style: 'css', + skipTests: false, + }; + + beforeEach(() => { + appTree = schematicRunner.runExternalSchematic('@schematics/angular', 'workspace', workspaceOptions); + appTree = schematicRunner.runExternalSchematic('@schematics/angular', 'application', appOptions, appTree); + }); + + it('should run the service worker schematic', (done) => { + schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { + const configText = tree.readContent('/angular.json'); + const config = JSON.parse(configText); + const swFlag = config.projects.bar.architect.build.configurations.production.serviceWorker; + expect(swFlag).toEqual(true); + done(); + }, done.fail); + }); + + it('should create icon files', (done) => { + const dimensions = [72, 96, 128, 144, 152, 192, 384, 512]; + const iconPath = '/projects/bar/src/assets/icons/icon-'; + schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { + dimensions.forEach(d => { + const path = `${iconPath}${d}x${d}.png`; + expect(tree.exists(path)).toEqual(true); + }); + done(); + }, done.fail); + }); + + it('should create a manifest file', (done) => { + schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { + expect(tree.exists('/projects/bar/src/manifest.json')).toEqual(true); + done(); + }, done.fail); + }); + + it('should set the name & short_name in the manifest file', (done) => { + schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { + const manifestText = tree.readContent('/projects/bar/src/manifest.json'); + const manifest = JSON.parse(manifestText); + + expect(manifest.name).toEqual(defaultOptions.title); + expect(manifest.short_name).toEqual(defaultOptions.title); + done(); + }, done.fail); + }); + + it('should set the name & short_name in the manifest file when no title provided', (done) => { + const options = {...defaultOptions, title: undefined}; + schematicRunner.runSchematicAsync('ng-add', options, appTree).toPromise().then(tree => { + const manifestText = tree.readContent('/projects/bar/src/manifest.json'); + const manifest = JSON.parse(manifestText); + + expect(manifest.name).toEqual(defaultOptions.project); + expect(manifest.short_name).toEqual(defaultOptions.project); + done(); + }, done.fail); + }); + + it('should update the index file', (done) => { + schematicRunner.runSchematicAsync('ng-add', defaultOptions, appTree).toPromise().then(tree => { + const content = tree.readContent('projects/bar/src/index.html'); + + expect(content).toMatch(//); + expect(content).toMatch(//); + expect(content) + .toMatch(/