Compare commits
1 Commits
2.0.2
...
2.0.0-alph
Author | SHA1 | Date | |
---|---|---|---|
7d5c3eb001 |
4
.bowerrc
4
.bowerrc
@ -1,3 +1,3 @@
|
||||
{
|
||||
"directory" : "bower_components"
|
||||
}
|
||||
"directory": "bower_components"
|
||||
}
|
6
.gitattributes
vendored
6
.gitattributes
vendored
@ -1,9 +1,5 @@
|
||||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
||||
|
||||
# JS and TS files must always use LF for tools to work
|
||||
# JS files must always use LF for tools to work
|
||||
*.js eol=lf
|
||||
*.ts eol=lf
|
||||
|
||||
# Must keep Windows line ending to be parsed correctly
|
||||
scripts/windows/packages.txt eol=crlf
|
||||
|
39
.github/ISSUE_TEMPLATE.md
vendored
39
.github/ISSUE_TEMPLATE.md
vendored
@ -1,39 +0,0 @@
|
||||
<!--
|
||||
IF YOU DON'T FILL OUT THE FOLLOWING INFORMATION WE MIGHT CLOSE YOUR ISSUE WITHOUT INVESTIGATING
|
||||
-->
|
||||
|
||||
**I'm submitting a ...** (check one with "x")
|
||||
```
|
||||
[ ] bug report => search github for a similar issue or PR before submitting
|
||||
[ ] feature request
|
||||
[ ] support request => Please do not submit support request here, instead see https://github.com/angular/angular/blob/master/CONTRIBUTING.md#question
|
||||
```
|
||||
|
||||
**Current behavior**
|
||||
<!-- Describe how the bug manifests. -->
|
||||
|
||||
**Expected behavior**
|
||||
<!-- Describe what the behavior would be without the bug. -->
|
||||
|
||||
**Minimal reproduction of the problem with instructions**
|
||||
<!--
|
||||
If the current behavior is a bug or you can illustrate your feature request better with an example,
|
||||
please provide the *STEPS TO REPRODUCE* and if possible a *MINIMAL DEMO* of the problem via
|
||||
https://plnkr.co or similar (you can use this template as a starting point: http://plnkr.co/edit/tpl:AvJOMERrnz94ekVua0u5).
|
||||
-->
|
||||
|
||||
**What is the motivation / use case for changing the behavior?**
|
||||
<!-- Describe the motivation or the concrete use case -->
|
||||
|
||||
**Please tell us about your environment:**
|
||||
<!-- Operating system, IDE, package manager, HTTP server, ... -->
|
||||
|
||||
* **Angular version:** 2.0.X
|
||||
<!-- Check whether this is still an issue in the most recent Angular version -->
|
||||
|
||||
* **Browser:** [all | Chrome XX | Firefox XX | IE XX | Safari XX | Mobile Chrome XX | Android X.X Web Browser | iOS XX Safari | iOS XX UIWebView | iOS XX WKWebView ]
|
||||
<!-- All browsers where this could be reproduced -->
|
||||
|
||||
* **Language:** [all | TypeScript X.X | ES6/7 | ES5]
|
||||
|
||||
* **Node (for AoT issues):** `node --version` =
|
36
.github/PULL_REQUEST_TEMPLATE.md
vendored
36
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -1,36 +0,0 @@
|
||||
**Please check if the PR fulfills these requirements**
|
||||
- [ ] The commit message follows our guidelines: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#commit
|
||||
- [ ] Tests for the changes have been added (for bug fixes / features)
|
||||
- [ ] Docs have been added / updated (for bug fixes / features)
|
||||
|
||||
|
||||
**What kind of change does this PR introduce?** (check one with "x")
|
||||
```
|
||||
[ ] Bugfix
|
||||
[ ] Feature
|
||||
[ ] Code style update (formatting, local variables)
|
||||
[ ] Refactoring (no functional changes, no api changes)
|
||||
[ ] Build related changes
|
||||
[ ] CI related changes
|
||||
[ ] Other... Please describe:
|
||||
```
|
||||
|
||||
**What is the current behavior?** (You can also link to an open issue here)
|
||||
|
||||
|
||||
|
||||
**What is the new behavior?**
|
||||
|
||||
|
||||
|
||||
**Does this PR introduce a breaking change?** (check one with "x")
|
||||
```
|
||||
[ ] Yes
|
||||
[ ] No
|
||||
```
|
||||
|
||||
If this PR contains a breaking change, please describe the impact and migration path for existing applications: ...
|
||||
|
||||
|
||||
**Other information**:
|
||||
|
28
.gitignore
vendored
28
.gitignore
vendored
@ -1,14 +1,34 @@
|
||||
.DS_STORE
|
||||
|
||||
# Don’t commit the following directories created by pub.
|
||||
packages
|
||||
pubspec.lock
|
||||
.pub
|
||||
.packages
|
||||
|
||||
/dist/
|
||||
.buildlog
|
||||
node_modules
|
||||
bower_components
|
||||
|
||||
# Or broccoli working directory
|
||||
tmp
|
||||
|
||||
# Or the files created by dart2js.
|
||||
*.dart.js
|
||||
*.dart.precompiled.js
|
||||
*.js_
|
||||
*.js.deps
|
||||
*.js.map
|
||||
|
||||
# Or type definitions we mirror from github
|
||||
**/typings/**/*.d.ts
|
||||
**/typings/tsd.cached.json
|
||||
|
||||
# Include when developing application packages.
|
||||
pubspec.lock
|
||||
.c9
|
||||
.idea/
|
||||
.settings/
|
||||
*.swo
|
||||
modules/.settings
|
||||
.vscode
|
||||
@ -20,8 +40,4 @@ modules/.vscode
|
||||
# Ignore npm debug log
|
||||
npm-debug.log
|
||||
|
||||
# build-analytics
|
||||
.build-analytics
|
||||
|
||||
# rollup-test output
|
||||
/modules/rollup-test/dist/
|
||||
/docs/bower_components/
|
||||
|
12
.settings/settings.json
Normal file
12
.settings/settings.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"search.exclude": {
|
||||
".git" : true,
|
||||
".idea": true,
|
||||
"node_modules" : true,
|
||||
"bower_components" : true,
|
||||
"packages" : true,
|
||||
"build" : true,
|
||||
"dist" : true,
|
||||
"tmp" : true
|
||||
}
|
||||
}
|
135
.travis.yml
135
.travis.yml
@ -1,51 +1,128 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '6.6.0'
|
||||
|
||||
addons:
|
||||
# firefox: "38.0"
|
||||
apt:
|
||||
sources:
|
||||
# needed to install g++ that is used by npms's native modules
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
- '4.1.1'
|
||||
|
||||
branches:
|
||||
except:
|
||||
- g3_v2_0
|
||||
- g3sync
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- ./node_modules
|
||||
- ./.chrome/chromium
|
||||
- node_modules
|
||||
- $HOME/.pub-cache
|
||||
|
||||
env:
|
||||
global:
|
||||
# GITHUB_TOKEN_ANGULAR
|
||||
# This is needed for the e2e Travis matrix task to publish packages to github for continuous packages delivery.
|
||||
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
|
||||
- KARMA_BROWSERS=DartiumWithWebPlatform
|
||||
- E2E_BROWSERS=Dartium
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- ARCH=linux-x64
|
||||
# TODO: change DART_DEV_VERSION to "latest" again once
|
||||
# https://github.com/angular/angular/issues/4467 is solved
|
||||
- DART_DEV_VERSION=1.13.0-dev.3.1
|
||||
- DART_STABLE_VERSION=latest
|
||||
# Token for tsd to increase github rate limit
|
||||
# See https://github.com/DefinitelyTyped/tsd#tsdrc
|
||||
# This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
|
||||
# because those are not visible for pull requests, and those should also be reliable.
|
||||
# This SSO token belongs to github account angular-github-ratelimit-token which has no access
|
||||
# (password is in Valentine)
|
||||
- TSDRC='{"token":"ef474500309daea53d5991b3079159a29520a40b"}'
|
||||
# GITHUB_TOKEN_ANGULAR
|
||||
- secure: "fq/U7VDMWO8O8SnAQkdbkoSe2X92PVqg4d044HmRYVmcf6YbO48+xeGJ8yOk0pCBwl3ISO4Q2ot0x546kxfiYBuHkZetlngZxZCtQiFT9kyId8ZKcYdXaIW9OVdw3Gh3tQyUwDucfkVhqcs52D6NZjyE2aWZ4/d1V4kWRO/LMgo="
|
||||
matrix:
|
||||
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
|
||||
- CI_MODE=js
|
||||
- CI_MODE=e2e
|
||||
- CI_MODE=saucelabs_required
|
||||
- CI_MODE=browserstack_required
|
||||
- CI_MODE=saucelabs_optional
|
||||
- CI_MODE=browserstack_optional
|
||||
# Order: slowest build on top, so that we don't hog VMs while waiting for others to complete.
|
||||
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=js DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=router DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=lint DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
allow_failures:
|
||||
- env: "CI_MODE=saucelabs_optional"
|
||||
- env: "CI_MODE=browserstack_optional"
|
||||
- env: "MODE=saucelabs DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
|
||||
addons:
|
||||
firefox: "38.0"
|
||||
|
||||
before_install:
|
||||
- echo ${TSDRC} > .tsdrc
|
||||
- export DISPLAY=:99.0
|
||||
- export GIT_SHA=$(git rev-parse HEAD)
|
||||
- ./scripts/ci/init_android.sh
|
||||
- ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${DART_VERSION} ${ARCH}
|
||||
- sh -e /etc/init.d/xvfb start
|
||||
- if [[ -e SKIP_TRAVIS_TESTS ]]; then { cat SKIP_TRAVIS_TESTS ; exit 0; } fi
|
||||
- '[ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ] && SAUCE_USERNAME="angular2-ci" && SAUCE_ACCESS_KEY="693ebc16208a-0b5b-1614-8d66-a2662f4e" || true'
|
||||
|
||||
install:
|
||||
- ./scripts/ci-lite/install.sh
|
||||
# Update npm
|
||||
- npm install -g npm@2.14.5
|
||||
- npm --version
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules || true
|
||||
# Install npm dependecies
|
||||
- npm install
|
||||
|
||||
before_script:
|
||||
- mkdir -p $LOGS_DIR
|
||||
- ./scripts/ci/presubmit-queue-setup.sh
|
||||
|
||||
script:
|
||||
- ./scripts/ci-lite/build.sh && ./scripts/ci-lite/test.sh
|
||||
- ./scripts/ci/build_and_test.sh ${MODE}
|
||||
|
||||
after_script:
|
||||
- ./scripts/ci-lite/cleanup.sh
|
||||
- ./scripts/ci/print-logs.sh
|
||||
- ./scripts/ci/after-script.sh
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/1ef62e23078036f9cee4
|
||||
# trigger Buildtime Trend Service to parse Travis CI log
|
||||
- https://buildtimetrend.herokuapp.com/travis
|
||||
on_success: always # options: [always|never|change] default: always
|
||||
on_failure: always # options: [always|never|change] default: always
|
||||
on_start: false # default: false
|
||||
slack:
|
||||
secure: EP4MzZ8JMyNQJ4S3cd5LEPWSMjC7ZRdzt3veelDiOeorJ6GwZfCDHncR+4BahDzQAuqyE/yNpZqaLbwRWloDi15qIUsm09vgl/1IyNky1Sqc6lEknhzIXpWSalo4/T9ZP8w870EoDvM/UO+LCV99R3wS8Nm9o99eLoWVb2HIUu0=
|
||||
|
||||
deploy:
|
||||
- provider: gcs
|
||||
# This is for project angular-github-babysitter
|
||||
access_key_id: GOOGIOQTDBEOPBUAWFZQ
|
||||
secret_access_key:
|
||||
secure: "MEDggllZ5fw4wI9CEUi8WR6jKsKXqdRF/DLxSNC2JpzM5RlVeBm0uqjntYT1Cf1dASvQ2/+vZCUikL/3A48NcoEYRHXGmxu8D6t/SvleQD8Xv434xFOdsa2QqP/HiCtqCLOI5jJz1JVoB5nNyKKZ33ogTUL1LV1TfcrAioyizW8="
|
||||
# this bucket has a lifecycle to delete after 90 days:
|
||||
# $ echo '{"rule": [{"action": {"type": "Delete"}, "condition": {"age": 90}}]}' > lifecycle.json
|
||||
# $ gsutil lifecycle set lifecycle.json gs://angular2-snapshots
|
||||
bucket: angular2-snapshots
|
||||
# don't delete generated files
|
||||
skip_cleanup: true
|
||||
# serve to public at https://storage.googleapis.com/angular2-snapshots/SHA/dart_stable/dist.tgz
|
||||
acl: public-read
|
||||
# upload the .tgz archive created in scripts/ci/build_and_test.sh
|
||||
local-dir: deploy
|
||||
# create a "subdirectory" for each commit
|
||||
upload-dir: $TRAVIS_COMMIT/dart_stable
|
||||
on:
|
||||
repo: angular/angular
|
||||
condition: "$MODE = dart && $DART_CHANNEL = stable"
|
||||
- provider: gcs
|
||||
access_key_id: GOOGIOQTDBEOPBUAWFZQ
|
||||
secret_access_key:
|
||||
secure: "MEDggllZ5fw4wI9CEUi8WR6jKsKXqdRF/DLxSNC2JpzM5RlVeBm0uqjntYT1Cf1dASvQ2/+vZCUikL/3A48NcoEYRHXGmxu8D6t/SvleQD8Xv434xFOdsa2QqP/HiCtqCLOI5jJz1JVoB5nNyKKZ33ogTUL1LV1TfcrAioyizW8="
|
||||
bucket: angular2-snapshots
|
||||
skip_cleanup: true
|
||||
acl: public-read
|
||||
local-dir: deploy
|
||||
upload-dir: $TRAVIS_COMMIT/js
|
||||
on:
|
||||
repo: angular/angular
|
||||
condition: "$MODE = js"
|
||||
|
2924
CHANGELOG.md
2924
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@ -11,11 +11,8 @@ Someone with committer access will do the rest.
|
||||
We have automated the process for merging pull requests into master. Our goal is to minimize the disruption for
|
||||
Angular committers and also prevent breakages on master.
|
||||
|
||||
When a PR has `pr_state: LGTM` and is ready to merge, you should add the `pr_action: merge` label.
|
||||
Currently (late 2015), we need to ensure that each PR will cleanly merge into the Google-internal version control,
|
||||
so the caretaker reviews the changes manually.
|
||||
|
||||
After this review, the caretaker adds `zomg_admin: do_merge` which is restricted to admins only.
|
||||
When a PR is ready to merge, a project member in the CoreTeamMember list (see below) can add the special label,
|
||||
`PR: merge`.
|
||||
A robot running as [mary-poppins](https://github.com/mary-poppins)
|
||||
is notified that the label was added by an authorized person,
|
||||
and will create a new branch in the angular project, using the convention `presubmit-{username}-pr-{number}`.
|
||||
@ -29,6 +26,6 @@ Finally, after merge `mary-poppins` removes the presubmit branch.
|
||||
|
||||
## Administration
|
||||
|
||||
The list of users who can trigger a merge by adding the `zomg_admin: do_merge` label is stored in our appengine app datastore.
|
||||
The list of users who can trigger a merge by adding the label is stored in our appengine app datastore.
|
||||
Edit the contents of the [CoreTeamMember Table](
|
||||
https://console.developers.google.com/project/angular2-automation/datastore/query?queryType=KindQuery&namespace=&kind=CoreTeamMember)
|
||||
|
@ -18,17 +18,18 @@ Help us keep Angular open and inclusive. Please read and follow our [Code of Con
|
||||
## <a name="question"></a> Got a Question or Problem?
|
||||
|
||||
If you have questions about how to *use* Angular, please direct them to the [Google Group][angular-group]
|
||||
discussion list or [StackOverflow][stackoverflow]. Please note that the Angular team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
||||
discussion list or [StackOverflow][stackoverflow]. Please note that Angular 2 is still in early developer preview, and the core team's capacity to answer usage questions is limited. We are also available on [Gitter][gitter].
|
||||
|
||||
## <a name="issue"></a> Found an Issue?
|
||||
If you find a bug in the source code, you can help us by
|
||||
If you find a bug in the source code or a mistake in the documentation, you can help us by
|
||||
[submitting an issue](#submit-issue) to our [GitHub Repository][github]. Even better, you can
|
||||
[submit a Pull Request](#submit-pr) with a fix.
|
||||
|
||||
## <a name="feature"></a> 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.
|
||||
a proposal for your work first, to be sure that we can use it. Angular 2 is in developer preview
|
||||
and we are not ready to accept major contributions ahead of the full release.
|
||||
Please consider what kind of change it is:
|
||||
|
||||
* For a **Major Feature**, first open an issue and outline your proposal so that it can be
|
||||
@ -47,18 +48,14 @@ features, by not reporting duplicate issues. Providing the following informatio
|
||||
chances of your issue being dealt with quickly:
|
||||
|
||||
* **Overview of the Issue** - if an error is being thrown a non-minified stack trace helps
|
||||
* **Angular Version** - what version of Angular is affected (e.g. 2.0.0-alpha.53)
|
||||
* **Motivation for or Use Case** - explain what are you trying to do and why the current behavior is a bug for you
|
||||
* **Motivation for or Use Case** - explain why this is a bug for you
|
||||
* **Browsers and Operating System** - is this a problem with all browsers?
|
||||
* **Reproduce the Error** - provide a live example (using [Plunker][plunker],
|
||||
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps
|
||||
[JSFiddle][jsfiddle] or [Runnable][runnable]) or a unambiguous set of steps.
|
||||
* **Related Issues** - has a similar issue been reported before?
|
||||
* **Suggest a Fix** - if you can't fix the bug yourself, perhaps you can point to what might be
|
||||
causing the problem (line of code or commit)
|
||||
|
||||
You can file new issues by providing the above information [here](https://github.com/angular/angular/issues/new).
|
||||
|
||||
|
||||
### <a name="submit-pr"></a> Submitting a Pull Request (PR)
|
||||
Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
|
||||
@ -94,7 +91,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
|
||||
* In GitHub, send a pull request to `angular:master`.
|
||||
* If we suggest changes then:
|
||||
* Make the required updates.
|
||||
* Re-run the Angular 2 test suites to ensure tests are still passing.
|
||||
* Re-run the Angular 2 test suites for JS and Dart to ensure tests are still passing.
|
||||
* Rebase your branch and force push to your GitHub repository (this will update your Pull Request):
|
||||
|
||||
```shell
|
||||
@ -165,19 +162,6 @@ The **header** is mandatory and the **scope** of the header is optional.
|
||||
Any line of the commit message cannot be longer 100 characters! This allows the message to be easier
|
||||
to read on GitHub as well as in various git tools.
|
||||
|
||||
Footer should contain a [closing reference to an issue](https://help.github.com/articles/closing-issues-via-commit-messages/) if any.
|
||||
|
||||
Samples: (even more [samples](https://github.com/angular/angular/commits/master))
|
||||
|
||||
```
|
||||
docs(changelog): update change log to beta.5
|
||||
```
|
||||
```
|
||||
fix(release): need to depend on latest rxjs and zone.js
|
||||
|
||||
The version in our package.json gets copied to the one we publish, and users need the latest of these.
|
||||
```
|
||||
|
||||
### Revert
|
||||
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit. In the body it should say: `This reverts commit <hash>.`, where the hash is the SHA of the commit being reverted.
|
||||
|
||||
@ -191,10 +175,9 @@ Must be one of the following:
|
||||
semi-colons, etc)
|
||||
* **refactor**: A code change that neither fixes a bug nor adds a feature
|
||||
* **perf**: A code change that improves performance
|
||||
* **test**: Adding missing tests or correcting existing tests
|
||||
* **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **ci**: Changes to our CI configuration files and scripts (example scopes: Travis, Circle, BrowserStack, SauceLabs)
|
||||
* **chore**: Other changes that don't modify `src` or `test` files
|
||||
* **test**: Adding missing tests
|
||||
* **chore**: Changes to the build process or auxiliary tools and libraries such as documentation
|
||||
generation
|
||||
|
||||
### Scope
|
||||
The scope could be anything specifying place of the commit change. For example
|
||||
@ -237,8 +220,8 @@ changes to be accepted, the CLA must be signed. It's a quick process, we promise
|
||||
[github]: https://github.com/angular/angular
|
||||
[gitter]: https://gitter.im/angular/angular
|
||||
[individual-cla]: http://code.google.com/legal/individual-cla-v1.0.html
|
||||
[js-style-guide]: https://google.github.io/styleguide/javascriptguide.xml
|
||||
[jsfiddle]: http://jsfiddle.net
|
||||
[js-style-guide]: http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
|
||||
[jsfiddle]: http://jsfiddle.net/
|
||||
[plunker]: http://plnkr.co/edit
|
||||
[runnable]: http://runnable.com
|
||||
[runnable]: http://runnable.com/
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/angular
|
||||
|
291
DEVELOPER.md
291
DEVELOPER.md
@ -1,13 +1,18 @@
|
||||
# Building and Testing Angular 2 for JS
|
||||
# Building and Testing Angular 2 for JS and Dart
|
||||
|
||||
This document describes how to set up your development environment to build and test Angular 2 JS version.
|
||||
It also explains the basic mechanics of using `git`, `node`, and `npm`.
|
||||
This document describes how to set up your development environment to build and test Angular, both
|
||||
JS and Dart versions. It also explains the basic mechanics of using `git`, `node`, and `npm`.
|
||||
|
||||
* [Prerequisite Software](#prerequisite-software)
|
||||
* [Getting the Sources](#getting-the-sources)
|
||||
* [Installing NPM Modules](#installing-npm-modules)
|
||||
* [Building](#building)
|
||||
* [Environment Variable Setup](#environment-variable-setup)
|
||||
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
|
||||
* [Running Tests Locally](#running-tests-locally)
|
||||
* [Formatting](#clang-format)
|
||||
* [Project Information](#project-information)
|
||||
* [CI using Travis](#ci-using-travis)
|
||||
* [Transforming Dart code](#transforming-dart-code)
|
||||
* [Debugging](#debugging)
|
||||
|
||||
See the [contribution guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md)
|
||||
if you'd like to contribute to Angular.
|
||||
@ -17,17 +22,30 @@ if you'd like to contribute to Angular.
|
||||
Before you can build and test Angular, you must install and configure the
|
||||
following products on your development machine:
|
||||
|
||||
* [Dart](https://www.dartlang.org) (version ` >=1.12.0 <2.0.0`), specifically the Dart-SDK and
|
||||
Dartium (a version of [Chromium](http://www.chromium.org) with native support for Dart through
|
||||
the Dart VM). One of the **simplest** ways to get both is to install the **Dart Editor bundle**,
|
||||
which includes the editor, SDK and Dartium. See the [Dart tools](https://www.dartlang.org/tools)
|
||||
download [page for instructions](https://www.dartlang.org/tools/download.html).
|
||||
You can also download both **stable** and **dev** channel versions from the [download
|
||||
archive](https://www.dartlang.org/tools/download-archive). In that case, on Windows, Dart must be added
|
||||
to the `Path` (e.g. `path-to-dart-sdk-folder\bin`) and a new `DARTIUM_BIN` environment variable must be
|
||||
created, pointing to the executable (e.g. `path-to-dartium-folder\chrome.exe).`
|
||||
|
||||
* [Git](http://git-scm.com) and/or the **GitHub app** (for [Mac](http://mac.github.com) or
|
||||
[Windows](http://windows.github.com)); [GitHub's Guide to Installing
|
||||
Git](https://help.github.com/articles/set-up-git) is a good source of information.
|
||||
|
||||
* [Node.js](http://nodejs.org), (version `>=5.4.1 <6`) which is used to run a development web server,
|
||||
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
|
||||
(version `>=3.5.3 <4.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
* [Node.js](http://nodejs.org), (version `>=4.1.1 <5`) which is used to run a development web server,
|
||||
run tests, and generate distributable files. We also use Node's Package Manager, `npm`
|
||||
(version `>=2.14.5 <3.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
source or as a pre-packaged bundle.
|
||||
|
||||
* [Java Development Kit](http://www.oracle.com/technetwork/es/java/javase/downloads/index.html) which is used
|
||||
to execute the selenium standalone server for e2e testing.
|
||||
* [Chrome Canary](https://www.google.com/chrome/browser/canary.html), a version of Chrome with
|
||||
bleeding edge functionality, built especially for developers (and early adopters).
|
||||
|
||||
* [Bower](http://bower.io/).
|
||||
|
||||
|
||||
## Getting the Sources
|
||||
|
||||
@ -50,9 +68,36 @@ cd angular
|
||||
# Add the main Angular repository as an upstream remote to your repository:
|
||||
git remote add upstream https://github.com/angular/angular.git
|
||||
```
|
||||
## Installing NPM Modules
|
||||
|
||||
Next, install the JavaScript modules needed to build and test Angular:
|
||||
## Environment Variable Setup
|
||||
|
||||
Define the environment variables listed below. These are mainly needed for the testing. The
|
||||
notation shown here is for [`bash`](http://www.gnu.org/software/bash); adapt as appropriate for
|
||||
your favorite shell.
|
||||
|
||||
Examples given below of possible values for initializing the environment variables assume **Mac OS
|
||||
X** and that you have installed the Dart Editor in the directory named by
|
||||
`DART_EDITOR_DIR=/Applications/dart`. This is only for illustrative purposes.
|
||||
|
||||
```shell
|
||||
# DARTIUM_BIN: path to a Dartium browser executable; used by Karma to run Dart tests
|
||||
export DARTIUM_BIN="$DART_EDITOR_DIR/chromium/Chromium.app/Contents/MacOS/Chromium"
|
||||
```
|
||||
|
||||
Add the Dart SDK `bin` directory to your path and/or define `DART_SDK` (this is also detailed
|
||||
[here](https://www.dartlang.org/tools/pub/installing.html)):
|
||||
|
||||
```shell
|
||||
# DART_SDK: path to a Dart SDK directory
|
||||
export DART_SDK="$DART_EDITOR_DIR/dart-sdk"
|
||||
|
||||
# Update PATH to include the Dart SDK bin directory
|
||||
PATH+=":$DART_SDK/bin"
|
||||
```
|
||||
|
||||
## Installing NPM Modules and Dart Packages
|
||||
|
||||
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
|
||||
|
||||
```shell
|
||||
# Install Angular project dependencies (package.json)
|
||||
@ -74,67 +119,219 @@ use in these instructions.
|
||||
*Option 2*: defining a bash alias like `alias nbin='PATH=$(npm bin):$PATH'` as detailed in this
|
||||
[Stackoverflow answer](http://stackoverflow.com/questions/9679932/how-to-use-package-installed-locally-in-node-modules/15157360#15157360) and used like this: e.g., `nbin gulp build`.
|
||||
|
||||
## Windows only
|
||||
## Build commands
|
||||
|
||||
To build Angular and prepare tests, run:
|
||||
|
||||
In order to create the right symlinks, run **as administrator**:
|
||||
```shell
|
||||
./scripts/windows/create-symlinks.sh
|
||||
$(npm bin)/gulp build
|
||||
```
|
||||
|
||||
Before submitting a PR, do not forget to remove them:
|
||||
```shell
|
||||
./scripts/windows/remove-symlinks.sh
|
||||
```
|
||||
Notes:
|
||||
* Results are put in the `dist` folder.
|
||||
* This will also run `pub get` for the subfolders in `modules` and run `dartanalyzer` for
|
||||
every file that matches `<module>/src/<module>.dart`, e.g. `di/src/di.dart`.
|
||||
|
||||
## Building
|
||||
You can selectively build either the JS or Dart versions as follows:
|
||||
|
||||
To build Angular run:
|
||||
* `$(npm bin)/gulp build.js`
|
||||
* `$(npm bin)/gulp build.dart`
|
||||
|
||||
Also note that in order for the whole test suite to succeed you will need to generate the type definitions by running:
|
||||
|
||||
```shell
|
||||
./build.sh
|
||||
$(npm bin)/gulp docs/typings
|
||||
```
|
||||
|
||||
* Results are put in the dist folder.
|
||||
To clean out the `dist` folder, run:
|
||||
|
||||
```shell
|
||||
$(npm bin)/gulp clean
|
||||
```
|
||||
|
||||
## Running Tests Locally
|
||||
|
||||
To run tests:
|
||||
### Full test suite
|
||||
|
||||
* `npm test`: full test suite for both JS and Dart versions of Angular. These are the same tests
|
||||
that run on Travis.
|
||||
|
||||
You can selectively run either the JS or Dart versions as follows:
|
||||
|
||||
* `$(npm bin)/gulp test.all.js`
|
||||
* `$(npm bin)/gulp test.all.dart`
|
||||
|
||||
### Unit tests
|
||||
|
||||
You can run just the unit tests as follows:
|
||||
|
||||
* `$(npm bin)/gulp test.unit.js`: JS tests in a browser; runs in **watch mode** (i.e.
|
||||
watches the test files for changes and re-runs tests when files are updated).
|
||||
* `$(npm bin)/gulp test.unit.cjs`: JS tests in NodeJS; runs in **watch mode**.
|
||||
* `$(npm bin)/gulp test.unit.dart`: Dart tests in Dartium; runs in **watch mode**.
|
||||
|
||||
If you prefer running tests in "single-run" mode rather than watch mode use:
|
||||
|
||||
* `$(npm bin)/gulp test.unit.js/ci`
|
||||
* `$(npm bin)/gulp test.unit.cjs/ci`
|
||||
* `$(npm bin)/gulp test.unit.dart/ci`
|
||||
|
||||
The task updates the dist folder with transpiled code whenever a source or test file changes, and
|
||||
Karma is run against the new output.
|
||||
|
||||
**Note**: If you want to only run a single test you can alter the test you wish to run by changing
|
||||
`it` to `iit` or `describe` to `ddescribe`. This will only run that individual test and make it
|
||||
much easier to debug. `xit` and `xdescribe` can also be useful to exclude a test and a group of
|
||||
tests respectively.
|
||||
|
||||
**Note**: **watch mode** needs symlinks to work, so if you're using windows, ensure you have the
|
||||
rights to built them in your operating system.
|
||||
|
||||
### E2E tests
|
||||
|
||||
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder).
|
||||
2. `$(npm bin)/gulp serve.js.prod serve.dart` (runs a local webserver).
|
||||
3. `$(npm bin)/protractor protractor-js.conf.js`: JS e2e tests.
|
||||
4. `$(npm bin)/protractor protractor-dart2js.conf.js`: dart2js e2e tests.
|
||||
|
||||
Angular specific command line options when running protractor:
|
||||
- `$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
|
||||
|
||||
### Performance tests
|
||||
|
||||
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder)
|
||||
2. `$(npm bin)/gulp serve.js.prod serve.dart` (runs a local webserver)
|
||||
3. `$(npm bin)/protractor protractor-js.conf.js --benchmark`: JS performance tests
|
||||
4. `$(npm bin)/protractor protractor-dart2js.conf.js --benchmark`: dart2js performance tests
|
||||
|
||||
Angular specific command line options when running protractor (e.g. force gc, ...):
|
||||
`$(npm bin)/protractor protractor-{js|dart2js}-conf.js --ng-help`
|
||||
|
||||
## Formatting with <a name="clang-format">clang-format</a>
|
||||
|
||||
We use [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to automatically enforce code
|
||||
style for our TypeScript code. This allows us to focus our code reviews more on the content, and
|
||||
less on style nit-picking. It also lets us encode our style guide in the `.clang-format` file in the
|
||||
repository, allowing many tools and editors to share our settings.
|
||||
|
||||
To check the formatting of your code, run
|
||||
|
||||
gulp check-format
|
||||
|
||||
Note that the continuous build on Travis runs `gulp enforce-format`. Unlike the `check-format` task,
|
||||
this will actually fail the build if files aren't formatted according to the style guide.
|
||||
|
||||
Your life will be easier if you include the formatter in your standard workflow. Otherwise, you'll
|
||||
likely forget to check the formatting, and waste time waiting for a build on Travis that fails due
|
||||
to some whitespace difference.
|
||||
|
||||
* Install clang-format with `npm install -g clang-format`.
|
||||
* Use `clang-format -i [file name]` to format a file (or multiple).
|
||||
Note that `clang-format` tries to load a `clang-format` node module close to the sources being
|
||||
formatted, or from the `$CWD`, and only then uses the globally installed one - so the version used
|
||||
should automatically match the one required by the project.
|
||||
Use `clang-format -version` in case you get confused.
|
||||
* Use `gulp enforce-format` to check if your code is `clang-format` clean. This also gives
|
||||
you a command line to format your code.
|
||||
* `clang-format` also includes a git hook, run `git clang-format` to format all files you
|
||||
touched.
|
||||
* You can run this as a **git pre-commit hook** to automatically format your delta regions when you
|
||||
commit a change. In the angular repo, run
|
||||
|
||||
```
|
||||
$ echo -e '#!/bin/sh\nexec git clang-format' > .git/hooks/pre-commit
|
||||
$ chmod u+x !$
|
||||
```
|
||||
|
||||
* **WebStorm** can run clang-format on the current file.
|
||||
1. Under Preferences, open Tools > External Tools.
|
||||
1. Plus icon to Create Tool
|
||||
1. Fill in the form:
|
||||
- Name: clang-format
|
||||
- Description: Format
|
||||
- Synchronize files after execution: checked
|
||||
- Open console: not checked
|
||||
- Show in: Editor menu
|
||||
- Program: [path to clang-format, try `$ echo $(npm config get prefix)/bin/clang-format`]
|
||||
- Parameters: `-i -style=file $FilePath$`
|
||||
- Working directory: `$ProjectFileDir$`
|
||||
* `clang-format` integrations are also available for many popular editors (`vim`, `emacs`,
|
||||
`Sublime Text`, etc.).
|
||||
|
||||
## Generating the API documentation
|
||||
|
||||
The following gulp task will generate the API docs in the `dist/angular.io/partials/api/angular2`:
|
||||
|
||||
```shell
|
||||
$ ./test.sh node # Run all angular tests on node
|
||||
|
||||
$ ./test.sh browser # Run all angular tests in browser
|
||||
$ ./test.sh browserNoRouter # Optionally run all angular tests without router in browser
|
||||
|
||||
$ ./test.sh tools # Run angular tooling (not framework) tests
|
||||
$(npm bin)/gulp docs/angular.io
|
||||
```
|
||||
|
||||
You should execute the 3 test suites before submitting a PR to github.
|
||||
You can serve the generated documentation to check how it would render on [angular.io](https://angular.io/):
|
||||
- check out the [angular.io repo](https://github.com/angular/angular.io) locally,
|
||||
- install dependencies as described in the [angular.io README](https://github.com/angular/angular.io/blob/master/README.md),
|
||||
- copy the generated documentation from your local angular repo at `angular/dist/angular.io/partials/api/angular2` to your local angular.io repo at `angular.io/public/docs/js/latest/api`,
|
||||
- run `harp compile` at the root of the angular.io repo to check the generated documentation for errors,
|
||||
- run `harp server` and open a browser at `http://localhost:9000/docs/js/latest/api/` to check the rendered documentation.
|
||||
|
||||
## Project Information
|
||||
|
||||
All the tests are executed on our Continuous Integration infrastructure and a PR could only be merged once the tests pass.
|
||||
### Folder structure
|
||||
|
||||
- CircleCI fails if your code is not formatted properly,
|
||||
- Travis CI fails if any of the test suites described above fails.
|
||||
* `modules/*`: modules that will be loaded in the browser
|
||||
* `tools/*`: tools that are needed to build Angular
|
||||
* `dist/*`: build files are placed here.
|
||||
|
||||
## Update the public API tests
|
||||
### File suffixes
|
||||
|
||||
If you happen to modify the public API of Angular, API golden files must be updated using:
|
||||
* `*.ts`: TypeScript files that get transpiled to Dart and EcmaScript 5/6
|
||||
* `*.dart`: Dart files that don't get transpiled
|
||||
|
||||
``` shell
|
||||
$ gulp public-api:update
|
||||
```
|
||||
## CI using Travis
|
||||
|
||||
Note: The command `./test.sh tools` fails when the API doesn't match the golden files.
|
||||
For instructions on setting up Continuous Integration using Travis, see the instructions given
|
||||
[here](https://github.com/angular/angular.dart/blob/master/travis.md).
|
||||
|
||||
## Formatting your source code
|
||||
## Transforming Dart code
|
||||
|
||||
Angular uses [clang-format](http://clang.llvm.org/docs/ClangFormat.html) to format the source code. If the source code
|
||||
is not properly formatted, the CI will fail and the PR can not be merged.
|
||||
See the [wiki](//github.com/angular/angular/wiki/Angular-2-Dart-Transformer).
|
||||
|
||||
You can automatically format your code by running:
|
||||
## Debugging
|
||||
|
||||
``` shell
|
||||
$ gulp format
|
||||
```
|
||||
### Debug the transpiler
|
||||
|
||||
If you need to debug the transpiler:
|
||||
|
||||
- add a `debugger;` statement in the transpiler code,
|
||||
- from the root folder, execute `node debug $(npm bin)/gulp build` to enter the node
|
||||
debugger
|
||||
- press "c" to execute the program until you reach the `debugger;` statement,
|
||||
- you can then type "repl" to enter the REPL and inspect variables in the context.
|
||||
|
||||
See the [Node.js manual](http://nodejs.org/api/debugger.html) for more information.
|
||||
|
||||
Notes:
|
||||
- You can also execute `node $(npm bin)/karma start karma-dart.conf.js` depending on which
|
||||
code you want to debug (the former will process the "modules" folder while the later processes
|
||||
the transpiler specs).
|
||||
- You can also add `debugger;` statements in the specs (JavaScript). The execution will halt when
|
||||
the developer tools are opened in the browser running Karma.
|
||||
|
||||
### Debug the tests
|
||||
|
||||
If you need to debug the tests:
|
||||
|
||||
- add a `debugger;` statement to the test you want to debug (or the source code),
|
||||
- execute karma `$(npm bin)/gulp test.js`,
|
||||
- press the top right "DEBUG" button,
|
||||
- open the DevTools and press F5,
|
||||
- the execution halts at the `debugger;` statement
|
||||
|
||||
**Note (WebStorm users)**:
|
||||
|
||||
1. Create a Karma run config from WebStorm.
|
||||
2. Then in the "Run" menu, press "Debug 'karma-js.conf.js'", and WebStorm will stop in the generated
|
||||
code on the `debugger;` statement.
|
||||
3. You can then step into the code and add watches.
|
||||
|
||||
The `debugger;` statement is needed because WebStorm will stop in a transpiled file. Breakpoints in
|
||||
the original source files are not supported at the moment.
|
||||
|
215
LICENSE
215
LICENSE
@ -1,21 +1,202 @@
|
||||
The MIT License
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
Copyright (c) 2014-2016 Google, Inc. http://angular.io
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
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:
|
||||
1. Definitions.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright {yyyy} {name of copyright owner}
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
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.
|
||||
|
36
README.md
36
README.md
@ -1,37 +1,43 @@
|
||||
[](https://travis-ci.org/angular/angular)
|
||||
[](https://circleci.com/gh/angular/angular/tree/master)
|
||||
[](https://travis-ci.org/angular/angular)
|
||||
[](https://gitter.im/angular/angular?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](https://badge.fury.io/js/%40angular%2Fcore)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://badge.fury.io/js/angular2)
|
||||
[](https://npmjs.org/package/angular2)
|
||||
[](https://saucelabs.com/u/angular2-ci)
|
||||
|
||||
[](https://saucelabs.com/u/angular2-ci)
|
||||
*Safari (7+), iOS (7+), Edge (14) and IE mobile (11) are tested on [BrowserStack][browserstack].*
|
||||
|
||||
Angular
|
||||
Angular
|
||||
=========
|
||||
|
||||
Angular is a development platform for building mobile and desktop web applications. This is the
|
||||
repository for [Angular 2][ng2] Typescript/JavaScript (JS).
|
||||
|
||||
Angular2 for [Dart][dart] can be found at [dart-lang/angular2][ng2dart].
|
||||
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
|
||||
|
||||
Angular 2 is currently in **Developer Preview**. We recommend using Angular 1.X for production
|
||||
applications:
|
||||
|
||||
* [AngularJS][ngJS]: [angular/angular.js](http://github.com/angular/angular.js).
|
||||
* [AngularDart][ngDart]: [angular/angular.dart](http://github.com/angular/angular.dart).
|
||||
|
||||
## Quickstart
|
||||
|
||||
[Get started in 5 minutes][quickstart].
|
||||
|
||||
## Setup & Install Angular 2
|
||||
|
||||
Follow the instructions given on the [Angular download page][download].
|
||||
|
||||
|
||||
## Want to help?
|
||||
|
||||
Want to file a bug, contribute some code, or improve documentation? Excellent! Read up on our
|
||||
guidelines for [contributing][contributing] and then check out one of our issues in the [hotlist: community-help](https://github.com/angular/angular/labels/hotlist%3A%20community-help).
|
||||
|
||||
[browserstack]: https://www.browserstack.com/
|
||||
|
||||
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||
[dart]: http://www.dartlang.org
|
||||
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
|
||||
[dartium]: http://www.dartlang.org/tools/dartium
|
||||
[download]: http://angular.io/download/
|
||||
[quickstart]: https://angular.io/docs/js/latest/quickstart.html
|
||||
[ng2]: http://angular.io
|
||||
[ngDart]: http://angulardart.org
|
||||
[ngJS]: http://angularjs.org
|
||||
[ng2dart]: https://github.com/dart-lang/angular2
|
||||
|
140
TOOLS.md
140
TOOLS.md
@ -1,140 +1,4 @@
|
||||
# Developer Tools for Angular 2
|
||||
|
||||
Here you will find a collection of tools and tips for keeping your application
|
||||
perform well and contain fewer bugs.
|
||||
|
||||
## Angular debug tools in the dev console
|
||||
|
||||
Angular provides a set of debug tools that are accessible from any browser's
|
||||
developer console. In Chrome the dev console can be accessed by pressing
|
||||
Ctrl + Shift + j.
|
||||
|
||||
### Enabling debug tools
|
||||
|
||||
By default the debug tools are disabled. You can enable debug tools as follows:
|
||||
|
||||
```typescript
|
||||
import {enableDebugTools} from '@angular/platform-browser';
|
||||
|
||||
bootstrap(Application).then((appRef) => {
|
||||
enableDebugTools(appRef);
|
||||
});
|
||||
```
|
||||
|
||||
### Using debug tools
|
||||
|
||||
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
|
||||
top level object is called `ng` and contains more specific tools inside it.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics it is important to find the root cause of the issue. Change detection
|
||||
is a phase in Angular's lifecycle that detects changes in values that are
|
||||
bound to UI, and if it finds a change it performs the corresponding UI update.
|
||||
However, sometimes it is hard to tell if the slowness is due to the act of
|
||||
computing the changes being slow, or due to the act of applying those changes
|
||||
to the UI. For your application to be performant it is important that the
|
||||
process of computing changes is very fast. For best results it should be under
|
||||
3 milliseconds in order to leave room for the application logic, the UI updates
|
||||
and browser's rendering pipeline to fit withing the 16 millisecond frame
|
||||
(assuming the 60 FPS target frame rate).
|
||||
|
||||
Change detection profiler repeatedly performs change detection without invoking
|
||||
any user actions, such as clicking buttons or entering text in input fields. It
|
||||
then computes the average amount of time it took to perform a single cycle of
|
||||
change detection in milliseconds and prints it to the console. This number
|
||||
depends on the current state of the UI. You will likely see different numbers
|
||||
as you go from one screen in your application to another.
|
||||
|
||||
#### Running the profiler
|
||||
|
||||
Enable debug tools (see above), then in the dev console enter the following:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results will be printed to the console.
|
||||
|
||||
#### Recording CPU profile
|
||||
|
||||
Pass `{record: true}` an argument:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then open the "Profiles" tab. You will see the recorded profile titled
|
||||
"Change Detection". In Chrome, if you record the profile repeatedly, all the
|
||||
profiles will be nested under "Change Detection".
|
||||
|
||||
#### Interpreting the numbers
|
||||
|
||||
In a properly-designed application repeated attempts to detect changes without
|
||||
any user actions should result in no changes to be applied on the UI. It is
|
||||
also desirable to have the cost of a user action be proportional to the amount
|
||||
of UI changes required. For example, popping up a menu with 5 items should be
|
||||
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
|
||||
change detection with no UI updates should be as fast as possible. Ideally the
|
||||
number printed by the profiler should be well below the length of a single
|
||||
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
|
||||
|
||||
#### Investigating slow change detection
|
||||
|
||||
So you found a screen in your application on which the profiler reports a very
|
||||
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
|
||||
recording while profiling:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then look for hot spots using
|
||||
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
|
||||
|
||||
#### Reducing change detection cost
|
||||
|
||||
There are many reasons for slow change detection. To gain intuition about
|
||||
possible causes it would help to understand how change detection works. Such a
|
||||
discussion is outside the scope of this document (TODO link to docs), but here
|
||||
are some key concepts in brief.
|
||||
|
||||
By default Angular uses "dirty checking" mechanism for finding model changes.
|
||||
This mechanism involves evaluating every bound expression that's active on the
|
||||
UI. These usually include text interpolation via `{{expression}}` and property
|
||||
bindings via `[prop]="expression"`. If any of the evaluated expressions are
|
||||
costly to compute they could contribute to slow change detection. A good way to
|
||||
speed things up is to use plain class fields in your expressions and avoid any
|
||||
kinds of computation. Example:
|
||||
|
||||
```typescript
|
||||
@Component({
|
||||
template: '<button [enabled]="isEnabled">{{title}}</button>'
|
||||
})
|
||||
class FancyButton {
|
||||
// GOOD: no computation, just return the value
|
||||
isEnabled: boolean;
|
||||
|
||||
// BAD: computes the final value upon request
|
||||
_title: String;
|
||||
get title(): String { return this._title.trim().toUpperCase(); }
|
||||
}
|
||||
```
|
||||
|
||||
Most cases like these could be solved by precomputing the value and storing the
|
||||
final value in a field.
|
||||
|
||||
Angular also supports a second type of change detection - the "push" model. In
|
||||
this model Angular does not poll your component for changes. Instead, the
|
||||
component "tells" Angular when it changes and only then does Angular perform
|
||||
the update. This model is suitable in situations when your data model uses
|
||||
observable or immutable objects (also a discussion for another time).
|
||||
- [JavaScript](TOOLS_JS.md)
|
||||
- [Dart](TOOLS_DART.md)
|
||||
|
324
TOOLS_DART.md
Normal file
324
TOOLS_DART.md
Normal file
@ -0,0 +1,324 @@
|
||||
# Developer Tools for Dart
|
||||
|
||||
Use these tools and techniques to increase your app's performance
|
||||
and reliability.
|
||||
|
||||
* [Angular debugging tools](#angular-debugging-tools)
|
||||
* [Code size](#code-size)
|
||||
* [Performance](#performance)
|
||||
|
||||
|
||||
## Angular debugging tools
|
||||
|
||||
Starting with alpha.38, Angular provides a set of debugging tools
|
||||
that are accessible from any browser's developer console.
|
||||
In Chrome, you can get to the dev console by pressing
|
||||
Ctrl + Shift + J (on Mac: Cmd + Opt + J).
|
||||
|
||||
### Enabling the debugging tools
|
||||
|
||||
By default the debugging tools are disabled.
|
||||
Enable the debugging tools as follows:
|
||||
|
||||
```dart
|
||||
import 'package:angular2/tools.dart';
|
||||
|
||||
main() async {
|
||||
var appRef = await bootstrap(Application);
|
||||
enableDebugTools(appRef);
|
||||
}
|
||||
```
|
||||
|
||||
<!-- Change function name to enableDebuggingTools? -->
|
||||
|
||||
|
||||
### Using the debugging tools
|
||||
|
||||
In the browser, open the dev console. The top-level object is called `ng` and
|
||||
contains more specific tools inside it.
|
||||
|
||||
For example, to run the change detection profiler on your app:
|
||||
<!-- QUESTION: is "on your app" accurate?
|
||||
is "run the change detection profiler on your app" the best wording? -->
|
||||
|
||||
```javascript
|
||||
// In the dev console:
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The [Change detection profiler](#change-detection-profiler) section
|
||||
has more details.
|
||||
<!-- Point to API docs when they're published, if they're useful.
|
||||
They should be under
|
||||
http://www.dartdocs.org/documentation/angular2/latest
|
||||
and/or
|
||||
https://angular.io/docs/js/latest/api/. -->
|
||||
|
||||
|
||||
## Code size
|
||||
|
||||
Code must be downloaded, parsed, and executed. Too much code can lead to
|
||||
slow application start-up time, especially on slow networks and low-end devices.
|
||||
The tools and techniques in this section can help you to identify
|
||||
unnecessarily large code and to reduce code size.
|
||||
|
||||
### Finding contributors to code size
|
||||
|
||||
Options for investigating code size include the `--dump-info` dart2js option,
|
||||
ng2soyc, `reflector.trackUsage()`, and code coverage information
|
||||
from the Dart VM.
|
||||
|
||||
#### --dump-info
|
||||
|
||||
The `--dump-info` option of `dart2js` outputs information about what happened
|
||||
during compilation. You can specify `--dump-info` in `pubspec.yaml`:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
...
|
||||
- $dart2js:
|
||||
commandLineOptions:
|
||||
- --dump-info
|
||||
```
|
||||
|
||||
The [Dump Info Visualizer](https://github.com/dart-lang/dump-info-visualizer)
|
||||
can help you analyze the output.
|
||||
For more information, see the
|
||||
[dart2js_info API reference](http://dart-lang.github.io/dart2js_info/doc/api/).
|
||||
|
||||
#### ng2soyc.dart
|
||||
|
||||
[ng2soyc](https://github.com/angular/ng2soyc.dart) is a utility for analyzing
|
||||
code size contributors in Angular 2 applications. It groups code size by
|
||||
library and, assuming your library names follow
|
||||
[standard naming conventions](https://www.dartlang.org/articles/style-guide/#do-prefix-library-names-with-the-package-name-and-a-dot-separated-path)
|
||||
(package.library.sublibrary...), gives the code size breakdown at
|
||||
each level. To reduce noise in the output of very large apps, ng2soyc provides
|
||||
an option to hide libraries that are too small, so you can focus on the biggest
|
||||
contributors.
|
||||
|
||||
#### Track unused reflection data
|
||||
|
||||
<!-- QUESTION: How do you get access to reflector & ReflectionInfo? -->
|
||||
|
||||
Call `reflector.trackUsage()` to track reflection information used
|
||||
by the application. Reflection information (`ReflectionInfo`) is a data
|
||||
structure that stores information about your application that Angular uses for
|
||||
locating DI factories, generated change detectors and other code related to a
|
||||
given type. After exercising your application, call `reflector.listUnusedKeys()`
|
||||
to get a list of types and functions whose reflection information was retained
|
||||
but never used by the application.
|
||||
|
||||
#### Use code coverage to find dead code
|
||||
|
||||
When running in Dartium (or in the Dart VM, in general) you can request code
|
||||
coverage information from the VM. You can either use
|
||||
[observatory](https://www.dartlang.org/tools/observatory/) or download
|
||||
the coverage file and use your own tools to inspect it. Lines of code that are
|
||||
not covered are top candidates for dead code.
|
||||
|
||||
Keep in mind, however, that uncovered code is not sufficient evidence of dead
|
||||
code, only necessary evidence. It is perfectly possible that you simply didn't
|
||||
exercise your application in a way that triggers the execution of uncovered
|
||||
code. A common example is error handling code. Just because your testing never
|
||||
encountered an error does not mean the error won't happen in production. You
|
||||
therefore don't have to rush and remove all the `catch` blocks.
|
||||
|
||||
### Reducing code size
|
||||
|
||||
To reduce code size, you can disable reflection,
|
||||
enable minification, and manually remove dead code.
|
||||
You can also try less safe options such as
|
||||
telling dart2js to trust type annotations.
|
||||
|
||||
|
||||
#### Disable reflection
|
||||
|
||||
`dart:mirrors` allows discovering program metadata at runtime. However, this
|
||||
means that `dart2js` needs to retain that metadata and thus increase the size
|
||||
of resulting JS output. In practice, however, it is possible to extract most
|
||||
metadata necessary for your metaprogramming tasks statically using a
|
||||
transformer and `package:analyzer`, and act on it before compiling to JS.
|
||||
|
||||
#### Enable minification
|
||||
|
||||
Minification shortens all your `longMethodNames` into 2- or 3-letter long
|
||||
symbols. `dart2js` ensures that this kind of renaming is done safely, without
|
||||
breaking the functionality of your programs. You can enable it in `pubspec.yaml`
|
||||
under `$dart2js` transformer:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
...
|
||||
- $dart2js:
|
||||
minify: true
|
||||
```
|
||||
|
||||
#### Manually remove dead code
|
||||
|
||||
`dart2js` comes with dead code elimination out-of-the-box. However, it may not
|
||||
always be able to tell if a piece of code could be used. Consider the following
|
||||
example:
|
||||
|
||||
```dart
|
||||
/// This function decides which serialization format to use
|
||||
void setupSerializers() {
|
||||
if (server.doYouSupportProtocolBuffers()) {
|
||||
useProtobufSerializers();
|
||||
} else {
|
||||
useJsonSerializers();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In this example the application asks the server what kind of serialization
|
||||
format it uses and dynamically chooses one or the other. `dart2js` can't
|
||||
tell whether the server responds with yes or no, so it must retain both
|
||||
kinds of serializers. However, if you know that your server supports
|
||||
protocol buffers, you can remove that `if` block entirely and default to
|
||||
protocol buffers.
|
||||
|
||||
Code coverage (see above) is a good way to find dead code in your app.
|
||||
|
||||
#### Unsafe options
|
||||
|
||||
Dart also provides more aggressive optimization options. However, you have to
|
||||
be careful when using them and as of today the benefits aren't that clear. If
|
||||
your type annotations are inaccurate you may end up with non-Darty runtime
|
||||
behavior, including the classic "undefined is not a function" tautology, as
|
||||
well as the "keep on truckin'" behavior, e.g. `null + 1 == 1` and
|
||||
`{} + [] == 0`.
|
||||
|
||||
`--trust-type-annotations` tells `dart2js` to trust that your type annotations
|
||||
are correct. So if you have a function `foo(Bar bar)` the compiler can omit the
|
||||
check that `bar` is truly `Bar` when calling methods on it.
|
||||
|
||||
`--trust-primitives` tells `dart2js` that primitive types, such as numbers and
|
||||
booleans are never `null` when performing arithmetic, and that your program
|
||||
does not run into range error when operating on lists, letting the compiler
|
||||
remove some of the error checking code.
|
||||
|
||||
Specify these options in `pubspec.yaml`.
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
...
|
||||
- $dart2js:
|
||||
commandLineOptions:
|
||||
- --trust-type-annotations
|
||||
- --trust-primitives
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics it is important to find the root cause of the issue. Change detection
|
||||
is a phase in Angular's lifecycle that detects changes in values that are
|
||||
bound to UI, and if it finds a change it performs the corresponding UI update.
|
||||
However, sometimes it is hard to tell if the slowness is due to the act of
|
||||
computing the changes being slow, or due to the act of applying those changes
|
||||
to the UI. For your application to be performant it is important that the
|
||||
process of computing changes is very fast. For best results it should be under
|
||||
3 milliseconds in order to leave room for the application logic, the UI updates
|
||||
and browser's rendering pipeline to fit withing the 16 millisecond frame
|
||||
(assuming the 60 FPS target frame rate).
|
||||
|
||||
Change detection profiler repeatedly performs change detection without invoking
|
||||
any user actions, such as clicking buttons or entering text in input fields. It
|
||||
then computes the average amount of time it took to perform a single cycle of
|
||||
change detection in milliseconds and prints it to the console. This number
|
||||
depends on the current state of the UI. You are likely to see different numbers
|
||||
as you go from one screen in your application to another.
|
||||
|
||||
#### Running the profiler
|
||||
|
||||
Enable the debugging tools (see above),
|
||||
then in the dev console enter the following:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results are printed to the console.
|
||||
|
||||
#### Recording CPU profiles
|
||||
|
||||
To record a profile, pass `{record: true}` to `timeChangeDetection()`:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then open the **Profiles** tab. The recorded profile has the title
|
||||
**Change Detection**. In Chrome, if you record the profile repeatedly, all the
|
||||
profiles are nested under Change Detection.
|
||||
|
||||
#### Interpreting the numbers
|
||||
|
||||
In a properly designed application, repeated attempts to detect changes without
|
||||
any user actions result in no changes to the UI. It is
|
||||
also desirable to have the cost of a user action be proportional to the amount
|
||||
of UI changes required. For example, popping up a menu with 5 items should be
|
||||
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
|
||||
change detection with no UI updates should be as fast as possible. Ideally the
|
||||
number printed by the profiler should be well below the length of a single
|
||||
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
|
||||
|
||||
#### Investigating slow change detection
|
||||
|
||||
So you found a screen in your application on which the profiler reports a very
|
||||
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
|
||||
recording while profiling:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then look for hot spots using
|
||||
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
|
||||
|
||||
#### Reducing change detection cost
|
||||
|
||||
There are many reasons for slow change detection. To gain intuition about
|
||||
possible causes it helps to understand how change detection works. Such a
|
||||
discussion is outside the scope of this document,
|
||||
but here are some key concepts.
|
||||
|
||||
<!-- TODO: link to change detection docs -->
|
||||
|
||||
By default, Angular uses a _dirty checking_ mechanism to find model changes.
|
||||
This mechanism involves evaluating every bound expression that's active on the
|
||||
UI. These usually include text interpolation via `{{expression}}` and property
|
||||
bindings via `[prop]="expression"`. If any of the evaluated expressions are
|
||||
costly to compute, they might contribute to slow change detection. A good way to
|
||||
speed things up is to use plain class fields in your expressions and avoid any
|
||||
kind of computation. For example:
|
||||
|
||||
```dart
|
||||
@View(
|
||||
template: '<button [enabled]="isEnabled">{{title}}</button>'
|
||||
)
|
||||
class FancyButton {
|
||||
// GOOD: no computation, just returns the value
|
||||
bool isEnabled;
|
||||
|
||||
// BAD: computes the final value upon request
|
||||
String _title;
|
||||
String get title => _title.trim().toUpperCase();
|
||||
}
|
||||
```
|
||||
|
||||
Most cases like these can be solved by precomputing the value and storing the
|
||||
final value in a field.
|
||||
|
||||
Angular also supports a second type of change detection: the _push_ model. In
|
||||
this model, Angular does not poll your component for changes. Instead, the
|
||||
component tells Angular when it changes, and only then does Angular perform
|
||||
the update. This model is suitable in situations when your data model uses
|
||||
observable or immutable objects.
|
||||
|
||||
<!-- TODO: link to discussion of push model -->
|
140
TOOLS_JS.md
Normal file
140
TOOLS_JS.md
Normal file
@ -0,0 +1,140 @@
|
||||
# Developer Tools for JavaScript
|
||||
|
||||
Here you will find a collection of tools and tips for keeping your application
|
||||
perform well and contain fewer bugs.
|
||||
|
||||
## Angular debug tools in the dev console
|
||||
|
||||
Angular provides a set of debug tools that are accessible from any browser's
|
||||
developer console. In Chrome the dev console can be accessed by pressing
|
||||
Ctrl + Shift + j.
|
||||
|
||||
### Enabling debug tools
|
||||
|
||||
By default the debug tools are disabled. You can enable debug tools as follows:
|
||||
|
||||
```typescript
|
||||
import 'angular2/tools';
|
||||
|
||||
bootstrap(Application).then((appRef) => {
|
||||
enableDebugTools(appRef);
|
||||
});
|
||||
```
|
||||
|
||||
### Using debug tools
|
||||
|
||||
In the browser open the developer console (Ctrl + Shift + j in Chrome). The
|
||||
top level object is called `ng` and contains more specific tools inside it.
|
||||
|
||||
Example:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics it is important to find the root cause of the issue. Change detection
|
||||
is a phase in Angular's lifecycle that detects changes in values that are
|
||||
bound to UI, and if it finds a change it performs the corresponding UI update.
|
||||
However, sometimes it is hard to tell if the slowness is due to the act of
|
||||
computing the changes being slow, or due to the act of applying those changes
|
||||
to the UI. For your application to be performant it is important that the
|
||||
process of computing changes is very fast. For best results it should be under
|
||||
3 milliseconds in order to leave room for the application logic, the UI updates
|
||||
and browser's rendering pipeline to fit withing the 16 millisecond frame
|
||||
(assuming the 60 FPS target frame rate).
|
||||
|
||||
Change detection profiler repeatedly performs change detection without invoking
|
||||
any user actions, such as clicking buttons or entering text in input fields. It
|
||||
then computes the average amount of time it took to perform a single cycle of
|
||||
change detection in milliseconds and prints it to the console. This number
|
||||
depends on the current state of the UI. You will likely see different numbers
|
||||
as you go from one screen in your application to another.
|
||||
|
||||
#### Running the profiler
|
||||
|
||||
Enable debug tools (see above), then in the dev console enter the following:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results will be printed to the console.
|
||||
|
||||
#### Recording CPU profile
|
||||
|
||||
Pass `{record: true}` an argument:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then open the "Profiles" tab. You will see the recorded profile titled
|
||||
"Change Detection". In Chrome, if you record the profile repeatedly, all the
|
||||
profiles will be nested under "Change Detection".
|
||||
|
||||
#### Interpreting the numbers
|
||||
|
||||
In a properly-designed application repeated attempts to detect changes without
|
||||
any user actions should result in no changes to be applied on the UI. It is
|
||||
also desirable to have the cost of a user action be proportional to the amount
|
||||
of UI changes required. For example, popping up a menu with 5 items should be
|
||||
vastly faster than rendering a table of 500 rows and 10 columns. Therefore,
|
||||
change detection with no UI updates should be as fast as possible. Ideally the
|
||||
number printed by the profiler should be well below the length of a single
|
||||
animation frame (16ms). A good rule of thumb is to keep it under 3ms.
|
||||
|
||||
#### Investigating slow change detection
|
||||
|
||||
So you found a screen in your application on which the profiler reports a very
|
||||
high number (i.e. >3ms). This is where a recorded CPU profile can help. Enable
|
||||
recording while profiling:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection({record: true});
|
||||
```
|
||||
|
||||
Then look for hot spots using
|
||||
[Chrome CPU profiler](https://developer.chrome.com/devtools/docs/cpu-profiling).
|
||||
|
||||
#### Reducing change detection cost
|
||||
|
||||
There are many reasons for slow change detection. To gain intuition about
|
||||
possible causes it would help to understand how change detection works. Such a
|
||||
discussion is outside the scope of this document (TODO link to docs), but here
|
||||
are some key concepts in brief.
|
||||
|
||||
By default Angular uses "dirty checking" mechanism for finding model changes.
|
||||
This mechanism involves evaluating every bound expression that's active on the
|
||||
UI. These usually include text interpolation via `{{expression}}` and property
|
||||
bindings via `[prop]="expression"`. If any of the evaluated expressions are
|
||||
costly to compute they could contribute to slow change detection. A good way to
|
||||
speed things up is to use plain class fields in your expressions and avoid any
|
||||
kinds of computation. Example:
|
||||
|
||||
```typescript
|
||||
@View({
|
||||
template: '<button [enabled]="isEnabled">{{title}}</button>'
|
||||
})
|
||||
class FancyButton {
|
||||
// GOOD: no computation, just return the value
|
||||
isEnabled: boolean;
|
||||
|
||||
// BAD: computes the final value upon request
|
||||
_title: String;
|
||||
get title(): String { return this._title.trim().toUpperCase(); }
|
||||
}
|
||||
```
|
||||
|
||||
Most cases like these could be solved by precomputing the value and storing the
|
||||
final value in a field.
|
||||
|
||||
Angular also supports a second type of change detection - the "push" model. In
|
||||
this model Angular does not poll your component for changes. Instead, the
|
||||
component "tells" Angular when it changes and only then does Angular perform
|
||||
the update. This model is suitable in situations when your data model uses
|
||||
observable or immutable objects (also a discussion for another time).
|
@ -1,72 +1,25 @@
|
||||
# Triage Process and Github Labels for Angular 2
|
||||
|
||||
This document describes how the Angular team uses labels and milestones
|
||||
to triage issues on github. The basic idea of the new process is that
|
||||
caretaker only assigns a component and type (bug, feature) label. The
|
||||
owner of the component than is in full control of how the issues should
|
||||
be triaged further.
|
||||
This document describes how the Angular team uses labels and milestones to triage issues on github.
|
||||
|
||||
Once this process is implemented and in use, we will revisit it to see
|
||||
if further labeling is needed.
|
||||
# Issues and PRs
|
||||
## Triaged vs Untriaged Issues
|
||||
|
||||
## Components
|
||||
Every triaged issue must have four attributes assigned to it:
|
||||
|
||||
A caretaker should be able to determine which component the issue
|
||||
belongs to. The components have a clear piece of source code associated
|
||||
with it.
|
||||
* `priority` -- P0 through P4. P0 issues are "drop everything and do this now". P4 are nice to have.
|
||||
* `component` -- Which area of Angular knowledge this relates to.
|
||||
* `effort` -- Rough assessment of how much work this issue is. E.g. `effort: easy` means
|
||||
"probably a few hours of work".
|
||||
* `type` -- Whether this issue is a bug, feature, or other kind of task.
|
||||
|
||||
* `comp: animations`: `@matsko`
|
||||
* `comp: benchpress`: `@tbosch`
|
||||
* `comp: build & ci`: `@IgorMinar` -- All build and CI scripts
|
||||
* `comp: common`: `@mhevery` -- This includes core components / pipes.
|
||||
* `comp: core & compiler`: `@tbosch` -- Because core and compiler are very
|
||||
intertwined, we will be treating them as one.
|
||||
* `comp: forms`: `@kara`
|
||||
* `comp: http`: `@jeffbcross`
|
||||
* `comp: i18n`: `@vicb`
|
||||
* `comp: metadata-extractor`: `@chuckjaz`
|
||||
* `comp: router`: `@vsavkin`
|
||||
* `comp: testing`: `@juliemr`
|
||||
* `comp: upgrade`: `@mhevery`
|
||||
* `comp: web-worker`: `@vicb`
|
||||
* `comp: zones`: `@mhevery`
|
||||
Untriaged issues are any issues in the queue that don't yet have these four attributes.
|
||||
|
||||
There are few components which are cross-cutting. They don't have
|
||||
a clear location in the source tree. We will treat them as a component
|
||||
even thought no specific source tree is associated with them.
|
||||
You can view a report of untriaged issues here, in our
|
||||
[Angular Triage Dashboard](http://mhevery.github.io/github_issues/).
|
||||
|
||||
* `comp: documentation`: `@naomiblack`
|
||||
* `comp: packaging`: `@IgorMinar`
|
||||
* `comp: performance`: `@tbosch`
|
||||
* `comp: security`: `@IgorMinar`
|
||||
|
||||
|
||||
## Type
|
||||
What kind of problem is this?
|
||||
|
||||
* `type: RFC / discussion / question`
|
||||
* `type: bug`
|
||||
* `type: chore`
|
||||
* `type: feature`
|
||||
* `type: performance`
|
||||
* `type: refactor`
|
||||
|
||||
## Caretaker Triage Process
|
||||
|
||||
It is the caretaker's responsibility to assign `comp: *` and `type: *`
|
||||
to each new issue as they come in. The reason why we limit the
|
||||
responsibility of the caretaker to these two labels is that it is
|
||||
unlikely that without domain knowledge the caretaker could add any
|
||||
additional labels of value.
|
||||
|
||||
|
||||
## Component's owner Triage Process
|
||||
|
||||
At this point we are leaving each component owner to determine their own
|
||||
process for their component.
|
||||
|
||||
It will be up to the component owner to determine the order in which the
|
||||
issues within the component will be resolved.
|
||||
Issues should also have a clear action to complete that can be addressed or resolved within the
|
||||
scope of Angular 2. We'll close issues that don't meet these criteria.
|
||||
|
||||
### Assigning Issues to Milestones
|
||||
|
||||
@ -84,10 +37,7 @@ We aim to only have at most three milestones open at a time:
|
||||
The [backlog](https://github.com/angular/angular/issues?q=is%3Aopen+is%3Aissue+no%3Amilestone)
|
||||
consists of all issues that have been triaged but do not have an assignee or milestone.
|
||||
|
||||
## Triaged vs Untrained PRs
|
||||
|
||||
PRs should also be label with a `comp: *` so that it is clear which
|
||||
primary area the PR effects.
|
||||
## Triaged vs Untriaged PRs
|
||||
|
||||
Because of the cumulative pain associated with rebasing PRs, we triage PRs daily, and
|
||||
closing or reviewing PRs is a top priority ahead of other ongoing work.
|
||||
@ -113,6 +63,90 @@ uncontroversial change.
|
||||
PRs do not need to be assigned to milestones, unless a milestone release should be held for that
|
||||
PR to land.
|
||||
|
||||
Victor (`vsavkin`) and Tobias (`tbosch`) are owners of the PR queue. Here is a list of [current
|
||||
untriaged PRs](https://github.com/angular/angular/pulls?utf8=%E2%9C%93&q=is%3Aopen+no%3Amilestone+is%3Apr+-label%3A%22pr_action%3A+cleanup%22+-label%3A%22pr_action%3A+merge%22+-label%3A%22pr_action%3A+review%22+-label%3A%22pr_action%3A+discuss%22+-label%3A%22pr_state%3A+blocked%22+-label%3A%22pr_state%3A+WIP%22+).
|
||||
|
||||
# Prioritization of Work
|
||||
|
||||
What should you be working on?
|
||||
|
||||
1. Any PRs that are assigned to you that don't have `pr_state: WIP` or `pr_state: blocked`
|
||||
1. Any issues that are assigned to you in the lowest-numbered Milestone
|
||||
1. Any issues that are assigned to you in any Milestone
|
||||
|
||||
If there are no issues assigned to you in any Milestone, pick an issue, self-assign it, and add
|
||||
it to the most appropriate Milestone based on effort.
|
||||
|
||||
Here are some suggestions for what to work on next:
|
||||
|
||||
* Filter for issues in a component that you are knowledgeable about, and pick something that has a
|
||||
high priority.
|
||||
* Filter for any small effort task that has the special `cust: GT` or `cust:Ionic` tags,
|
||||
and priority > P3.
|
||||
* Add a new task that's really important, add `component`, `priority`, `effort`, `type` and
|
||||
assign it to yourself and the most appropriate milestone.
|
||||
|
||||
# Labels Used in Triage
|
||||
|
||||
## Priority
|
||||
How urgent is this issue? We use priority to determine what should be worked on in each new
|
||||
milestone.
|
||||
|
||||
* `P0: critical` -- drop everything to work on this
|
||||
* `P1: urgent` -- resolve quickly in the current milestone. people are blocked
|
||||
* `P2: required` -- needed for development but not urgent yet. workaround exists, or e.g. new API
|
||||
* `P3: important` -- must complete before Angular 2 is ready for release
|
||||
* `P4: nice to have` -- a good idea, but maybe not until after release
|
||||
|
||||
|
||||
## Effort
|
||||
Rough, non-binding estimate of how much work this issue represents. Please change this assessment
|
||||
for anything you're working on to better reflect reality.
|
||||
|
||||
* `effort: easy` -- straightforward issue that can be resolved in a few hours, e.g. < 1 day of work.
|
||||
* `effort: medium` -- issue that will be a few days of work. Can be completed within a single
|
||||
milestone.
|
||||
* `effort: tough` -- issue that will likely take more than 1 milestone to complete.
|
||||
|
||||
<!-- We don't like these label names as
|
||||
they're not absolute (what is one developer-hour, really?) but decided it wasn't worth arguing
|
||||
over terms. -->
|
||||
|
||||
## Component
|
||||
Which area of Angular knowledge is this issue most closely related to? Helpful when deciding what
|
||||
to work on next.
|
||||
|
||||
* `comp: benchpress` -- benchmarks and performance testing → *tbosch*, *crossj*
|
||||
* `comp: build/dev-productivity` -- build process, e.g. CLI and related tasks → *iminar*, *caitp*
|
||||
* `comp: build/pipeline` -- build pipeline, e.g. ts2dart → *mprobst*, *alexeagle*
|
||||
* `comp: core` -- general core Angular issues, not related to a sub-category (see below) →
|
||||
*mhevery*
|
||||
* `comp: core/animations` -- animations framework → *matsko*
|
||||
* `comp: core/change_detection` -- change detection → *vsavkin*
|
||||
* `comp: core/di` -- dependency injection → *vicb*, *rkirov*
|
||||
* `comp: core/directives` -- directives
|
||||
* `comp: core/forms` -- forms → *vsavkin*
|
||||
* `comp: core/pipes` -- pipes
|
||||
* `comp: core/view` -- runtime processing of the `View`s
|
||||
* `comp: core/view/compiler` -- static analysis of the templates which generate `ProtoView`s.
|
||||
* `comp: core/testbed` -- e2e tests and support for them
|
||||
* `comp: core/webworker` -- core web worker infrastructure
|
||||
* `comp: dart-transformer` -- Dart transforms → *kegluneq*, *jakemac*
|
||||
* `comp: data-access` -- → *jeffbcross*
|
||||
* `comp: docs` -- API docs and doc generation → *naomiblack*, *petebacondarwin*
|
||||
* `comp: material-components` -- Angular Material components built in Angular 2 → *jelbourn*
|
||||
* `comp: router` -- Component Router → *btford*, *igorminar*, *matsko*
|
||||
* `comp: wrenchjs`
|
||||
|
||||
## Type
|
||||
What kind of problem is this?
|
||||
|
||||
* `type RFC / discussion / question`
|
||||
* `type bug`
|
||||
* `type chore`
|
||||
* `type feature`
|
||||
* `type performance`
|
||||
* `type refactor`
|
||||
|
||||
## Special Labels
|
||||
|
||||
@ -126,6 +160,9 @@ More active discussion is needed before the issue can be worked on further. Typi
|
||||
Managed by googlebot. Indicates whether a PR has a CLA on file for its author(s). Only issues with
|
||||
`cla:yes` should be merged into master.
|
||||
|
||||
### cust
|
||||
This is an issue causing user pain for early adopter customers `cust: GT` or `cust: Ionic`.
|
||||
|
||||
### WORKS_AS_INTENDED
|
||||
|
||||
Only used on closed issues, to indicate to the reporter why we closed it.
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "angular2",
|
||||
"dependencies": {
|
||||
"polymer": "Polymer/polymer#^1.6.0"
|
||||
"polymer": "dart-lang/polymer_js#0.8.0-preview"
|
||||
}
|
||||
}
|
||||
|
@ -1,177 +0,0 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright Google Inc. All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
// Unique place to configure the browsers which are used in the different CI jobs in Sauce Labs (SL)
|
||||
// and BrowserStack (BS).
|
||||
// If the target is set to null, then the browser is not run anywhere during CI.
|
||||
// If a category becomes empty (e.g. BS and required), then the corresponding job must be commented
|
||||
// out in Travis configuration.
|
||||
var CIconfiguration = {
|
||||
'Chrome': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Firefox': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
// FirefoxBeta and ChromeBeta should be target:'BS' or target:'SL', and required:true
|
||||
// Currently deactivated due to https://github.com/angular/angular/issues/7560
|
||||
'ChromeBeta': {unitTest: {target: null, required: true}, e2e: {target: null, required: false}},
|
||||
'FirefoxBeta': {unitTest: {target: null, required: false}, e2e: {target: null, required: false}},
|
||||
'ChromeDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
|
||||
'FirefoxDev': {unitTest: {target: null, required: true}, e2e: {target: null, required: true}},
|
||||
'IE9': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'IE10': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'IE11': {unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'Edge': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.1': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.2': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.3': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android4.4': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Android5': {unitTest: {target: 'SL', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari7': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari9': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'Safari10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'iOS7': {unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
||||
'iOS8': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'iOS9': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'iOS10': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
'WindowsPhone': {unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}}
|
||||
};
|
||||
|
||||
var customLaunchers = {
|
||||
'DartiumWithWebPlatform':
|
||||
{base: 'Dartium', flags: ['--enable-experimental-web-platform-features']},
|
||||
'ChromeNoSandbox': {base: 'Chrome', flags: ['--no-sandbox']},
|
||||
'SL_CHROME': {base: 'SauceLabs', browserName: 'chrome', version: '52'},
|
||||
'SL_CHROMEBETA': {base: 'SauceLabs', browserName: 'chrome', version: 'beta'},
|
||||
'SL_CHROMEDEV': {base: 'SauceLabs', browserName: 'chrome', version: 'dev'},
|
||||
'SL_FIREFOX': {base: 'SauceLabs', browserName: 'firefox', version: '46'},
|
||||
'SL_FIREFOXBETA': {base: 'SauceLabs', browserName: 'firefox', version: 'beta'},
|
||||
'SL_FIREFOXDEV': {base: 'SauceLabs', browserName: 'firefox', version: 'dev'},
|
||||
'SL_SAFARI7': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.9', version: '7.0'},
|
||||
'SL_SAFARI8': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.10', version: '8.0'},
|
||||
'SL_SAFARI9': {base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.11', version: '9.0'},
|
||||
'SL_SAFARI10':
|
||||
{base: 'SauceLabs', browserName: 'safari', platform: 'OS X 10.12', version: '10.0'},
|
||||
'SL_IOS7': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '7.1'},
|
||||
'SL_IOS8': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '8.4'},
|
||||
'SL_IOS9': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '9.3'},
|
||||
'SL_IOS10': {base: 'SauceLabs', browserName: 'iphone', platform: 'OS X 10.10', version: '10.0'},
|
||||
'SL_IE9':
|
||||
{base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 2008', version: '9'},
|
||||
'SL_IE10': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'internet explorer',
|
||||
platform: 'Windows 2012',
|
||||
version: '10'
|
||||
},
|
||||
'SL_IE11':
|
||||
{base: 'SauceLabs', browserName: 'internet explorer', platform: 'Windows 8.1', version: '11'},
|
||||
'SL_EDGE': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'MicrosoftEdge',
|
||||
platform: 'Windows 10',
|
||||
version: '13.10586'
|
||||
},
|
||||
'SL_ANDROID4.1': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.1'},
|
||||
'SL_ANDROID4.2': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.2'},
|
||||
'SL_ANDROID4.3': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.3'},
|
||||
'SL_ANDROID4.4': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '4.4'},
|
||||
'SL_ANDROID5': {base: 'SauceLabs', browserName: 'android', platform: 'Linux', version: '5.1'},
|
||||
|
||||
'BS_CHROME': {base: 'BrowserStack', browser: 'chrome', os: 'OS X', os_version: 'Yosemite'},
|
||||
'BS_FIREFOX': {base: 'BrowserStack', browser: 'firefox', os: 'Windows', os_version: '10'},
|
||||
'BS_SAFARI7': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Mavericks'},
|
||||
'BS_SAFARI8': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Yosemite'},
|
||||
'BS_SAFARI9': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'El Capitan'},
|
||||
'BS_SAFARI10': {base: 'BrowserStack', browser: 'safari', os: 'OS X', os_version: 'Sierra'},
|
||||
'BS_IOS7': {base: 'BrowserStack', device: 'iPhone 5S', os: 'ios', os_version: '7.0'},
|
||||
'BS_IOS8': {base: 'BrowserStack', device: 'iPhone 6', os: 'ios', os_version: '8.3'},
|
||||
'BS_IOS9': {base: 'BrowserStack', device: 'iPhone 6S', os: 'ios', os_version: '9.1'},
|
||||
'BS_IOS10': {base: 'BrowserStack', device: 'iPhone SE', os: 'ios', os_version: '10.0'},
|
||||
'BS_IE9':
|
||||
{base: 'BrowserStack', browser: 'ie', browser_version: '9.0', os: 'Windows', os_version: '7'},
|
||||
'BS_IE10': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '10.0',
|
||||
os: 'Windows',
|
||||
os_version: '8'
|
||||
},
|
||||
'BS_IE11': {
|
||||
base: 'BrowserStack',
|
||||
browser: 'ie',
|
||||
browser_version: '11.0',
|
||||
os: 'Windows',
|
||||
os_version: '10'
|
||||
},
|
||||
'BS_EDGE': {base: 'BrowserStack', browser: 'edge', os: 'Windows', os_version: '10'},
|
||||
'BS_WINDOWSPHONE':
|
||||
{base: 'BrowserStack', device: 'Nokia Lumia 930', os: 'winphone', os_version: '8.1'},
|
||||
'BS_ANDROID5': {base: 'BrowserStack', device: 'Google Nexus 5', os: 'android', os_version: '5.0'},
|
||||
'BS_ANDROID4.4': {base: 'BrowserStack', device: 'HTC One M8', os: 'android', os_version: '4.4'},
|
||||
'BS_ANDROID4.3':
|
||||
{base: 'BrowserStack', device: 'Samsung Galaxy S4', os: 'android', os_version: '4.3'},
|
||||
'BS_ANDROID4.2':
|
||||
{base: 'BrowserStack', device: 'Google Nexus 4', os: 'android', os_version: '4.2'},
|
||||
'BS_ANDROID4.1':
|
||||
{base: 'BrowserStack', device: 'Google Nexus 7', os: 'android', os_version: '4.1'}
|
||||
};
|
||||
|
||||
var sauceAliases = {
|
||||
'ALL': Object.keys(customLaunchers).filter(function(item) {
|
||||
return customLaunchers[item].base == 'SauceLabs';
|
||||
}),
|
||||
'DESKTOP': [
|
||||
'SL_CHROME', 'SL_FIREFOX', 'SL_IE9', 'SL_IE10', 'SL_IE11', 'SL_EDGE', 'SL_SAFARI7',
|
||||
'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'
|
||||
],
|
||||
'MOBILE': [
|
||||
'SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7',
|
||||
'SL_IOS8', 'SL_IOS9', 'SL_IOS10'
|
||||
],
|
||||
'ANDROID': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5'],
|
||||
'IE': ['SL_IE9', 'SL_IE10', 'SL_IE11'],
|
||||
'IOS': ['SL_IOS7', 'SL_IOS8', 'SL_IOS9', 'SL_IOS10'],
|
||||
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9', 'SL_SAFARI10'],
|
||||
'BETA': ['SL_CHROMEBETA', 'SL_FIREFOXBETA'],
|
||||
'DEV': ['SL_CHROMEDEV', 'SL_FIREFOXDEV'],
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'SL', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'SL', false)
|
||||
};
|
||||
|
||||
var browserstackAliases = {
|
||||
'ALL': Object.keys(customLaunchers).filter(function(item) {
|
||||
return customLaunchers[item].base == 'BrowserStack';
|
||||
}),
|
||||
'DESKTOP': [
|
||||
'BS_CHROME', 'BS_FIREFOX', 'BS_IE9', 'BS_IE10', 'BS_IE11', 'BS_EDGE', 'BS_SAFARI7',
|
||||
'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'
|
||||
],
|
||||
'MOBILE': [
|
||||
'BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10', 'BS_WINDOWSPHONE'
|
||||
],
|
||||
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
|
||||
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
|
||||
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_IOS10'],
|
||||
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9', 'BS_SAFARI10'],
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
customLaunchers: customLaunchers,
|
||||
sauceAliases: sauceAliases,
|
||||
browserstackAliases: browserstackAliases
|
||||
};
|
||||
|
||||
function buildConfiguration(type, target, required) {
|
||||
return Object.keys(CIconfiguration)
|
||||
.filter((item) => {
|
||||
var conf = CIconfiguration[item][type];
|
||||
return conf.required === required && conf.target === target;
|
||||
})
|
||||
.map((item) => target + '_' + item.toUpperCase());
|
||||
}
|
165
build.sh
165
build.sh
@ -1,165 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e -o pipefail
|
||||
|
||||
cd `dirname $0`
|
||||
|
||||
PACKAGES=(core
|
||||
compiler
|
||||
common
|
||||
forms
|
||||
platform-browser
|
||||
platform-browser-dynamic
|
||||
platform-server
|
||||
platform-webworker
|
||||
platform-webworker-dynamic
|
||||
http
|
||||
router
|
||||
upgrade
|
||||
compiler-cli
|
||||
benchpress)
|
||||
BUILD_ALL=true
|
||||
BUNDLE=true
|
||||
|
||||
for ARG in "$@"; do
|
||||
case "$ARG" in
|
||||
--packages=*)
|
||||
PACKAGES_STR=${ARG#--packages=}
|
||||
PACKAGES=( ${PACKAGES_STR//,/ } )
|
||||
BUILD_ALL=false
|
||||
;;
|
||||
--bundle=*)
|
||||
BUNDLE=( "${ARG#--bundle=}" )
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option $ARG."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
export NODE_PATH=${NODE_PATH}:$(pwd)/dist/all:$(pwd)/dist/tools
|
||||
TSC="node --max-old-space-size=3000 dist/tools/@angular/tsc-wrapped/src/main"
|
||||
UGLIFYJS=`pwd`/node_modules/.bin/uglifyjs
|
||||
TSCONFIG=./tools/tsconfig.json
|
||||
echo "====== (tools)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
|
||||
rm -rf ./dist/tools/
|
||||
mkdir -p ./dist/tools/
|
||||
$(npm bin)/tsc -p ${TSCONFIG}
|
||||
|
||||
cp ./tools/@angular/tsc-wrapped/package.json ./dist/tools/@angular/tsc-wrapped
|
||||
|
||||
if [[ ${BUILD_ALL} == true ]]; then
|
||||
rm -rf ./dist/all/
|
||||
mkdir -p ./dist/all/
|
||||
|
||||
echo "====== Copying files needed for e2e tests ====="
|
||||
cp -r ./modules/playground ./dist/all/
|
||||
cp -r ./modules/playground/favicon.ico ./dist/
|
||||
#rsync -aP ./modules/playground/* ./dist/all/playground/
|
||||
mkdir ./dist/all/playground/vendor
|
||||
cd ./dist/all/playground/vendor
|
||||
ln -s ../../../../node_modules/core-js/client/core.js .
|
||||
ln -s ../../../../node_modules/zone.js/dist/zone.js .
|
||||
ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js .
|
||||
ln -s ../../../../node_modules/systemjs/dist/system.src.js .
|
||||
ln -s ../../../../node_modules/base64-js/lib/b64.js .
|
||||
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
|
||||
ln -s ../../../../node_modules/rxjs .
|
||||
ln -s ../../../../node_modules/angular/angular.js .
|
||||
cd -
|
||||
|
||||
echo "====== Copying files needed for benchmarks ====="
|
||||
cp -r ./modules/benchmarks ./dist/all/
|
||||
cp -r ./modules/benchmarks/favicon.ico ./dist/
|
||||
mkdir ./dist/all/benchmarks/vendor
|
||||
cd ./dist/all/benchmarks/vendor
|
||||
ln -s ../../../../node_modules/core-js/client/core.js .
|
||||
ln -s ../../../../node_modules/zone.js/dist/zone.js .
|
||||
ln -s ../../../../node_modules/zone.js/dist/long-stack-trace-zone.js .
|
||||
ln -s ../../../../node_modules/systemjs/dist/system.src.js .
|
||||
ln -s ../../../../node_modules/base64-js/lib/b64.js .
|
||||
ln -s ../../../../node_modules/reflect-metadata/Reflect.js .
|
||||
ln -s ../../../../node_modules/rxjs .
|
||||
ln -s ../../../../node_modules/angular/angular.js .
|
||||
ln -s ../../../../bower_components/polymer .
|
||||
ln -s ../../../../node_modules/incremental-dom/dist/incremental-dom-cjs.js
|
||||
cd -
|
||||
|
||||
TSCONFIG=./modules/tsconfig.json
|
||||
echo "====== (all)COMPILING: \$(npm bin)/tsc -p ${TSCONFIG} ====="
|
||||
# compile ts code
|
||||
$TSC -p modules/tsconfig.json
|
||||
|
||||
rm -rf ./dist/packages-dist
|
||||
fi
|
||||
|
||||
for PACKAGE in ${PACKAGES[@]}
|
||||
do
|
||||
PWD=`pwd`
|
||||
SRCDIR=${PWD}/modules/@angular/${PACKAGE}
|
||||
DESTDIR=${PWD}/dist/packages-dist/${PACKAGE}
|
||||
UMD_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.js
|
||||
UMD_TESTING_ES5_PATH=${DESTDIR}/bundles/${PACKAGE}-testing.umd.js
|
||||
UMD_ES5_MIN_PATH=${DESTDIR}/bundles/${PACKAGE}.umd.min.js
|
||||
LICENSE_BANNER=${PWD}/modules/@angular/license-banner.txt
|
||||
|
||||
rm -rf ${DESTDIR}
|
||||
|
||||
echo "====== COMPILING: ${TSC} -p ${SRCDIR}/tsconfig-build.json ====="
|
||||
$TSC -p ${SRCDIR}/tsconfig-build.json
|
||||
|
||||
cp ${SRCDIR}/package.json ${DESTDIR}/
|
||||
cp ${PWD}/modules/@angular/README.md ${DESTDIR}/
|
||||
|
||||
if [[ -e ${SRCDIR}/tsconfig-testing.json ]]; then
|
||||
echo "====== COMPILING TESTING: ${TSC} -p ${SRCDIR}/tsconfig-testing.json"
|
||||
$TSC -p ${SRCDIR}/tsconfig-testing.json
|
||||
fi
|
||||
|
||||
echo "====== TSC 1.8 d.ts compat for ${DESTDIR} ====="
|
||||
# safely strips 'readonly' specifier from d.ts files to make them compatible with tsc 1.8
|
||||
if [ "$(uname)" == "Darwin" ]; then
|
||||
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\(^ *(static |private )*\)*readonly */\1/g'
|
||||
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -e 's/\/\/\/ <reference types="node" \/>//g'
|
||||
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i '' -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
|
||||
else
|
||||
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\(^ *(static |private )*\)*readonly */\1/g'
|
||||
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -e 's/\/\/\/ <reference types="node" \/>//g'
|
||||
find ${DESTDIR} -type f -name '*.d.ts' -print0 | xargs -0 sed -i -E 's/^( +)abstract ([[:alnum:]]+\:)/\1\2/g'
|
||||
fi
|
||||
|
||||
if [[ ${PACKAGE} == benchpress ]]; then
|
||||
cp ${SRCDIR}/*.md ${DESTDIR}
|
||||
cp -r ${SRCDIR}/docs ${DESTDIR}
|
||||
fi
|
||||
|
||||
if [[ ${BUNDLE} == true && ${PACKAGE} != compiler-cli && ${PACKAGE} != benchpress ]]; then
|
||||
|
||||
echo "====== BUNDLING: ${SRCDIR} ====="
|
||||
mkdir ${DESTDIR}/bundles
|
||||
|
||||
(
|
||||
cd ${SRCDIR}
|
||||
echo "====== Rollup ${PACKAGE} index"
|
||||
../../../node_modules/.bin/rollup -c rollup.config.js
|
||||
cat ${LICENSE_BANNER} > ${UMD_ES5_PATH}.tmp
|
||||
cat ${UMD_ES5_PATH} >> ${UMD_ES5_PATH}.tmp
|
||||
mv ${UMD_ES5_PATH}.tmp ${UMD_ES5_PATH}
|
||||
$UGLIFYJS -c --screw-ie8 --comments -o ${UMD_ES5_MIN_PATH} ${UMD_ES5_PATH}
|
||||
|
||||
|
||||
if [[ -e rollup-testing.config.js ]]; then
|
||||
echo "====== Rollup ${PACKAGE} testing"
|
||||
../../../node_modules/.bin/rollup -c rollup-testing.config.js
|
||||
echo "{\"main\": \"../bundles/${PACKAGE}-testing.umd.js\"}" > ${DESTDIR}/testing/package.json
|
||||
cat ${LICENSE_BANNER} > ${UMD_TESTING_ES5_PATH}.tmp
|
||||
cat ${UMD_TESTING_ES5_PATH} >> ${UMD_TESTING_ES5_PATH}.tmp
|
||||
mv ${UMD_TESTING_ES5_PATH}.tmp ${UMD_TESTING_ES5_PATH}
|
||||
fi
|
||||
) 2>&1 | grep -v "as external dependency"
|
||||
|
||||
fi
|
||||
done
|
||||
|
||||
./modules/@angular/examples/build.sh
|
11
circle.yml
11
circle.yml
@ -1,11 +0,0 @@
|
||||
machine:
|
||||
node:
|
||||
version: 5.4.1
|
||||
|
||||
dependencies:
|
||||
pre:
|
||||
- npm install -g npm
|
||||
|
||||
test:
|
||||
override:
|
||||
- gulp lint
|
76
docs/angular.io-package/index.js
Normal file
76
docs/angular.io-package/index.js
Normal file
@ -0,0 +1,76 @@
|
||||
var path = require('canonical-path');
|
||||
var Package = require('dgeni').Package;
|
||||
var basePackage = require('../public-docs-package');
|
||||
|
||||
var PARTIAL_PATH = 'partials';
|
||||
var MODULES_DOCS_PATH = PARTIAL_PATH + '/api';
|
||||
|
||||
module.exports = new Package('angular.io', [basePackage])
|
||||
|
||||
.factory(require('./services/renderMarkdown'))
|
||||
.processor(require('./processors/addJadeDataDocsProcessor'))
|
||||
.processor(require('./processors/filterUnwantedDecorators'))
|
||||
|
||||
// Configure rendering
|
||||
.config(function(templateFinder, templateEngine) {
|
||||
|
||||
templateFinder.templateFolders
|
||||
.unshift(path.resolve(__dirname, 'templates'));
|
||||
})
|
||||
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/angular.io';
|
||||
})
|
||||
|
||||
.config(function(readFilesProcessor, generateNavigationDoc, createOverviewDump) {
|
||||
// Clear out unwanted processors
|
||||
readFilesProcessor.$enabled = false;
|
||||
generateNavigationDoc.$enabled = false;
|
||||
createOverviewDump.$enabled = false;
|
||||
})
|
||||
|
||||
|
||||
.config(function(filterUnwantedDecorators, log) {
|
||||
log.level = 'info';
|
||||
filterUnwantedDecorators.decoratorsToIgnore = [
|
||||
'CONST',
|
||||
'IMPLEMENTS',
|
||||
'ABSTRACT'
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
.config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) {
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['module'],
|
||||
pathTemplate: '${id}/',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.jade'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: EXPORT_DOC_TYPES,
|
||||
pathTemplate: '${moduleDoc.id}/${name}-${docType}.html',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${moduleDoc.id}/${name}-${docType}.jade',
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['jade-data'],
|
||||
pathTemplate: '${originalDoc.id}/_data',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${path}.json'
|
||||
});
|
||||
})
|
||||
|
||||
.config(function(getLinkInfo) {
|
||||
getLinkInfo.relativeLinks = true;
|
||||
})
|
||||
|
||||
|
||||
.config(function(templateEngine, getInjectables) {
|
||||
templateEngine.filters = templateEngine.filters.concat(getInjectables([
|
||||
require('./rendering/trimBlankLines'),
|
||||
require('./rendering/toId')
|
||||
]));
|
||||
});
|
||||
|
||||
|
8
docs/angular.io-package/mocks/mockPackage.js
Normal file
8
docs/angular.io-package/mocks/mockPackage.js
Normal file
@ -0,0 +1,8 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = function mockPackage() {
|
||||
|
||||
return new Package('mockPackage', [require('../')])
|
||||
|
||||
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); })
|
||||
};
|
@ -0,0 +1,86 @@
|
||||
var _ = require('lodash');
|
||||
var path = require('canonical-path');
|
||||
|
||||
var titleCase = function(text) {
|
||||
return text.replace(/(.)(.*)/, function(_, first, rest) {
|
||||
return first.toUpperCase() + rest;
|
||||
});
|
||||
};
|
||||
|
||||
/*
|
||||
* Create _data.json file for Harp pages
|
||||
*
|
||||
* http://harpjs.com/docs/development/metadata
|
||||
*
|
||||
* This method creates the meta data required for each page
|
||||
* such as the title, description, etc. This meta data is used
|
||||
* in the harp static site generator to create the title for headers
|
||||
* and the navigation used in the API docs
|
||||
*
|
||||
*/
|
||||
|
||||
module.exports = function addJadeDataDocsProcessor() {
|
||||
return {
|
||||
$runAfter: ['adding-extra-docs'],
|
||||
$runBefore: ['extra-docs-added'],
|
||||
$process: function(docs) {
|
||||
var extraDocs = [];
|
||||
var modules = [];
|
||||
|
||||
|
||||
/*
|
||||
* Create Data for Modules
|
||||
*
|
||||
* Modules must be public and have content
|
||||
*/
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
if (doc.docType === 'module' && !doc.private && doc.exports.length) {
|
||||
modules.push(doc);
|
||||
|
||||
// GET DATA FOR INDEX PAGE OF MODULE SECTION
|
||||
var indexPageInfo = [{
|
||||
name: 'index',
|
||||
title: _.map(path.basename(doc.fileInfo.baseName).split('_'), function(part) {
|
||||
return titleCase(part);
|
||||
}).join(' '),
|
||||
intro: doc.description.replace('"', '\"').replace(/\s*(\r?\n|\r)\s*/g," "),
|
||||
docType: 'module'
|
||||
}];
|
||||
|
||||
// GET DATA FOR EACH PAGE (CLASS, VARS, FUNCTIONS)
|
||||
var modulePageInfo = _(doc.exports)
|
||||
.map(function(exportDoc) {
|
||||
var dataDoc = {
|
||||
name: exportDoc.name + '-' + exportDoc.docType,
|
||||
title: exportDoc.name,
|
||||
docType: exportDoc.docType
|
||||
};
|
||||
if (exportDoc.symbolTypeName) dataDoc.varType = titleCase(exportDoc.symbolTypeName);
|
||||
if (exportDoc.originalModule) dataDoc.originalModule = exportDoc.originalModule;
|
||||
return dataDoc;
|
||||
})
|
||||
.sortBy('name')
|
||||
.value();
|
||||
|
||||
|
||||
|
||||
//COMBINE PAGE DATA
|
||||
var allPageData = indexPageInfo.concat(modulePageInfo);
|
||||
|
||||
// PUSH DATA TO EXTRA DOCS ARRAY
|
||||
extraDocs.push({
|
||||
id: doc.id + "-data",
|
||||
aliases: [doc.id + "-data"],
|
||||
docType: 'jade-data',
|
||||
originalDoc: doc,
|
||||
data: allPageData
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
return docs.concat(extraDocs);
|
||||
}
|
||||
};
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
|
||||
describe('addJadeDataDocsProcessor', function() {
|
||||
var dgeni, injector, processor;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
processor = injector.get('addJadeDataDocsProcessor');
|
||||
});
|
||||
|
||||
it('should add a doc for each module', function() {
|
||||
var docs = [
|
||||
{
|
||||
docType: 'module',
|
||||
id: 'someModule',
|
||||
exports: [
|
||||
{ name: 'someObj', docType: 'var', symbolTypeName: 'MyClass', originalModule: 'some/private/module' }
|
||||
],
|
||||
fileInfo: { baseName: 'x_y' },
|
||||
description: 'some description\nsecond line'
|
||||
}
|
||||
];
|
||||
docs = processor.$process(docs);
|
||||
|
||||
expect(docs[1]).toEqual({
|
||||
id : 'someModule-data',
|
||||
aliases : [ 'someModule-data' ],
|
||||
docType : 'jade-data',
|
||||
originalDoc : docs[0],
|
||||
data : [
|
||||
{ name : 'index', title : 'X Y', intro : 'some description second line', docType : 'module' },
|
||||
{ name : 'someObj-var', title : 'someObj', varType : 'MyClass', docType: 'var', originalModule: 'some/private/module' }
|
||||
] });
|
||||
});
|
||||
|
||||
it('should sort the exports into alphabetical order', function() {
|
||||
var docs = [
|
||||
{
|
||||
docType: 'module',
|
||||
id: 'someModule',
|
||||
exports: [
|
||||
{ name: 'Beta', docType: 'class'},
|
||||
{ name: 'Alpha', docType: 'class'},
|
||||
{ name: 'Gamma', docType: 'class'},
|
||||
{ name: 'Nu', docType: 'class'},
|
||||
{ name: 'Mu', docType: 'class'}
|
||||
],
|
||||
fileInfo: { baseName: 'x_y' },
|
||||
description: 'some description\nsecond line'
|
||||
}
|
||||
];
|
||||
docs = processor.$process(docs);
|
||||
|
||||
expect(docs[1].data).toEqual([
|
||||
{ name : 'index', title : 'X Y', intro : 'some description second line', docType : 'module' },
|
||||
{ name: 'Alpha-class', title: 'Alpha', docType: 'class' },
|
||||
{ name: 'Beta-class', title: 'Beta', docType: 'class' },
|
||||
{ name: 'Gamma-class', title: 'Gamma', docType: 'class' },
|
||||
{ name: 'Mu-class', title: 'Mu', docType: 'class' },
|
||||
{ name: 'Nu-class', title: 'Nu', docType: 'class' }
|
||||
]);
|
||||
|
||||
});
|
||||
});
|
@ -0,0 +1,20 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function filterUnwantedDecorators() {
|
||||
return {
|
||||
decoratorsToIgnore: [],
|
||||
$runAfter: ['processing-docs'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$process: function(docs) {
|
||||
var decoratorsToIgnore = this.decoratorsToIgnore || [];
|
||||
_.forEach(docs, function(doc) {
|
||||
if (doc.decorators) {
|
||||
doc.decorators = _.filter(doc.decorators, function(decorator) {
|
||||
return decoratorsToIgnore.indexOf(decorator.name) === -1;
|
||||
});
|
||||
}
|
||||
});
|
||||
return docs;
|
||||
}
|
||||
};
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
|
||||
describe('filterUnwantedDecorators', function() {
|
||||
var dgeni, injector, processor;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
processor = injector.get('filterUnwantedDecorators');
|
||||
});
|
||||
|
||||
|
||||
it('should remove decorators specified by name', function() {
|
||||
var docs = [
|
||||
{ id: 'doc1', decorators: [ { name: 'A' }, { name: 'B' } ] },
|
||||
{ id: 'doc2', decorators: [ { name: 'B' }, { name: 'C' } ] },
|
||||
{ id: 'doc3', decorators: [ { name: 'A' }, { name: 'C' } ] }
|
||||
];
|
||||
processor.decoratorsToIgnore = ['D', 'B'];
|
||||
docs = processor.$process(docs);
|
||||
|
||||
expect(docs).toEqual([
|
||||
{ id: 'doc1', decorators: [ { name: 'A' } ] },
|
||||
{ id: 'doc2', decorators: [ { name: 'C' } ] },
|
||||
{ id: 'doc3', decorators: [ { name: 'A' }, { name: 'C' } ] }
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should ignore docs that have no decorators', function() {
|
||||
var docs = [
|
||||
{ id: 'doc1', decorators: [ { name: 'A' }, { name: 'B' } ] },
|
||||
{ id: 'doc2' },
|
||||
{ id: 'doc3', decorators: [ { name: 'A' }, { name: 'C' } ] }
|
||||
];
|
||||
processor.decoratorsToIgnore = ['D', 'B'];
|
||||
docs = processor.$process(docs);
|
||||
|
||||
expect(docs).toEqual([
|
||||
{ id: 'doc1', decorators: [ { name: 'A' } ] },
|
||||
{ id: 'doc2' },
|
||||
{ id: 'doc3', decorators: [ { name: 'A' }, { name: 'C' } ] }
|
||||
]);
|
||||
});
|
||||
});
|
8
docs/angular.io-package/rendering/toId.js
Normal file
8
docs/angular.io-package/rendering/toId.js
Normal file
@ -0,0 +1,8 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
name: 'toId',
|
||||
process: function(str) {
|
||||
return str.replace(/[^(a-z)(A-Z)(0-9)._-]/, '-');
|
||||
}
|
||||
};
|
||||
};
|
12
docs/angular.io-package/rendering/trimBlankLines.js
Normal file
12
docs/angular.io-package/rendering/trimBlankLines.js
Normal file
@ -0,0 +1,12 @@
|
||||
module.exports = function() {
|
||||
return {
|
||||
name: 'trimBlankLines',
|
||||
process: function(str) {
|
||||
var lines = str.split(/\r?\n/);
|
||||
while(lines.length && (lines[0].trim() === '')) {
|
||||
lines.shift();
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
};
|
||||
};
|
18
docs/angular.io-package/rendering/trimBlankLines.spec.js
Normal file
18
docs/angular.io-package/rendering/trimBlankLines.spec.js
Normal file
@ -0,0 +1,18 @@
|
||||
var factory = require('./trimBlankLines');
|
||||
|
||||
describe('trimBlankLines filter', function() {
|
||||
var filter;
|
||||
|
||||
beforeEach(function() {
|
||||
filter = factory();
|
||||
});
|
||||
|
||||
it('should be called "trimBlankLines"', function() {
|
||||
expect(filter.name).toEqual('trimBlankLines');
|
||||
});
|
||||
|
||||
it('should remove all empty lines from the start of the string', function() {
|
||||
expect(filter.process('\n\n\nsome text\n\nmore text\n\n'))
|
||||
.toEqual('some text\n\nmore text\n\n');
|
||||
});
|
||||
});
|
54
docs/angular.io-package/services/renderMarkdown.js
Normal file
54
docs/angular.io-package/services/renderMarkdown.js
Normal file
@ -0,0 +1,54 @@
|
||||
var marked = require('marked');
|
||||
var Encoder = require('node-html-encoder').Encoder;
|
||||
var html2jade = require('html2jade');
|
||||
var indentString = require('indent-string');
|
||||
|
||||
|
||||
function stripTags(s) { //from sugar.js
|
||||
return s.replace(RegExp('<\/?[^<>]*>', 'gi'), '');
|
||||
}
|
||||
|
||||
// entity type encoder
|
||||
var encoder = new Encoder('entity');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @dgService renderMarkdown
|
||||
* @description
|
||||
* Render the markdown in the given string as HTML.
|
||||
*/
|
||||
module.exports = function renderMarkdown(trimIndentation) {
|
||||
|
||||
var renderer = new marked.Renderer();
|
||||
|
||||
renderer.code = function(code, lang, escaped) {
|
||||
|
||||
var cssClasses = ['prettyprint', 'linenums'];
|
||||
var trimmedCode = trimIndentation(code);
|
||||
|
||||
if(lang) {
|
||||
if(lang=='html') {
|
||||
trimmedCode = encoder.htmlEncode(trimmedCode);
|
||||
}
|
||||
cssClasses.push(this.options.langPrefix + escape(lang, true));
|
||||
}
|
||||
|
||||
return 'pre(class="' + cssClasses.join(' ') + '")\n' + indentString('code.\n', ' ', 2) + trimmedCode;
|
||||
};
|
||||
|
||||
renderer.heading = function (text, level, raw) {
|
||||
var headingText = marked.Renderer.prototype.heading.call(renderer, text, level, raw);
|
||||
var title = 'h2 ' + stripTags(headingText);
|
||||
|
||||
if (level==2) {
|
||||
title = '.l-main-section\n' + indentString(title, ' ', 2) ;
|
||||
}
|
||||
|
||||
return title;
|
||||
};
|
||||
|
||||
return function(content) {
|
||||
return marked(content, { renderer: renderer });
|
||||
};
|
||||
};
|
62
docs/angular.io-package/templates/class.template.html
Normal file
62
docs/angular.io-package/templates/class.template.html
Normal file
@ -0,0 +1,62 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% include "lib/paramList.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
|
||||
{% block body %}
|
||||
p.location-badge.
|
||||
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
:markdown
|
||||
{$ doc.description | indent(2, true) | trimBlankLines $}
|
||||
|
||||
{%- if doc.decorators %}
|
||||
.l-main-section
|
||||
h2 Annotations
|
||||
{%- for decorator in doc.decorators %}
|
||||
.l-sub-section
|
||||
h3.annotation {$ decorator.name $}
|
||||
pre.prettyprint
|
||||
code.
|
||||
@{$ decorator.name $}{$ paramList(decorator.arguments) | indent(8, false) $}
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
|
||||
|
||||
{%- if doc.constructorDoc or doc.members.length -%}
|
||||
.l-main-section
|
||||
h2 Members
|
||||
|
||||
{%- if doc.constructorDoc %}
|
||||
.l-sub-section
|
||||
h3#{$ doc.constructorDoc.name | toId $} {$ doc.constructorDoc.name $}
|
||||
|
||||
{% if doc.constructorDoc.parameters %}
|
||||
pre.prettyprint
|
||||
code.
|
||||
{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.parameters) | indent(8, false) | trim $}
|
||||
{% endif %}
|
||||
:markdown
|
||||
{$ doc.constructorDoc.description | indent(6, true) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $}
|
||||
|
||||
|
||||
{% endif -%}
|
||||
|
||||
{%- for member in doc.members %}{% if not member.private %}
|
||||
.l-sub-section
|
||||
h3#{$ member.name | toId $} {$ member.name $}{% if member.optional %}?{% endif %}
|
||||
|
||||
{% if member.parameters %}
|
||||
pre.prettyprint
|
||||
code.
|
||||
{$ member.name $}{$ paramList(member.parameters) | indent(8, false) | trim $}{$ returnType(doc.returnType) $}
|
||||
{% endif %}
|
||||
:markdown
|
||||
{$ member.description | indent(6, true) | replace('## Example', '') | replace('# Example', '') | trimBlankLines $}
|
||||
|
||||
|
||||
|
||||
{% endif %}{% endfor %}
|
||||
{%- endif -%}
|
||||
|
||||
{% endblock %}
|
1
docs/angular.io-package/templates/enum.template.html
Normal file
1
docs/angular.io-package/templates/enum.template.html
Normal file
@ -0,0 +1 @@
|
||||
{% extends 'class.template.html' -%}
|
22
docs/angular.io-package/templates/function.template.html
Normal file
22
docs/angular.io-package/templates/function.template.html
Normal file
@ -0,0 +1,22 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% include "lib/paramList.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
|
||||
{% block body %}
|
||||
.l-main-section
|
||||
h2(class="function export") {$ doc.name $}
|
||||
|
||||
{% if doc.parameters %}
|
||||
pre.prettyprint
|
||||
code.
|
||||
{$ doc.name $}{$ paramList(doc.parameters) | indent(4, true) | trim $}{$ returnType(doc.returnType) $}
|
||||
{% endif %}
|
||||
|
||||
p.location-badge.
|
||||
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
:markdown
|
||||
{$ doc.description | indent(4, true) | trimBlankLines $}
|
||||
|
||||
{% endblock %}
|
17
docs/angular.io-package/templates/jade-data.template.html
Normal file
17
docs/angular.io-package/templates/jade-data.template.html
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
{%- for item in doc.data %}
|
||||
"{$ item.name $}" : {
|
||||
"title" : "{$ item.title $}",
|
||||
{%- if item.intro %}
|
||||
"intro" : "{$ item.intro $}",
|
||||
{%- endif %}
|
||||
{%- if item.varType %}
|
||||
"varType" : "{$ item.varType $}",
|
||||
{%- endif %}
|
||||
{%- if item.originalModule %}
|
||||
"originalModule" : "{$ item.originalModule $}",
|
||||
{%- endif %}
|
||||
"docType": "{$ item.docType $}"
|
||||
}{% if not loop.last %},{% endif %}
|
||||
{% endfor -%}
|
||||
}
|
@ -0,0 +1 @@
|
||||
{% block body %}{% endblock %}
|
12
docs/angular.io-package/templates/lib/paramList.html
Normal file
12
docs/angular.io-package/templates/lib/paramList.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% macro paramList(params) -%}
|
||||
{%- if params -%}
|
||||
({%- for param in params -%}
|
||||
{$ param | escape $}{% if not loop.last %}, {% endif %}
|
||||
{%- endfor %})
|
||||
{%- endif %}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
{% macro returnType(returnType) -%}
|
||||
{%- if returnType %} : {$ returnType | escape $}{% endif -%}
|
||||
{%- endmacro -%}
|
15
docs/angular.io-package/templates/module.template.html
Normal file
15
docs/angular.io-package/templates/module.template.html
Normal file
@ -0,0 +1,15 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
{% block body -%}
|
||||
p.location-badge.
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
ul
|
||||
for page, slug in public.docs[current.path[1]][current.path[2]][current.path[3]][current.path[4]]._data
|
||||
if slug != 'index'
|
||||
- var url = "/docs/" + current.path[1] + "/" + current.path[2] + "/" + current.path[3] + "/" + current.path[4] + "/" + slug + ".html"
|
||||
|
||||
li.c8
|
||||
!= partial("../../../../../_includes/_hover-card", {name: page.title, url: url })
|
||||
|
||||
{% endblock %}
|
12
docs/angular.io-package/templates/var.template.html
Normal file
12
docs/angular.io-package/templates/var.template.html
Normal file
@ -0,0 +1,12 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
.l-main-section
|
||||
p.location-badge.
|
||||
exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
|
||||
:markdown
|
||||
{$ doc.description | indent(4, true) | trimBlankLines $}
|
||||
{% endblock %}
|
379
docs/app/css/app.css
Normal file
379
docs/app/css/app.css
Normal file
@ -0,0 +1,379 @@
|
||||
|
||||
.hide { display: none !important; }
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #3f51b5;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-bottom: 20px;
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: $baseline-grid ($baseline-grid * 2);
|
||||
border-top: 1px solid #ddd;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
th {
|
||||
border-bottom: 2px solid #ddd;
|
||||
vertical-align: bottom;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.md-sidenav-inner {
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
.layout-content,
|
||||
.doc-content {
|
||||
max-width: 864px;
|
||||
margin: auto;
|
||||
}
|
||||
.layout-label {
|
||||
width: 120px;
|
||||
}
|
||||
.layout-content code.highlight {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.menu-item {
|
||||
background: none;
|
||||
border-width: 0;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
color: #333;
|
||||
font-size: inherit;
|
||||
line-height: 40px;
|
||||
max-height: 40px;
|
||||
opacity: 1;
|
||||
margin: 0;
|
||||
outline: none;
|
||||
padding: 0px 28px;
|
||||
position: relative;
|
||||
text-align: left;
|
||||
text-decoration: none;
|
||||
width: 100%;
|
||||
z-index: 1;
|
||||
-webkit-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
-webkit-transition-property: max-height, background-color, opacity;
|
||||
-moz-transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
-moz-transition-property: max-height, background-color, opacity;
|
||||
transition: 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition-property: max-height, background-color, opacity;
|
||||
}
|
||||
.menu-item.ng-hide {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
.menu-item:hover {
|
||||
color: #999;
|
||||
}
|
||||
.menu-item:focus {
|
||||
font-weight: bold;
|
||||
}
|
||||
.menu-item.menu-title {
|
||||
color: #888;
|
||||
font-size: 14px;
|
||||
padding-left: 16px;
|
||||
text-align: left;
|
||||
text-transform: uppercase;
|
||||
transition: color 0.35s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
}
|
||||
.menu-item.menu-title:hover,
|
||||
.menu-item.menu-title.active {
|
||||
color: #1976d2;
|
||||
}
|
||||
|
||||
.menu-icon {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
.app-toolbar .md-toolbar-tools h3 {
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
}
|
||||
|
||||
.demo-container {
|
||||
border-radius: 4px;
|
||||
margin-top: 16px;
|
||||
-webkit-transition: 0.02s padding cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: 0.02s padding cubic-bezier(0.35, 0, 0.25, 1);
|
||||
position: relative;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.demo-source-tabs {
|
||||
z-index: 1;
|
||||
-webkit-transition: all 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
transition: all 0.45s cubic-bezier(0.35, 0, 0.25, 1);
|
||||
max-height: 448px;
|
||||
min-height: 448px;
|
||||
background: #fff;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
md-tabs.demo-source-tabs md-tab,
|
||||
md-tabs.demo-source-tabs .md-header {
|
||||
background-color: #444444 !important;
|
||||
}
|
||||
|
||||
|
||||
md-tabs.demo-source-tabs md-tab-label {
|
||||
color: #ccc !important;
|
||||
}
|
||||
|
||||
md-tabs.demo-source-tabs .active md-tab-label {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.demo-source-tabs.ng-hide {
|
||||
max-height: 0px;
|
||||
min-height: 0px;
|
||||
}
|
||||
.demo-source-tabs {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
z-index: 0;
|
||||
}
|
||||
.demo-content {
|
||||
position: relative;
|
||||
overflow:hidden;
|
||||
min-height: 448px;
|
||||
display: -webkit-box;
|
||||
display: -webkit-flex;
|
||||
display: -moz-box;
|
||||
display: -moz-flex;
|
||||
display: -ms-flexbox;
|
||||
display: flex;
|
||||
}
|
||||
.small-demo .demo-source-tabs:not(.ng-hide) {
|
||||
min-height: 224px;
|
||||
max-height: 224px;
|
||||
}
|
||||
.small-demo .demo-content {
|
||||
min-height: 128px;
|
||||
}
|
||||
.demo-content > * {
|
||||
-webkit-box-flex: 1;
|
||||
-webkit-flex: 1;
|
||||
-moz-box-flex: 1;
|
||||
-moz-flex: 1;
|
||||
-ms-flex: 1;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.demo-content > div[layout-fill] {
|
||||
min-height: 448px;
|
||||
}
|
||||
.small-demo .demo-content > div[layout-fill] {
|
||||
min-height: 224px;
|
||||
}
|
||||
.small-demo .demo-toolbar,
|
||||
.small-demo .md-toolbar-tools {
|
||||
min-height: 48px;
|
||||
max-height: 48px;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.show-source md-toolbar.demo-toolbar {
|
||||
box-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.36);
|
||||
}
|
||||
.demo-toolbar .md-button {
|
||||
color: #616161;
|
||||
}
|
||||
|
||||
md-toolbar.demo-toolbar,
|
||||
.demo-source-tabs md-tab,
|
||||
.demo-source-tabs .tabs-header {
|
||||
background: #E0E0E0 !important;
|
||||
color: #616161;
|
||||
}
|
||||
md-toolbar.demo-toolbar md-tab-label {
|
||||
color: #99E4EE
|
||||
}
|
||||
md-toolbar.demo-toolbar .md-button:hover,
|
||||
md-toolbar.demo-toolbar .md-button:focus,
|
||||
md-toolbar.demo-toolbar .md-button.active {
|
||||
background: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
md-toolbar.demo-toolbar .md-button {
|
||||
-webkit-transition: all 0.3s linear;
|
||||
-moz-transition: all 0.3s linear;
|
||||
transition: all 0.3s linear;
|
||||
}
|
||||
.demo-source-container {
|
||||
display: block;
|
||||
border: 1px solid #ddd;
|
||||
background-color: #f6f6f6;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.demo-source-content {
|
||||
height: 400px;
|
||||
}
|
||||
.demo-source-content,
|
||||
.demo-source-content pre,
|
||||
.demo-source-content code {
|
||||
background: #f6f6f6;
|
||||
font-family: monospace;
|
||||
}
|
||||
.demo-source-content pre {
|
||||
max-width: 100%;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.show-source div[demo-include] {
|
||||
border-top: #ddd solid 2px;
|
||||
}
|
||||
|
||||
|
||||
.menu-separator-icon {
|
||||
margin: 0;
|
||||
}
|
||||
.menu-module-name {
|
||||
opacity: 0.6;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/************
|
||||
* DOCS
|
||||
************/
|
||||
.api-options-bar .md-button {
|
||||
margin: 4px;
|
||||
padding: 4px;
|
||||
}
|
||||
.api-options-bar .md-button:hover,
|
||||
.api-options-bar .md-button:focus {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
.api-options-bar.with-icon md-icon {
|
||||
position: absolute;
|
||||
top: -3px;
|
||||
left: 2px;
|
||||
}
|
||||
.api-options-bar.with-icon .md-button span {
|
||||
margin-left: 22px;
|
||||
}
|
||||
|
||||
.api-params-item {
|
||||
min-height: 72px;
|
||||
border-bottom: 1px solid #ddd;
|
||||
}
|
||||
.api-params-label {
|
||||
margin-right: 8px;
|
||||
text-align: center;
|
||||
margin-top: 14px;
|
||||
-webkit-align-self: flex-start;
|
||||
-moz-align-self: flex-start;
|
||||
-ms-flex-item-align: start;
|
||||
align-self: flex-start;
|
||||
}
|
||||
.api-params-title {
|
||||
color: #888;
|
||||
}
|
||||
code.api-type {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
ul {
|
||||
margin: 0;
|
||||
}
|
||||
ul li {
|
||||
margin-top: 3px;
|
||||
list-style-position: inside;
|
||||
}
|
||||
ul li:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
.layout-title {
|
||||
color: #999999;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-params-content ul {
|
||||
padding-left: 4px;
|
||||
}
|
||||
ul.methods > li {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
ul.methods .method-function-syntax {
|
||||
font-weight: normal;
|
||||
font-size: 20px;
|
||||
margin: 0;
|
||||
-webkit-margin-before: 0;
|
||||
-webkit-margin-after: 0;
|
||||
}
|
||||
ul.methods li h3 {
|
||||
/* border-bottom: 1px solid #eee; */
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
ul.methods > li {
|
||||
padding-left: 0;
|
||||
border-left: none;
|
||||
list-style: default;
|
||||
}
|
||||
ul.methods .method-function-syntax {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
|
||||
.version {
|
||||
padding-left: 10px;
|
||||
text-decoration: underline;
|
||||
font-size: 0.95em;
|
||||
}
|
||||
|
||||
.demo-source-container pre,
|
||||
.demo-source-container code {
|
||||
min-height: 100%;
|
||||
}
|
||||
|
||||
md-content.demo-source-container > hljs > pre > code.highlight {
|
||||
position : absolute;
|
||||
top : 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
|
||||
.extraPad {
|
||||
padding-left:32px !important;
|
||||
padding-right:32px !important;
|
||||
}
|
||||
|
||||
|
||||
.member .name {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
font-family: monospace;
|
||||
font-size: 1.17em;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
.left-nav {
|
||||
min-width: 300px;
|
||||
}
|
142
docs/app/css/prettify-theme.css
Normal file
142
docs/app/css/prettify-theme.css
Normal file
@ -0,0 +1,142 @@
|
||||
/* GitHub Theme */
|
||||
.prettyprint {
|
||||
background: white;
|
||||
font-family: Menlo, 'Bitstream Vera Sans Mono', 'DejaVu Sans Mono', Monaco, Consolas, monospace;
|
||||
font-size: 12px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.lang-text * {
|
||||
color: #333333!important;
|
||||
}
|
||||
|
||||
.pln {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
@media screen {
|
||||
.str {
|
||||
color: #dd1144;
|
||||
}
|
||||
|
||||
.kwd {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.com {
|
||||
color: #999988;
|
||||
}
|
||||
|
||||
.typ {
|
||||
color: #445588;
|
||||
}
|
||||
|
||||
.lit {
|
||||
color: #445588;
|
||||
}
|
||||
|
||||
.pun {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.opn {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.clo {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: navy;
|
||||
}
|
||||
|
||||
.atn {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
.atv {
|
||||
color: #dd1144;
|
||||
}
|
||||
|
||||
.dec {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.var {
|
||||
color: teal;
|
||||
}
|
||||
|
||||
.fun {
|
||||
color: #990000;
|
||||
}
|
||||
}
|
||||
@media print, projection {
|
||||
.str {
|
||||
color: #006600;
|
||||
}
|
||||
|
||||
.kwd {
|
||||
color: #006;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.com {
|
||||
color: #600;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.typ {
|
||||
color: #404;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.lit {
|
||||
color: #004444;
|
||||
}
|
||||
|
||||
.pun, .opn, .clo {
|
||||
color: #444400;
|
||||
}
|
||||
|
||||
.tag {
|
||||
color: #006;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.atn {
|
||||
color: #440044;
|
||||
}
|
||||
|
||||
.atv {
|
||||
color: #006600;
|
||||
}
|
||||
}
|
||||
/* Specify class=linenums on a pre to get line numbering */
|
||||
ol.linenums {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
/* IE indents via margin-left */
|
||||
li.L0,
|
||||
li.L1,
|
||||
li.L2,
|
||||
li.L3,
|
||||
li.L4,
|
||||
li.L5,
|
||||
li.L6,
|
||||
li.L7,
|
||||
li.L8,
|
||||
li.L9 {
|
||||
/* */
|
||||
}
|
||||
|
||||
/* Alternate shading for lines */
|
||||
li.L1,
|
||||
li.L3,
|
||||
li.L5,
|
||||
li.L7,
|
||||
li.L9 {
|
||||
/* */
|
||||
}
|
55
docs/app/index.html
Normal file
55
docs/app/index.html
Normal file
@ -0,0 +1,55 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Angular 2 Docs</title>
|
||||
<base href="/">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/lib/angular-material/angular-material.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/prettify-theme.css">
|
||||
<link rel="stylesheet" type="text/css" href="/css/app.css">
|
||||
|
||||
<script src="/lib/hammerjs/hammer.js"></script>
|
||||
<script src="/lib/google-code-prettify/src/prettify.js"></script>
|
||||
<script src="/lib/google-code-prettify/src/lang-css.js"></script>
|
||||
<script src="/lib/angular/angular.js"></script>
|
||||
<script src="/lib/angular-animate/angular-animate.js"></script>
|
||||
<script src="/lib/angular-aria/angular-aria.js"></script>
|
||||
<script src="/lib/angular-material/angular-material.js"></script>
|
||||
<script src="/js/navigation-modules.js"></script>
|
||||
<script src="/js/navigation-guides.js"></script>
|
||||
<script src="/js/app.js"></script>
|
||||
<script src="/js/code.js"></script>
|
||||
</head>
|
||||
<body ng-app="app" ng-controller="NavController as nav" layout="column">
|
||||
|
||||
<md-toolbar md-scroll-shrink>
|
||||
<h1 class="md-toolbar-tools">Angular V2</h1>
|
||||
</md-toolbar>
|
||||
|
||||
<section layout="row">
|
||||
|
||||
<md-content class="left-nav">
|
||||
<h2>Navigation</h2>
|
||||
<section ng-repeat="area in nav.areas">
|
||||
<h3>{{ area.name }}</h3>
|
||||
<md-list>
|
||||
<md-item ng-repeat="section in area.sections">
|
||||
<h3><a href="{{section.path}}">{{section.name}}</a></h3>
|
||||
<ul>
|
||||
<li ng-repeat="page in section.pages">
|
||||
<a href="{{page.path}}">{{ page.name }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</md-item>
|
||||
</md-list>
|
||||
</section>
|
||||
</md-content>
|
||||
|
||||
|
||||
<md-content class="md-padding">
|
||||
<ng-include autoscroll src="nav.currentPage.partial"></ng-include>
|
||||
</md-content>
|
||||
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
46
docs/app/js/app.js
Normal file
46
docs/app/js/app.js
Normal file
@ -0,0 +1,46 @@
|
||||
angular.module('app', ['ngMaterial', 'navigation-modules', 'navigation-guides', 'code'])
|
||||
|
||||
.config(function($locationProvider) {
|
||||
$locationProvider.html5Mode(true);
|
||||
})
|
||||
|
||||
.controller('NavController', ['$scope', '$location', 'MODULES', 'GUIDES',
|
||||
function($scope, $location, MODULES, GUIDES) {
|
||||
var that = this;
|
||||
|
||||
this.areas = [
|
||||
{ name: 'Guides', sections: [ { pages: GUIDES.pages } ] },
|
||||
{ name: 'Modules', sections: MODULES.sections }
|
||||
];
|
||||
|
||||
this.updateCurrentPage = function(path) {
|
||||
console.log('path', path);
|
||||
this.currentPage = null;
|
||||
|
||||
this.areas.forEach(function(area) {
|
||||
area.sections.forEach(function(section) {
|
||||
|
||||
// Short-circuit out if the page has been found
|
||||
if ( that.currentPage ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (section.path === path) {
|
||||
console.log('found!');
|
||||
that.currentPage = section;
|
||||
} else {
|
||||
section.pages.forEach(function(page) {
|
||||
if (page.path === path) {
|
||||
that.currentPage = page;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$scope.$watch(
|
||||
function getLocationPath() { return $location.path(); },
|
||||
function handleLocationPathChange(path) { that.updateCurrentPage(path); }
|
||||
);
|
||||
}]);
|
15
docs/app/js/code.js
Normal file
15
docs/app/js/code.js
Normal file
@ -0,0 +1,15 @@
|
||||
angular.module('code', [])
|
||||
|
||||
.directive('code', function() {
|
||||
return {
|
||||
restrict: 'E',
|
||||
terminal: true,
|
||||
compile: function(element) {
|
||||
var linenums = element.hasClass('linenum');
|
||||
var match = /lang-(\S+)/.exec(element[0].className);
|
||||
var lang = match && match[1];
|
||||
var html = element.html();
|
||||
element.html(window.prettyPrintOne(html, lang, linenums));
|
||||
}
|
||||
};
|
||||
});
|
20
docs/bower.json
Normal file
20
docs/bower.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "angular-docs",
|
||||
"main": "index.js",
|
||||
"version": "0.0.0",
|
||||
"homepage": "https://github.com/angular/angular",
|
||||
"authors": [],
|
||||
"license": "Apache-2.0",
|
||||
"private": true,
|
||||
"ignore": [
|
||||
"**/.*",
|
||||
"node_modules",
|
||||
"bower_components",
|
||||
"test",
|
||||
"tests"
|
||||
],
|
||||
"dependencies": {
|
||||
"angular-material": "~0.6.0",
|
||||
"google-code-prettify": "~1.0.3"
|
||||
}
|
||||
}
|
117
docs/docs-package/index.js
Normal file
117
docs/docs-package/index.js
Normal file
@ -0,0 +1,117 @@
|
||||
var Package = require('dgeni').Package;
|
||||
var jsdocPackage = require('dgeni-packages/jsdoc');
|
||||
var nunjucksPackage = require('dgeni-packages/nunjucks');
|
||||
var typescriptPackage = require('../typescript-package');
|
||||
var linksPackage = require('../links-package');
|
||||
var gitPackage = require('dgeni-packages/git');
|
||||
var path = require('canonical-path');
|
||||
|
||||
// Define the dgeni package for generating the docs
|
||||
module.exports = new Package('angular-v2-docs', [jsdocPackage, nunjucksPackage, typescriptPackage, linksPackage, gitPackage])
|
||||
|
||||
// Register the services and file readers
|
||||
.factory(require('./readers/ngdoc'))
|
||||
|
||||
// Register the processors
|
||||
.processor(require('./processors/convertPrivateClassesToInterfaces'))
|
||||
.processor(require('./processors/generateNavigationDoc'))
|
||||
.processor(require('./processors/extractTitleFromGuides'))
|
||||
.processor(require('./processors/createOverviewDump'))
|
||||
.processor(require('./processors/checkUnbalancedBackTicks'))
|
||||
|
||||
// Configure the log service
|
||||
.config(function(log) {
|
||||
log.level = 'warn';
|
||||
})
|
||||
|
||||
|
||||
.config(function(renderDocsProcessor, versionInfo) {
|
||||
renderDocsProcessor.extraData.versionInfo = versionInfo;
|
||||
})
|
||||
|
||||
// Configure file reading
|
||||
.config(function(readFilesProcessor, ngdocFileReader, readTypeScriptModules) {
|
||||
readFilesProcessor.fileReaders = [ngdocFileReader];
|
||||
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
||||
readFilesProcessor.sourceFiles = [
|
||||
{ include: 'modules/*/docs/**/*.md', basePath: 'modules' },
|
||||
{ include: 'docs/content/**/*.md', basePath: 'docs/content' }
|
||||
];
|
||||
|
||||
readTypeScriptModules.sourceFiles = [
|
||||
'*/*.@(js|es6|ts)',
|
||||
'*/src/**/*.@(js|es6|ts)'
|
||||
];
|
||||
readTypeScriptModules.basePath = path.resolve(readFilesProcessor.basePath, 'modules');
|
||||
})
|
||||
|
||||
|
||||
.config(function(parseTagsProcessor, getInjectables) {
|
||||
// We actually don't want to parse param docs in this package as we are getting the data out using TS
|
||||
parseTagsProcessor.tagDefinitions.forEach(function(tagDef) {
|
||||
if (tagDef.name === 'param') {
|
||||
tagDef.docProperty = 'paramData';
|
||||
tagDef.transforms = [];
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
// Configure links
|
||||
.config(function(getLinkInfo) {
|
||||
getLinkInfo.useFirstAmbiguousLink = true;
|
||||
})
|
||||
|
||||
|
||||
// Configure file writing
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/docs';
|
||||
})
|
||||
|
||||
|
||||
// Configure rendering
|
||||
.config(function(templateFinder, templateEngine) {
|
||||
|
||||
// Nunjucks and Angular conflict in their template bindings so change Nunjucks
|
||||
templateEngine.config.tags = {
|
||||
variableStart: '{$',
|
||||
variableEnd: '$}'
|
||||
};
|
||||
|
||||
templateFinder.templateFolders
|
||||
.unshift(path.resolve(__dirname, 'templates'));
|
||||
|
||||
templateFinder.templatePatterns = [
|
||||
'${ doc.template }',
|
||||
'${ doc.id }.${ doc.docType }.template.html',
|
||||
'${ doc.id }.template.html',
|
||||
'${ doc.docType }.template.html',
|
||||
'common.template.html'
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
// Configure ids and paths
|
||||
.config(function(computeIdsProcessor, computePathsProcessor) {
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['guide'],
|
||||
getId: function(doc) {
|
||||
return doc.fileInfo.relativePath
|
||||
// path should be relative to `modules` folder
|
||||
.replace(/.*\/?modules\//, '')
|
||||
// path should not include `/docs/`
|
||||
.replace(/\/docs\//, '/')
|
||||
// path should not have a suffix
|
||||
.replace(/\.\w*$/, '');
|
||||
},
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['guide'],
|
||||
pathTemplate: '/${id}',
|
||||
outputPathTemplate: 'partials/guides/${id}.html'
|
||||
});
|
||||
});
|
1
docs/docs-package/mocks/importedSrc.ts
Normal file
1
docs/docs-package/mocks/importedSrc.ts
Normal file
@ -0,0 +1 @@
|
||||
export var x = 100;
|
10
docs/docs-package/mocks/mockPackage.js
Normal file
10
docs/docs-package/mocks/mockPackage.js
Normal file
@ -0,0 +1,10 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = function mockPackage() {
|
||||
|
||||
return new Package('mockPackage', [require('../')])
|
||||
|
||||
// provide a mock log service
|
||||
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); });
|
||||
|
||||
};
|
34
docs/docs-package/mocks/testSrc.ts
Normal file
34
docs/docs-package/mocks/testSrc.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* This is the module description
|
||||
*/
|
||||
|
||||
export * from 'importedSrc';
|
||||
|
||||
/**
|
||||
* This is some random other comment
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is MyClass
|
||||
*/
|
||||
export class MyClass {
|
||||
message: String;
|
||||
|
||||
/**
|
||||
* Create a new MyClass
|
||||
* @param {String} name The name to say hello to
|
||||
*/
|
||||
constructor(name) { this.message = 'hello ' + name; }
|
||||
|
||||
/**
|
||||
* Return a greeting message
|
||||
*/
|
||||
greet() { return this.message; }
|
||||
}
|
||||
|
||||
/**
|
||||
* An exported function
|
||||
*/
|
||||
export var myFn = (val: number) => return val * 2;
|
28
docs/docs-package/processors/checkUnbalancedBackTicks.js
Normal file
28
docs/docs-package/processors/checkUnbalancedBackTicks.js
Normal file
@ -0,0 +1,28 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
/**
|
||||
* @dgProcessor checkUnbalancedBackTicks
|
||||
* @description
|
||||
* Searches the rendered content for an odd number of (```) backticks,
|
||||
* which would indicate an unbalanced pair and potentially a typo in the
|
||||
* source content.
|
||||
*/
|
||||
module.exports = function checkUnbalancedBackTicks(log, createDocMessage) {
|
||||
|
||||
var BACKTICK_REGEX = /^ *```/gm;
|
||||
|
||||
return {
|
||||
$runAfter: ['checkAnchorLinksProcessor'],
|
||||
$process: function(docs) {
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.renderedContent ) {
|
||||
var matches = doc.renderedContent.match(BACKTICK_REGEX);
|
||||
if (matches && matches.length % 2 !== 0) {
|
||||
log.warn(createDocMessage('checkUnbalancedBackTicks processor: unbalanced backticks found in rendered content', doc));
|
||||
console.log(doc.renderedContent);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
@ -0,0 +1,10 @@
|
||||
module.exports = function convertPrivateClassesToInterfacesProcessor(convertPrivateClassesToInterfaces) {
|
||||
return {
|
||||
$runAfter: ['processing-docs'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$process: function(docs) {
|
||||
convertPrivateClassesToInterfaces(docs, false);
|
||||
return docs;
|
||||
}
|
||||
};
|
||||
};
|
24
docs/docs-package/processors/createOverviewDump.js
Normal file
24
docs/docs-package/processors/createOverviewDump.js
Normal file
@ -0,0 +1,24 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function createOverviewDump() {
|
||||
|
||||
return {
|
||||
$runAfter: ['processing-docs'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$process: function(docs) {
|
||||
var overviewDoc = {
|
||||
id: 'overview-dump',
|
||||
aliases: ['overview-dump'],
|
||||
path: 'overview-dump',
|
||||
outputPath: 'overview-dump.html',
|
||||
modules: []
|
||||
};
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'module' ) {
|
||||
overviewDoc.modules.push(doc);
|
||||
}
|
||||
});
|
||||
docs.push(overviewDoc);
|
||||
}
|
||||
};
|
||||
};
|
24
docs/docs-package/processors/extractTitleFromGuides.js
Normal file
24
docs/docs-package/processors/extractTitleFromGuides.js
Normal file
@ -0,0 +1,24 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function extractTitleFromGuides() {
|
||||
|
||||
return {
|
||||
$runAfter: ['processing-docs'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$process: function(docs) {
|
||||
_(docs).forEach(function(doc) {
|
||||
if (doc.docType === 'guide') {
|
||||
doc.name = doc.name || getNameFromHeading(doc.description);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
function getNameFromHeading(text) {
|
||||
var match = /^\s*#\s*(.*)/.exec(text);
|
||||
if (match) {
|
||||
return match[1];
|
||||
}
|
||||
}
|
68
docs/docs-package/processors/generateNavigationDoc.js
Normal file
68
docs/docs-package/processors/generateNavigationDoc.js
Normal file
@ -0,0 +1,68 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function generateNavigationDoc() {
|
||||
|
||||
return {
|
||||
$runAfter: ['docs-processed'],
|
||||
$runBefore: ['rendering-docs'],
|
||||
$process: function(docs) {
|
||||
var modulesDoc = {
|
||||
value: { sections: [] },
|
||||
moduleName: 'navigation-modules',
|
||||
serviceName: 'MODULES',
|
||||
template: 'data-module.template.js',
|
||||
outputPath: 'js/navigation-modules.js'
|
||||
};
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'module' ) {
|
||||
var moduleNavItem = {
|
||||
path: doc.path,
|
||||
partial: doc.outputPath,
|
||||
name: doc.id,
|
||||
type: 'module',
|
||||
pages: []
|
||||
};
|
||||
|
||||
modulesDoc.value.sections.push(moduleNavItem);
|
||||
|
||||
_.forEach(doc.exports, function(exportDoc) {
|
||||
if (!exportDoc.private) {
|
||||
var exportNavItem = {
|
||||
path: exportDoc.path,
|
||||
partial: exportDoc.outputPath,
|
||||
name: exportDoc.name,
|
||||
type: exportDoc.docType
|
||||
};
|
||||
moduleNavItem.pages.push(exportNavItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
docs.push(modulesDoc);
|
||||
|
||||
|
||||
var guidesDoc = {
|
||||
value: { pages: [] },
|
||||
moduleName: 'navigation-guides',
|
||||
serviceName: 'GUIDES',
|
||||
template: 'data-module.template.js',
|
||||
outputPath: 'js/navigation-guides.js'
|
||||
};
|
||||
|
||||
_.forEach(docs, function(doc) {
|
||||
if ( doc.docType === 'guide' ) {
|
||||
var guideDoc = {
|
||||
path: doc.path,
|
||||
partial: doc.outputPath,
|
||||
name: doc.name,
|
||||
type: 'guide'
|
||||
};
|
||||
guidesDoc.value.pages.push(guideDoc);
|
||||
}
|
||||
});
|
||||
docs.push(guidesDoc);
|
||||
}
|
||||
};
|
||||
};
|
32
docs/docs-package/readers/ngdoc.js
Normal file
32
docs/docs-package/readers/ngdoc.js
Normal file
@ -0,0 +1,32 @@
|
||||
var path = require('canonical-path');
|
||||
|
||||
/**
|
||||
* @dgService ngdocFileReader
|
||||
* @description
|
||||
* This file reader will pull the contents from a text file (by default .ngdoc)
|
||||
*
|
||||
* The doc will initially have the form:
|
||||
* ```
|
||||
* {
|
||||
* content: 'the content of the file',
|
||||
* startingLine: 1
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
module.exports = function ngdocFileReader() {
|
||||
var reader = {
|
||||
name: 'ngdocFileReader',
|
||||
defaultPattern: /\.md$/,
|
||||
getDocs: function(fileInfo) {
|
||||
|
||||
// We return a single element array because ngdoc files only contain one document
|
||||
return [{
|
||||
docType: 'guide',
|
||||
content: fileInfo.content,
|
||||
startingLine: 1
|
||||
}];
|
||||
}
|
||||
};
|
||||
|
||||
return reader;
|
||||
};
|
45
docs/docs-package/readers/ngdoc.spec.js
Normal file
45
docs/docs-package/readers/ngdoc.spec.js
Normal file
@ -0,0 +1,45 @@
|
||||
var ngdocFileReaderFactory = require('./ngdoc');
|
||||
var path = require('canonical-path');
|
||||
|
||||
describe('ngdocFileReader', function() {
|
||||
|
||||
var fileReader;
|
||||
|
||||
var createFileInfo = function(file, content, basePath) {
|
||||
return {
|
||||
fileReader: fileReader.name,
|
||||
filePath: file,
|
||||
baseName: path.basename(file, path.extname(file)),
|
||||
extension: path.extname(file).replace(/^\./, ''),
|
||||
basePath: basePath,
|
||||
relativePath: path.relative(basePath, file),
|
||||
content: content
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
beforeEach(function() {
|
||||
fileReader = ngdocFileReaderFactory();
|
||||
});
|
||||
|
||||
|
||||
describe('defaultPattern', function() {
|
||||
it('should match .md files', function() {
|
||||
expect(fileReader.defaultPattern.test('abc.md')).toBeTruthy();
|
||||
expect(fileReader.defaultPattern.test('abc.js')).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getDocs', function() {
|
||||
it('should return an object containing info about the file and its contents', function() {
|
||||
var fileInfo = createFileInfo('project/path/modules/someModule/foo/docs/subfolder/bar.ngdoc', 'A load of content', 'project/path');
|
||||
expect(fileReader.getDocs(fileInfo)).toEqual([{
|
||||
docType: 'guide',
|
||||
content: 'A load of content',
|
||||
startingLine: 1
|
||||
}]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
44
docs/docs-package/templates/class.template.html
Normal file
44
docs/docs-package/templates/class.template.html
Normal file
@ -0,0 +1,44 @@
|
||||
{% include "lib/paramList.html" -%}
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="class export">{$ doc.name $} <span class="type">{$ doc.docType $}</span></h1>
|
||||
<p class="module">exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }<br/>
|
||||
defined in {$ githubViewLink(doc) $}
|
||||
</p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{%- if doc.decorators %}
|
||||
<h2>Annotations</h2>
|
||||
{%- for decorator in doc.decorators %}
|
||||
<h3 class="annotation">@{$ decorator.name $}{$ paramList(decorator.arguments) $}</h3>
|
||||
{% endfor %}
|
||||
{% endif -%}
|
||||
|
||||
{%- if doc.constructorDoc or doc.members.length -%}
|
||||
<h2>Members</h2>
|
||||
|
||||
{%- if doc.constructorDoc %}
|
||||
<section class="member constructor">
|
||||
<h1 id="constructor" class="name">{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) $}</h1>
|
||||
{% marked %}
|
||||
{$ doc.constructorDoc.description $}
|
||||
{% endmarked %}
|
||||
</section>
|
||||
{% endif -%}
|
||||
|
||||
{%- for member in doc.members %}{% if not member.private %}
|
||||
<section class="member">
|
||||
<h1 id="{$ member.name $}" class="name">
|
||||
{$ member.name $}{% if member.optional %}?{% endif %}{$ paramList(member.params) $}
|
||||
</h1>
|
||||
{% marked %}
|
||||
{$ member.description $}
|
||||
{% endmarked %}
|
||||
</section>
|
||||
|
||||
{% endif %}{% endfor %}
|
||||
{%- endif -%}
|
||||
|
||||
{% endblock %}
|
9
docs/docs-package/templates/common.template.html
Normal file
9
docs/docs-package/templates/common.template.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{$ doc.id $}</h1>
|
||||
<h2>({$ doc.docType $})</h2>
|
||||
<div>
|
||||
{$ doc.description | marked $}
|
||||
</div>
|
||||
{% endblock %}
|
1
docs/docs-package/templates/const.template.html
Normal file
1
docs/docs-package/templates/const.template.html
Normal file
@ -0,0 +1 @@
|
||||
{% extends 'var.template.html' -%}
|
3
docs/docs-package/templates/data-module.template.js
Normal file
3
docs/docs-package/templates/data-module.template.js
Normal file
@ -0,0 +1,3 @@
|
||||
angular.module('{$ doc.moduleName $}', [])
|
||||
|
||||
.value('{$ doc.serviceName $}', {$ doc.value | json $});
|
11
docs/docs-package/templates/function.template.html
Normal file
11
docs/docs-package/templates/function.template.html
Normal file
@ -0,0 +1,11 @@
|
||||
{% include "lib/paramList.html" -%}
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' -%}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="function export">{$ doc.name $}{$ paramList(doc.parameters) $}</h1>
|
||||
<p class="module">exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }<br/>
|
||||
defined in {$ githubViewLink(doc) $}</p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% endblock %}
|
5
docs/docs-package/templates/guide.template.html
Normal file
5
docs/docs-package/templates/guide.template.html
Normal file
@ -0,0 +1,5 @@
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
{$ doc.description | marked $}
|
||||
{% endblock %}
|
1
docs/docs-package/templates/interface.template.html
Normal file
1
docs/docs-package/templates/interface.template.html
Normal file
@ -0,0 +1 @@
|
||||
{% extends 'class.template.html' -%}
|
1
docs/docs-package/templates/layout/base.template.html
Normal file
1
docs/docs-package/templates/layout/base.template.html
Normal file
@ -0,0 +1 @@
|
||||
{% block body %}{% endblock %}
|
3
docs/docs-package/templates/lib/githubLinks.html
Normal file
3
docs/docs-package/templates/lib/githubLinks.html
Normal file
@ -0,0 +1,3 @@
|
||||
{% macro githubViewLink(doc) -%}
|
||||
<a href="https://github.com/{$ versionInfo.gitRepoInfo.owner $}/{$ versionInfo.gitRepoInfo.repo $}/tree/{$ versionInfo.currentVersion.isSnapshot and versionInfo.currentVersion.SHA or versionInfo.currentVersion.raw $}/modules/{$ doc.fileInfo.relativePath $}#L{$ doc.location.start.line+1 $}-L{$ doc.location.end.line+1 $}">{$ doc.fileInfo.relativePath $} (line {$ doc.location.start.line+1 $})</a>
|
||||
{%- endmacro -%}
|
7
docs/docs-package/templates/lib/paramList.html
Normal file
7
docs/docs-package/templates/lib/paramList.html
Normal file
@ -0,0 +1,7 @@
|
||||
{% macro paramList(params) -%}
|
||||
{%- if params -%}<span class="params">(
|
||||
{%- for param in params -%}
|
||||
<span class="param">{$ param | escape $}{% if not loop.last %}, {% endif %}</span>
|
||||
{%- endfor %})</span>
|
||||
{%- endif %}
|
||||
{%- endmacro -%}
|
19
docs/docs-package/templates/module.template.html
Normal file
19
docs/docs-package/templates/module.template.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1 class="id">{$ doc.id $} <span class="type">module</span></h1>
|
||||
<p>defined in {$ githubViewLink(doc) $}</p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% if doc.exports.length %}
|
||||
<h2>Exports</h2>
|
||||
<ul>
|
||||
{%- for exportDoc in doc.exports %}
|
||||
{% if not exportDoc.private -%}
|
||||
<li><a href="{$ exportDoc.path $}"><strong>{$ exportDoc.name $}</strong> {$ exportDoc.docType $}</a></li>
|
||||
{%- endif %}
|
||||
{%- endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% endblock %}
|
43
docs/docs-package/templates/overview-dump.template.html
Normal file
43
docs/docs-package/templates/overview-dump.template.html
Normal file
@ -0,0 +1,43 @@
|
||||
{% include "lib/paramList.html" -%}
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title></title>
|
||||
<style>
|
||||
h2 {
|
||||
padding-left: 20px;
|
||||
}
|
||||
h3 {
|
||||
padding-left: 50px;
|
||||
}
|
||||
h4 {
|
||||
padding-left: 60px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
<h1>Modules</h1>
|
||||
|
||||
{% for module in doc.modules %}
|
||||
|
||||
<h2>{$ module.id $}
|
||||
{%- if module.public %} (public){% endif %}</h2>
|
||||
|
||||
{% for export in module.exports %}
|
||||
<h3>{$ export.name $}</h3>
|
||||
|
||||
{%- if export.constructorDoc %}
|
||||
<h4>{$ doc.constructorDoc.name $}{$ paramList(doc.constructorDoc.params) $}</h4>
|
||||
{% endif -%}
|
||||
{%- for member in export.members %}
|
||||
<h4>{$ member.name $}{$ paramList(member.params) $}</h4>
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
{% endfor %}
|
||||
|
||||
</body>
|
||||
</html>
|
10
docs/docs-package/templates/type-alias.template.html
Normal file
10
docs/docs-package/templates/type-alias.template.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{$ doc.name $} <span class="type">type alias</span></h1>
|
||||
<p class="module">exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }<br/>
|
||||
defined in {$ githubViewLink(doc) $}</p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% endblock %}
|
10
docs/docs-package/templates/var.template.html
Normal file
10
docs/docs-package/templates/var.template.html
Normal file
@ -0,0 +1,10 @@
|
||||
{% include "lib/githubLinks.html" -%}
|
||||
{% extends 'layout/base.template.html' %}
|
||||
|
||||
{% block body %}
|
||||
<h1>{$ doc.name $} <span class="type">variable</span></h1>
|
||||
<p class="module">exported from {@link {$ doc.moduleDoc.id $} {$doc.moduleDoc.id $} }<br/>
|
||||
defined in {$ githubViewLink(doc) $}</p>
|
||||
<p>{$ doc.description | marked $}</p>
|
||||
|
||||
{% endblock %}
|
12
docs/links-package/index.js
Normal file
12
docs/links-package/index.js
Normal file
@ -0,0 +1,12 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = new Package('links', [])
|
||||
|
||||
.factory(require('./inline-tag-defs/link'))
|
||||
.factory(require('dgeni-packages/ngdoc/services/getAliases'))
|
||||
.factory(require('dgeni-packages/ngdoc/services/getDocFromAlias'))
|
||||
.factory(require('./services/getLinkInfo'))
|
||||
|
||||
.config(function(inlineTagProcessor, linkInlineTagDef) {
|
||||
inlineTagProcessor.inlineTagDefinitions.push(linkInlineTagDef);
|
||||
});
|
33
docs/links-package/inline-tag-defs/link.js
Normal file
33
docs/links-package/inline-tag-defs/link.js
Normal file
@ -0,0 +1,33 @@
|
||||
var INLINE_LINK = /(\S+)(?:\s+([\s\S]+))?/;
|
||||
|
||||
/**
|
||||
* @dgService linkInlineTagDef
|
||||
* @description
|
||||
* Process inline link tags (of the form {@link some/uri Some Title}), replacing them with HTML anchors
|
||||
* @kind function
|
||||
* @param {Object} url The url to match
|
||||
* @param {Function} docs error message
|
||||
* @return {String} The html link information
|
||||
*
|
||||
* @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc
|
||||
*/
|
||||
module.exports = function linkInlineTagDef(getLinkInfo, createDocMessage, log) {
|
||||
return {
|
||||
name: 'link',
|
||||
description: 'Process inline link tags (of the form {@link some/uri Some Title}), replacing them with HTML anchors',
|
||||
handler: function(doc, tagName, tagDescription) {
|
||||
|
||||
// Parse out the uri and title
|
||||
return tagDescription.replace(INLINE_LINK, function(match, uri, title) {
|
||||
|
||||
var linkInfo = getLinkInfo(uri, title, doc);
|
||||
|
||||
if ( !linkInfo.valid ) {
|
||||
log.warn(createDocMessage(linkInfo.error, doc));
|
||||
}
|
||||
|
||||
return "<a href='" + linkInfo.url + "'>" + linkInfo.title + "</a>";
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
72
docs/links-package/services/getLinkInfo.js
Normal file
72
docs/links-package/services/getLinkInfo.js
Normal file
@ -0,0 +1,72 @@
|
||||
var _ = require('lodash');
|
||||
var path = require('canonical-path');
|
||||
|
||||
/**
|
||||
* @dgService getLinkInfo
|
||||
* @description
|
||||
* Get link information to a document that matches the given url
|
||||
* @kind function
|
||||
* @param {String} url The url to match
|
||||
* @param {String} title An optional title to return in the link information
|
||||
* @return {Object} The link information
|
||||
*
|
||||
* @property {boolean} relativeLinks Whether we expect the links to be relative to the originating doc
|
||||
*/
|
||||
module.exports = function getLinkInfo(getDocFromAlias, encodeCodeBlock, log) {
|
||||
|
||||
return function getLinkInfoImpl(url, title, currentDoc) {
|
||||
var linkInfo = {
|
||||
url: url,
|
||||
type: 'url',
|
||||
valid: true,
|
||||
title: title || url
|
||||
};
|
||||
|
||||
if ( !url ) {
|
||||
throw new Error('Invalid url');
|
||||
}
|
||||
|
||||
var docs = getDocFromAlias(url, currentDoc);
|
||||
|
||||
if ( !getLinkInfoImpl.useFirstAmbiguousLink && docs.length > 1 ) {
|
||||
|
||||
linkInfo.valid = false;
|
||||
linkInfo.errorType = 'ambiguous';
|
||||
linkInfo.error = 'Ambiguous link: "' + url + '".\n' +
|
||||
docs.reduce(function(msg, doc) { return msg + '\n "' + doc.id + '" ('+ doc.docType + ') : (' + doc.path + ' / ' + doc.fileInfo.relativePath + ')'; }, 'Matching docs: ');
|
||||
|
||||
} else if ( docs.length >= 1 ) {
|
||||
|
||||
linkInfo.url = docs[0].path;
|
||||
linkInfo.title = title || encodeCodeBlock(docs[0].name, true);
|
||||
linkInfo.type = 'doc';
|
||||
|
||||
if ( getLinkInfoImpl.relativeLinks && currentDoc && currentDoc.path ) {
|
||||
var currentFolder = path.dirname(currentDoc.path);
|
||||
var docFolder = path.dirname(linkInfo.url);
|
||||
var relativeFolder = path.relative(path.join('/', currentFolder), path.join('/', docFolder));
|
||||
linkInfo.url = path.join(relativeFolder, path.basename(linkInfo.url));
|
||||
log.debug(currentDoc.path, docs[0].path, linkInfo.url);
|
||||
}
|
||||
|
||||
} else if ( url.indexOf('#') > 0 ) {
|
||||
var pathAndHash = url.split('#');
|
||||
linkInfo = getLinkInfoImpl(pathAndHash[0], title, currentDoc);
|
||||
linkInfo.url = linkInfo.url + '#' + pathAndHash[1];
|
||||
return linkInfo;
|
||||
|
||||
} else if ( url.indexOf('/') === -1 && url.indexOf('#') !== 0 ) {
|
||||
|
||||
linkInfo.valid = false;
|
||||
linkInfo.errorType = 'missing';
|
||||
linkInfo.error = 'Invalid link (does not match any doc): "' + url + '"';
|
||||
|
||||
} else {
|
||||
|
||||
linkInfo.title = title || (( url.indexOf('#') === 0 ) ? url.substring(1) : path.basename(url, '.html'));
|
||||
|
||||
}
|
||||
|
||||
return linkInfo;
|
||||
};
|
||||
};
|
24
docs/public-docs-package/index.js
Normal file
24
docs/public-docs-package/index.js
Normal file
@ -0,0 +1,24 @@
|
||||
var Package = require('dgeni').Package;
|
||||
var basePackage = require('../docs-package');
|
||||
|
||||
module.exports = new Package('angular-v2-public-docs', [basePackage])
|
||||
|
||||
.config(function(readTypeScriptModules) {
|
||||
readTypeScriptModules.sourceFiles = [
|
||||
'angular2/lifecycle_hooks.ts',
|
||||
'angular2/core.ts',
|
||||
'angular2/http.ts',
|
||||
'angular2/router.ts',
|
||||
'angular2/test.ts'
|
||||
];
|
||||
readTypeScriptModules.hidePrivateMembers = true;
|
||||
})
|
||||
|
||||
.config(function(getLinkInfo) {
|
||||
getLinkInfo.useFirstAmbiguousLink = false;
|
||||
})
|
||||
|
||||
// Configure file writing
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/public_docs';
|
||||
});
|
121
docs/typescript-definition-package/index.js
Normal file
121
docs/typescript-definition-package/index.js
Normal file
@ -0,0 +1,121 @@
|
||||
var Package = require('dgeni').Package;
|
||||
var jsdocPackage = require('dgeni-packages/jsdoc');
|
||||
var nunjucksPackage = require('dgeni-packages/nunjucks');
|
||||
var typescriptPackage = require('../typescript-package');
|
||||
var gitPackage = require('dgeni-packages/git');
|
||||
var path = require('canonical-path');
|
||||
|
||||
// Define the dgeni package for generating the docs
|
||||
module.exports = new Package('angular-v2-docs', [jsdocPackage, nunjucksPackage, typescriptPackage, gitPackage])
|
||||
|
||||
// Register the processors
|
||||
.processor(require('./processors/createTypeDefinitionFile'))
|
||||
|
||||
.config(function(readFilesProcessor, inlineTagProcessor) {
|
||||
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
||||
// Don't run unwanted processors
|
||||
readFilesProcessor.$enabled = false;
|
||||
inlineTagProcessor.$enabled = false;
|
||||
})
|
||||
|
||||
|
||||
// Configure the log service
|
||||
.config(function(log) {
|
||||
log.level = 'info';
|
||||
})
|
||||
|
||||
|
||||
.config(function(renderDocsProcessor, versionInfo) {
|
||||
renderDocsProcessor.extraData.versionInfo = versionInfo;
|
||||
})
|
||||
|
||||
.config(function(readFilesProcessor, inlineTagProcessor, readTypeScriptModules, createTypeDefinitionFile) {
|
||||
|
||||
// Don't run unwanted processors
|
||||
readFilesProcessor.$enabled = false; // We are not using the normal file reading processor
|
||||
inlineTagProcessor.$enabled = false; // We are not actually processing the inline link tags
|
||||
|
||||
// Configure file reading
|
||||
readFilesProcessor.basePath = path.resolve(__dirname, '../..');
|
||||
readTypeScriptModules.sourceFiles = [
|
||||
'angular2/angular2.ts',
|
||||
'angular2/web_worker/worker.ts',
|
||||
'angular2/web_worker/ui.ts',
|
||||
'angular2/router.ts',
|
||||
'angular2/http.ts',
|
||||
'angular2/test_lib.ts'
|
||||
];
|
||||
readTypeScriptModules.basePath = path.resolve(path.resolve(__dirname, '../../modules'));
|
||||
|
||||
createTypeDefinitionFile.typeDefinitions = [
|
||||
{
|
||||
id: 'angular2/angular2',
|
||||
references: ['../es6-shim/es6-shim.d.ts'],
|
||||
modules: {
|
||||
'angular2/angular2': {namespace: 'ng', id: 'angular2/angular2'},
|
||||
'angular2/web_worker/worker': {namespace: 'ngWorker', id: 'angular2/web_worker/worker'},
|
||||
'angular2/web_worker/ui': {namespace: 'ngUi', id: 'angular2/web_worker/ui'}
|
||||
}
|
||||
},
|
||||
{
|
||||
id: 'angular2/router',
|
||||
references: ['./angular2.d.ts'],
|
||||
remapTypes: {Type: 'ng.Type', InjectableReference: 'ng.InjectableReference'},
|
||||
modules: {'angular2/router': {namespace: 'ngRouter', id: 'angular2/router'}}
|
||||
},
|
||||
{
|
||||
id: 'angular2/http',
|
||||
references: ['./angular2.d.ts'],
|
||||
remapTypes: {Type: 'ng.Type', Observable: 'ng.Observable', EventEmitter: 'ng.EventEmitter', InjectableReference: 'ng.InjectableReference' },
|
||||
modules: {'angular2/http': {namespace: 'ngHttp', id: 'angular2/http'}}
|
||||
},
|
||||
{
|
||||
id: 'angular2/test_lib',
|
||||
references: ['./angular2.d.ts', '../jasmine/jasmine.d.ts'],
|
||||
remapTypes: { Type: 'ng.Type', Binding: 'ng.Binding', ViewMetadata: 'ng.ViewMetadata', Injector: 'ng.Injector',
|
||||
Predicate: 'ng.Predicate', ElementRef: 'ng.ElementRef', DebugElement: 'ng.DebugElement',
|
||||
InjectableReference: 'ng.InjectableReference' },
|
||||
modules: {'angular2/test_lib': {namespace: 'ngTestLib', id: 'angular2/test_lib'}}
|
||||
}
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
.config(function(parseTagsProcessor, getInjectables) {
|
||||
// We actually don't want to parse param docs in this package as we are getting the data out using TS
|
||||
parseTagsProcessor.tagDefinitions.forEach(function(tagDef) {
|
||||
if (tagDef.name === 'param') {
|
||||
tagDef.docProperty = 'paramData';
|
||||
tagDef.transforms = [];
|
||||
}
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
|
||||
// Configure file writing
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/docs';
|
||||
})
|
||||
|
||||
|
||||
// Configure rendering
|
||||
.config(function(templateFinder, templateEngine) {
|
||||
|
||||
// Nunjucks and Angular conflict in their template bindings so change Nunjucks
|
||||
templateEngine.config.tags = {
|
||||
variableStart: '{$',
|
||||
variableEnd: '$}'
|
||||
};
|
||||
|
||||
templateFinder.templateFolders
|
||||
.unshift(path.resolve(__dirname, 'templates'));
|
||||
|
||||
templateFinder.templatePatterns = [
|
||||
'${ doc.template }',
|
||||
'${ doc.id }.${ doc.docType }.template.html',
|
||||
'${ doc.id }.template.html',
|
||||
'${ doc.docType }.template.html',
|
||||
'common.template.html'
|
||||
];
|
||||
});
|
11
docs/typescript-definition-package/mocks/mockPackage.js
Normal file
11
docs/typescript-definition-package/mocks/mockPackage.js
Normal file
@ -0,0 +1,11 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = function mockPackage() {
|
||||
|
||||
return new Package('mockPackage', [require('../')])
|
||||
|
||||
// provide a mock log service
|
||||
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); })
|
||||
// .factory('templateEngine', function() { return {}; });
|
||||
|
||||
};
|
216
docs/typescript-definition-package/processors/code_gen.js
Normal file
216
docs/typescript-definition-package/processors/code_gen.js
Normal file
@ -0,0 +1,216 @@
|
||||
'use strict';
|
||||
|
||||
function DtsSerializer(remap) {
|
||||
this.remap = remap;
|
||||
}
|
||||
|
||||
DtsSerializer.prototype = {
|
||||
_initializerRegex: /\s*=[^>][^,}]*/g,
|
||||
|
||||
constructor: DtsSerializer,
|
||||
|
||||
declaration: function(buffer, ast) {
|
||||
buffer.push(ast.name);
|
||||
if (ast.optional) buffer.push('?');
|
||||
if (ast.typeParameters) {
|
||||
buffer.push('<');
|
||||
buffer.push(ast.typeParameters.join(', '));
|
||||
buffer.push('>');
|
||||
}
|
||||
if (ast.parameters) {
|
||||
buffer.push('(');
|
||||
var parameters = ast.parameters;
|
||||
for (var i = 0; i < parameters.length; i++) {
|
||||
parameters[i] = parameters[i].replace(this._initializerRegex, '');
|
||||
}
|
||||
buffer.push(parameters.join(', '));
|
||||
buffer.push(')');
|
||||
}
|
||||
if (!isConstructor(ast)) {
|
||||
if (ast.returnType) {
|
||||
buffer.push(': ', ast.returnType);
|
||||
} else if (ast.parameters) {
|
||||
buffer.push(': void');
|
||||
} else {
|
||||
buffer.push(': any');
|
||||
}
|
||||
}
|
||||
buffer.push(';\n');
|
||||
},
|
||||
|
||||
comment: function(buffer, commentText) {
|
||||
if (!(commentText && commentText.match(/\S/))) return;
|
||||
|
||||
buffer.push('/**\n');
|
||||
commentText.replace(/\n*$/, '').split('\n').forEach(function(line) {
|
||||
buffer.push(' * ' + line + '\n');
|
||||
});
|
||||
buffer.push(' */\n');
|
||||
},
|
||||
|
||||
member: function(buffer, ast) {
|
||||
if (ast.private) return;
|
||||
|
||||
buffer.push('\n');
|
||||
this.comment(buffer, ast.content);
|
||||
|
||||
if (ast.isStatic) buffer.push('static ');
|
||||
this.declaration(buffer, ast);
|
||||
},
|
||||
|
||||
interfaceOrClass: function(buffer, ast, isInterface) {
|
||||
buffer.push(isInterface ? 'interface ' : 'class ');
|
||||
buffer.push(ast.name);
|
||||
buffer.push(ast.typeParams);
|
||||
buffer.push(ast.heritage);
|
||||
buffer.push(' {');
|
||||
buffer.indent();
|
||||
if (ast.newMember) this.member(buffer, ast.newMember);
|
||||
if (ast.callMember) this.member(buffer, ast.callMember);
|
||||
if (ast.constructorDoc) this.member(buffer, ast.constructorDoc);
|
||||
|
||||
ast.statics.forEach(function(staticMember) {
|
||||
this.member(buffer, staticMember);
|
||||
}.bind(this));
|
||||
|
||||
ast.members.forEach(function(member) {
|
||||
this.member(buffer, member);
|
||||
}.bind(this));
|
||||
|
||||
buffer.unindent();
|
||||
buffer.push('}');
|
||||
},
|
||||
|
||||
enum: function(buffer, ast) {
|
||||
buffer.push('enum ');
|
||||
buffer.push(ast.name);
|
||||
buffer.push(ast.typeParams);
|
||||
buffer.push(ast.heritage);
|
||||
buffer.push(' {');
|
||||
buffer.indent();
|
||||
|
||||
ast.members.forEach(function(member, index) {
|
||||
buffer.push('\n');
|
||||
this.comment(buffer, member.content);
|
||||
buffer.push(member.name);
|
||||
if (index !== (ast.members.length - 1)) {
|
||||
buffer.push(',\n');
|
||||
}
|
||||
}.bind(this));
|
||||
|
||||
buffer.unindent();
|
||||
buffer.push('}\n');
|
||||
},
|
||||
|
||||
function: function(buffer, ast) {
|
||||
buffer.push('function ');
|
||||
this.declaration(buffer, ast);
|
||||
},
|
||||
|
||||
var: function(buffer, ast) {
|
||||
buffer.push('var ');
|
||||
this.declaration(buffer, ast);
|
||||
},
|
||||
|
||||
let: function(buffer, ast) {
|
||||
buffer.push('let ');
|
||||
this.declaration(buffer, ast);
|
||||
},
|
||||
|
||||
const: function(buffer, ast) {
|
||||
buffer.push('const ');
|
||||
this.declaration(buffer, ast);
|
||||
},
|
||||
|
||||
typeAlias: function(buffer, ast) {
|
||||
buffer.push('type ', ast.name, ' = ', ast.returnType);
|
||||
},
|
||||
|
||||
serializeExport: function(ast) {
|
||||
var buffer = new Buffer();
|
||||
buffer.push('\n');
|
||||
|
||||
try {
|
||||
this.comment(buffer, ast.content);
|
||||
|
||||
switch (ast.docType) {
|
||||
case 'class': this.interfaceOrClass(buffer, ast, false); break;
|
||||
case 'interface': this.interfaceOrClass(buffer, ast, true); break;
|
||||
case 'function': this.function(buffer, ast); break;
|
||||
case 'enum': this.enum(buffer, ast); break;
|
||||
case 'var': this.var(buffer, ast); break;
|
||||
case 'let': this.let(buffer, ast); break;
|
||||
case 'const': this.const(buffer, ast); break;
|
||||
case 'type-alias': this.typeAlias(buffer, ast); break;
|
||||
default: throw new Error("unknown docType: " + ast.docType);
|
||||
}
|
||||
|
||||
var string = buffer.toString();
|
||||
for (var key in this.remap) {
|
||||
if (this.remap.hasOwnProperty(key)) {
|
||||
string = string.replace(new RegExp('\\b' + key + '\\b', 'gm'), this.remap[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return string;
|
||||
} catch (e) {
|
||||
console.log(e.toString(), e.stack);
|
||||
return 'ERROR: ' + e.toString();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function Buffer() {
|
||||
this._globalBuffer = [];
|
||||
this._indentedBuffer = [];
|
||||
this._indentationLevel = 1;
|
||||
}
|
||||
|
||||
Buffer.prototype = {
|
||||
constructor: Buffer,
|
||||
|
||||
push: function() {
|
||||
this._indentedBuffer.push.apply(this._indentedBuffer, arguments);
|
||||
},
|
||||
|
||||
indent: function() {
|
||||
this._globalBuffer.push({indentationLevel: this._indentationLevel, content: this._indentedBuffer.join('')});
|
||||
this._indentationLevel++;
|
||||
this._indentedBuffer = [];
|
||||
},
|
||||
|
||||
unindent: function() {
|
||||
this._globalBuffer.push({indentationLevel: this._indentationLevel, content: this._indentedBuffer.join('')});
|
||||
this._indentationLevel--;
|
||||
this._indentedBuffer = [];
|
||||
},
|
||||
|
||||
toString: function() {
|
||||
if (this._indentationLevel !== 1) {
|
||||
throw new Exception("Forgot to unindent? Indentation level: " + this._indentationLevel);
|
||||
}
|
||||
|
||||
this.unindent();
|
||||
|
||||
var string = '';
|
||||
|
||||
this._globalBuffer.forEach(function(indentedChunk) {
|
||||
var indentation = (new Array(indentedChunk.indentationLevel * 2 + 1)).join(' ');
|
||||
indentedChunk.content.split('\n').forEach(function(line) {
|
||||
string += indentation + line + '\n';
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
return string;
|
||||
}
|
||||
};
|
||||
|
||||
function isConstructor(ast) {
|
||||
return ast.parameters && ast.name === "constructor";
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
DtsSerializer: DtsSerializer
|
||||
};
|
||||
|
@ -0,0 +1,72 @@
|
||||
var _ = require('lodash');
|
||||
var path = require('canonical-path');
|
||||
var codeGen = require('./code_gen.js');
|
||||
|
||||
module.exports = function createTypeDefinitionFile(log, convertPrivateClassesToInterfaces) {
|
||||
|
||||
return {
|
||||
$runAfter: ['processing-docs'],
|
||||
$runBefore: ['docs-processed'],
|
||||
$validate: {
|
||||
dtsPath: { presence: true },
|
||||
dtsExtension: { presence: true },
|
||||
typeDefinitions: { presence: true }
|
||||
},
|
||||
dtsPath: 'typings',
|
||||
dtsExtension: '.d.ts',
|
||||
typeDefinitions: [],
|
||||
$process: function(docs) {
|
||||
var dtsPath = this.dtsPath;
|
||||
var dtsExtension = this.dtsExtension;
|
||||
|
||||
// For each type definition that we wish to create we define a dgeni "doc" for it
|
||||
var typeDefDocs = _.map(this.typeDefinitions, function(def) {
|
||||
|
||||
var id = def.id + dtsExtension;
|
||||
var docPath = path.join(dtsPath, id);
|
||||
|
||||
return {
|
||||
docType: 'type-definition',
|
||||
id: id,
|
||||
aliases: [id],
|
||||
path: docPath,
|
||||
outputPath: docPath,
|
||||
// A type definition may include a number of top level modules
|
||||
// And those modules could be aliased (such as 'angular2/angular2.api' ->
|
||||
// 'angular2/angular2')
|
||||
moduleDocs: _.transform(def.modules,
|
||||
function(moduleDocs, props, alias) {
|
||||
moduleDocs[props.id] = {
|
||||
id: alias,
|
||||
doc: null, namespace: props.namespace,
|
||||
references: def.references
|
||||
};
|
||||
}),
|
||||
dts: new codeGen.DtsSerializer(def.remapTypes)
|
||||
};
|
||||
});
|
||||
|
||||
// Now add all the module docs to their corresponding type definition doc
|
||||
_.forEach(docs, function(doc) {
|
||||
_.forEach(typeDefDocs, function(typeDefDoc) {
|
||||
if(typeDefDoc.moduleDocs[doc.id]) {
|
||||
// Add a copy, because we are going to modify it
|
||||
typeDefDoc.moduleDocs[doc.id].doc = doc;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return _.filter(typeDefDocs, function(doc) {
|
||||
_.forEach(doc.moduleDocs, function(modDoc, alias) {
|
||||
if (!doc || !modDoc.doc) {
|
||||
log.error('createTypeDefinitionFile processor: no such module "' + alias + '" (Did you forget to add it to the modules to load?)');
|
||||
doc = null;
|
||||
return;
|
||||
}
|
||||
convertPrivateClassesToInterfaces(modDoc.doc.exports, true);
|
||||
});
|
||||
return !!doc;
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
@ -0,0 +1,53 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
var path = require('canonical-path');
|
||||
var _ = require('lodash');
|
||||
|
||||
describe('createTypeDefinitionFile processor', function() {
|
||||
var dgeni, injector, processor;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
processor = injector.get('createTypeDefinitionFile');
|
||||
|
||||
// Initialize the processor
|
||||
processor.typeDefinitions = [{
|
||||
id: 'angular2/angular2',
|
||||
modules: {
|
||||
'angular2/angular2': {
|
||||
id: 'angular2/angular2',
|
||||
namespace: 'ng'
|
||||
}
|
||||
}
|
||||
}];
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe('classes with private constructors', function() {
|
||||
|
||||
it('should convert heritage from `implements` into `extends`', function() {
|
||||
|
||||
// Create some mock docs for testing
|
||||
var docs = [
|
||||
{
|
||||
id: 'angular2/angular2',
|
||||
exports: [
|
||||
{ docType: 'class', heritage: 'implements Xyz', constructorDoc: { private: true } }
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
docs = processor.$process(docs);
|
||||
|
||||
expect(docs.length).toEqual(1);
|
||||
expect(docs[0].docType).toEqual('type-definition');
|
||||
|
||||
var moduleDoc = docs[0].moduleDocs['angular2/angular2'].doc;
|
||||
expect(moduleDoc.exports.length).toEqual(2);
|
||||
expect(moduleDoc.exports[0].heritage).toEqual('extends Xyz');
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -0,0 +1,17 @@
|
||||
{% extends '../type-definition.template.html' %}
|
||||
{% block staticDeclarations %}
|
||||
|
||||
interface Map<K,V> {}
|
||||
|
||||
{% for alias, module in doc.moduleDocs %}
|
||||
declare module {$ module.namespace $} {
|
||||
// See https://github.com/Microsoft/TypeScript/issues/1168
|
||||
class BaseException /* extends Error */ {
|
||||
message: string;
|
||||
stack: string;
|
||||
toString(): string;
|
||||
}
|
||||
interface InjectableReference {}
|
||||
}
|
||||
{% endfor %}
|
||||
{% endblock %}
|
@ -0,0 +1,43 @@
|
||||
|
||||
{%- macro commentBlock(doc, level) -%}
|
||||
{%- if doc.content | trim %}
|
||||
|
||||
{% if level > 1 %}{$ '/**' | indent(level-1, true) | replace(r/\n$/, "") $}{% else %}/**{% endif %}
|
||||
{$ doc.content | trim | replace(r/^/gm, "* ") | indent(level, true) | replace(r/\n$/, "") $}
|
||||
{$ '*/' | indent(level, true) | replace(r/\n$/, "") $}{% endif -%}
|
||||
{%- endmacro -%}
|
||||
|
||||
|
||||
// Type definitions for Angular v{$ versionInfo.currentVersion.full | replace(r/\+/, "_") $}
|
||||
// Project: http://angular.io/
|
||||
// Definitions by: angular team <https://github.com/angular/>
|
||||
// Definitions: https://github.com/borisyankov/DefinitelyTyped
|
||||
|
||||
// ***********************************************************
|
||||
// This file is generated by the Angular build process.
|
||||
// Please do not create manual edits or send pull requests
|
||||
// modifying this file.
|
||||
// ***********************************************************
|
||||
{% for alias, module in doc.moduleDocs %}
|
||||
{%- if module.references.length %}
|
||||
// {$ alias $} depends transitively on these libraries.
|
||||
// If you don't have them installed you can install them using TSD
|
||||
// https://github.com/DefinitelyTyped/tsd
|
||||
{%- endif %}
|
||||
{% for reference in module.references %}
|
||||
///<reference path="{$ reference $}"/>{% endfor %}{% endfor %}
|
||||
{% block staticDeclarations %}{% endblock %}
|
||||
{% for alias, module in doc.moduleDocs %}
|
||||
{$ commentBlock(module.doc, 1) $}
|
||||
declare module {$ module.namespace $} {
|
||||
|
||||
{%- for export in module.doc.exports -%}
|
||||
{$ doc.dts.serializeExport(export) $}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
declare module "{$ alias $}" {
|
||||
export = {$ module.namespace $};
|
||||
}
|
||||
|
||||
{% endfor %}
|
70
docs/typescript-package/index.js
Normal file
70
docs/typescript-package/index.js
Normal file
@ -0,0 +1,70 @@
|
||||
var basePackage = require('dgeni-packages/base');
|
||||
var Package = require('dgeni').Package;
|
||||
var path = require('canonical-path');
|
||||
|
||||
// Define the dgeni package for generating the docs
|
||||
module.exports = new Package('typescript-parsing', [basePackage])
|
||||
|
||||
// Register the services and file readers
|
||||
.factory(require('./services/modules'))
|
||||
.factory(require('./services/tsParser'))
|
||||
.factory(require('./services/tsParser/createCompilerHost'))
|
||||
.factory(require('./services/tsParser/getFileInfo'))
|
||||
.factory(require('./services/tsParser/getExportDocType'))
|
||||
.factory(require('./services/tsParser/getContent'))
|
||||
|
||||
.factory(require('./services/convertPrivateClassesToInterfaces'))
|
||||
|
||||
.factory('EXPORT_DOC_TYPES', function() {
|
||||
return [
|
||||
'class',
|
||||
'interface',
|
||||
'function',
|
||||
'var',
|
||||
'const',
|
||||
'enum',
|
||||
'type-alias'
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
// Register the processors
|
||||
.processor(require('./processors/readTypeScriptModules'))
|
||||
|
||||
|
||||
// Configure the log service
|
||||
.config(function(log) {
|
||||
log.level = 'warn';
|
||||
})
|
||||
|
||||
|
||||
// Configure ids and paths
|
||||
.config(function(computeIdsProcessor, computePathsProcessor, EXPORT_DOC_TYPES) {
|
||||
|
||||
computeIdsProcessor.idTemplates.push({
|
||||
docTypes: ['member'],
|
||||
idTemplate: '${classDoc.id}.${name}',
|
||||
getAliases: function(doc) { return [doc.id]; }
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['member'],
|
||||
pathTemplate: '${classDoc.path}/${name}',
|
||||
getOutputPath: function() {} // These docs are not written to their own file, instead they are part of their class doc
|
||||
});
|
||||
|
||||
var MODULES_DOCS_PATH = 'partials/modules';
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: ['module'],
|
||||
pathTemplate: '/${id}',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${id}/index.html'
|
||||
});
|
||||
|
||||
computePathsProcessor.pathTemplates.push({
|
||||
docTypes: EXPORT_DOC_TYPES,
|
||||
pathTemplate: '${moduleDoc.path}/${name}',
|
||||
outputPathTemplate: MODULES_DOCS_PATH + '/${path}/index.html'
|
||||
});
|
||||
|
||||
});
|
11
docs/typescript-package/mocks/mockPackage.js
Normal file
11
docs/typescript-package/mocks/mockPackage.js
Normal file
@ -0,0 +1,11 @@
|
||||
var Package = require('dgeni').Package;
|
||||
|
||||
module.exports = function mockPackage() {
|
||||
|
||||
return new Package('mockPackage', [require('../')])
|
||||
|
||||
// provide a mock log service
|
||||
.factory('log', function() { return require('dgeni/lib/mocks/log')(false); })
|
||||
.factory('templateEngine', function() { return {}; });
|
||||
|
||||
};
|
@ -0,0 +1,4 @@
|
||||
export var __esModule = true;
|
||||
export class OKToExport {}
|
||||
export function _thisIsPrivate() {}
|
||||
export var thisIsOK = '!';
|
@ -0,0 +1,5 @@
|
||||
export interface MyInterface {
|
||||
optionalProperty? : string
|
||||
<T, U extends Findable<T>>(param: T) : U
|
||||
new (param: number) : MyInterface
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
export class Test {
|
||||
firstItem;
|
||||
constructor() { this.doStuff(); }
|
||||
otherMethod() {}
|
||||
doStuff() {}
|
||||
}
|
@ -0,0 +1 @@
|
||||
export var x = 10;
|
@ -0,0 +1 @@
|
||||
export { x as y} from './privateModule';
|
1
docs/typescript-package/mocks/tsParser/importedSrc.ts
Normal file
1
docs/typescript-package/mocks/tsParser/importedSrc.ts
Normal file
@ -0,0 +1 @@
|
||||
export var x = 100;
|
34
docs/typescript-package/mocks/tsParser/testSrc.ts
Normal file
34
docs/typescript-package/mocks/tsParser/testSrc.ts
Normal file
@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @module
|
||||
* @description
|
||||
* This is the module description
|
||||
*/
|
||||
|
||||
export * from 'importedSrc';
|
||||
|
||||
/**
|
||||
* This is some random other comment
|
||||
*/
|
||||
|
||||
/**
|
||||
* This is MyClass
|
||||
*/
|
||||
export class MyClass {
|
||||
message: String;
|
||||
|
||||
/**
|
||||
* Create a new MyClass
|
||||
* @param {String} name The name to say hello to
|
||||
*/
|
||||
constructor(name) { this.message = 'hello ' + name; }
|
||||
|
||||
/**
|
||||
* Return a greeting message
|
||||
*/
|
||||
greet() { return this.message; }
|
||||
}
|
||||
|
||||
/**
|
||||
* An exported function
|
||||
*/
|
||||
export var myFn = (val: number) => return val * 2;
|
406
docs/typescript-package/processors/readTypeScriptModules.js
Normal file
406
docs/typescript-package/processors/readTypeScriptModules.js
Normal file
@ -0,0 +1,406 @@
|
||||
var glob = require('glob');
|
||||
var path = require('canonical-path');
|
||||
var _ = require('lodash');
|
||||
var ts = require('typescript');
|
||||
|
||||
module.exports = function readTypeScriptModules(tsParser, modules, getFileInfo,
|
||||
getExportDocType, getContent, log) {
|
||||
|
||||
return {
|
||||
$runAfter: ['files-read'],
|
||||
$runBefore: ['parsing-tags'],
|
||||
|
||||
$validate: {
|
||||
sourceFiles: {presence: true},
|
||||
basePath: {presence: true},
|
||||
hidePrivateMembers: {inclusion: [true, false]},
|
||||
sortClassMembers: {inclusion: [true, false]},
|
||||
ignoreExportsMatching: {}
|
||||
},
|
||||
|
||||
// A collection of globs that identify those modules for which we should create docs
|
||||
sourceFiles: [],
|
||||
// The base path from which to load the source files
|
||||
basePath: '.',
|
||||
// We can ignore members of classes that are private
|
||||
hidePrivateMembers: true,
|
||||
// We leave class members sorted in order of declaration
|
||||
sortClassMembers: false,
|
||||
// We can provide a collection of strings or regexes to ignore exports whose export names match
|
||||
ignoreExportsMatching: ['___esModule'],
|
||||
|
||||
$process: function(docs) {
|
||||
|
||||
// Convert ignoreExportsMatching to an array of regexes
|
||||
var ignoreExportsMatching = convertToRegexCollection(this.ignoreExportsMatching);
|
||||
|
||||
var hidePrivateMembers = this.hidePrivateMembers;
|
||||
var sortClassMembers = this.sortClassMembers;
|
||||
|
||||
var basePath = path.resolve(this.basePath);
|
||||
var filesPaths = expandSourceFiles(this.sourceFiles, basePath);
|
||||
var parseInfo = tsParser.parse(filesPaths, this.basePath);
|
||||
var moduleSymbols = parseInfo.moduleSymbols;
|
||||
|
||||
// Iterate through each of the modules that were parsed and generate a module doc
|
||||
// as well as docs for each module's exports.
|
||||
moduleSymbols.forEach(function(moduleSymbol) {
|
||||
|
||||
var moduleDoc = createModuleDoc(moduleSymbol, basePath);
|
||||
|
||||
// Add this module doc to the module lookup collection and the docs collection
|
||||
modules[moduleDoc.id] = moduleDoc;
|
||||
docs.push(moduleDoc);
|
||||
|
||||
// Iterate through this module's exports and generate a doc for each
|
||||
moduleSymbol.exportArray.forEach(function(exportSymbol) {
|
||||
|
||||
// Ignore exports starting with an underscore
|
||||
if (anyMatches(ignoreExportsMatching, exportSymbol.name)) return;
|
||||
|
||||
// If the symbol is an Alias then for most things we want the original resolved symbol
|
||||
var resolvedExport = exportSymbol.resolvedSymbol || exportSymbol;
|
||||
var exportDoc = createExportDoc(exportSymbol.name, resolvedExport, moduleDoc, basePath, parseInfo.typeChecker);
|
||||
log.debug('>>>> EXPORT: ' + exportDoc.name + ' (' + exportDoc.docType + ') from ' + moduleDoc.id);
|
||||
|
||||
exportDoc.members = [];
|
||||
exportDoc.statics = [];
|
||||
|
||||
// Generate docs for each of the export's members
|
||||
if (resolvedExport.flags & ts.SymbolFlags.HasMembers) {
|
||||
|
||||
for(var memberName in resolvedExport.members) {
|
||||
// FIXME(alexeagle): why do generic type params appear in members?
|
||||
if (memberName === 'T') {
|
||||
continue;
|
||||
}
|
||||
log.silly('>>>>>> member: ' + memberName + ' from ' + exportDoc.id + ' in ' + moduleDoc.id);
|
||||
var memberSymbol = resolvedExport.members[memberName];
|
||||
var memberDoc = createMemberDoc(memberSymbol, exportDoc, basePath, parseInfo.typeChecker);
|
||||
|
||||
// We special case the constructor and sort the other members alphabetically
|
||||
if (memberSymbol.flags & ts.SymbolFlags.Constructor) {
|
||||
exportDoc.constructorDoc = memberDoc;
|
||||
docs.push(memberDoc);
|
||||
} else if (!hidePrivateMembers || memberSymbol.name.charAt(0) !== '_') {
|
||||
docs.push(memberDoc);
|
||||
exportDoc.members.push(memberDoc);
|
||||
} else if (memberSymbol.name === '__call' && memberSymbol.flags & ts.SymbolFlags.Signature) {
|
||||
docs.push(memberDoc);
|
||||
exportDoc.callMember = memberDoc;
|
||||
} else if (memberSymbol.name === '__new' && memberSymbol.flags & ts.SymbolFlags.Signature) {
|
||||
docs.push(memberDoc);
|
||||
exportDoc.newMember = memberDoc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exportDoc.docType === 'enum') {
|
||||
for(var memberName in resolvedExport.exports) {
|
||||
log.silly('>>>>>> member: ' + memberName + ' from ' + exportDoc.id + ' in ' + moduleDoc.id);
|
||||
var memberSymbol = resolvedExport.exports[memberName];
|
||||
var memberDoc = createMemberDoc(memberSymbol, exportDoc, basePath, parseInfo.typeChecker);
|
||||
docs.push(memberDoc);
|
||||
exportDoc.members.push(memberDoc);
|
||||
}
|
||||
} else if (resolvedExport.flags & ts.SymbolFlags.HasExports) {
|
||||
for (var exported in resolvedExport.exports) {
|
||||
if (exported === 'prototype') continue;
|
||||
if (hidePrivateMembers && exported.charAt(0) === '_') continue;
|
||||
var memberSymbol = resolvedExport.exports[exported];
|
||||
var memberDoc = createMemberDoc(memberSymbol, exportDoc, basePath, parseInfo.typeChecker);
|
||||
memberDoc.isStatic = true;
|
||||
docs.push(memberDoc);
|
||||
exportDoc.statics.push(memberDoc);
|
||||
}
|
||||
}
|
||||
|
||||
if (sortClassMembers) {
|
||||
exportDoc.members.sort(function(a, b) {
|
||||
if (a.name > b.name) return 1;
|
||||
if (a.name < b.name) return -1;
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
// Add this export doc to its module doc
|
||||
moduleDoc.exports.push(exportDoc);
|
||||
docs.push(exportDoc);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
function createModuleDoc(moduleSymbol, basePath) {
|
||||
var id = moduleSymbol.name.replace(/^"|"$/g, '');
|
||||
var moduleDoc = {
|
||||
docType: 'module',
|
||||
id: id,
|
||||
aliases: [id],
|
||||
moduleTree: moduleSymbol,
|
||||
content: getContent(moduleSymbol),
|
||||
exports: [],
|
||||
fileInfo: getFileInfo(moduleSymbol, basePath),
|
||||
location: getLocation(moduleSymbol)
|
||||
};
|
||||
return moduleDoc;
|
||||
}
|
||||
|
||||
function createExportDoc(name, exportSymbol, moduleDoc, basePath, typeChecker) {
|
||||
var typeParamString = '';
|
||||
var heritageString = '';
|
||||
var typeDefinition = '';
|
||||
|
||||
exportSymbol.declarations.forEach(function(decl) {
|
||||
var sourceFile = ts.getSourceFileOfNode(decl);
|
||||
|
||||
if (decl.typeParameters) {
|
||||
typeParamString = '<' + getText(sourceFile, decl.typeParameters) + '>';
|
||||
}
|
||||
|
||||
if (decl.symbol.flags & ts.SymbolFlags.TypeAlias) {
|
||||
typeDefinition = getText(sourceFile, decl.type);
|
||||
}
|
||||
|
||||
if (decl.heritageClauses) {
|
||||
decl.heritageClauses.forEach(function(heritage) {
|
||||
|
||||
if (heritage.token == ts.SyntaxKind.ExtendsKeyword) {
|
||||
heritageString += " extends";
|
||||
heritage.types.forEach(function(typ, idx) {
|
||||
heritageString += (idx > 0 ? ',' : '') + typ.getFullText();
|
||||
});
|
||||
}
|
||||
|
||||
if (heritage.token == ts.SyntaxKind.ImplementsKeyword) {
|
||||
heritageString += " implements";
|
||||
heritage.types.forEach(function(typ, idx) {
|
||||
heritageString += (idx > 0 ? ', ' : '') + typ.getFullText();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//Make sure duplicate aliases aren't created, so "Ambiguous link" warnings are prevented
|
||||
var aliasNames = [name, moduleDoc.id + '/' + name];
|
||||
if (typeParamString) {
|
||||
aliasNames.push(name + typeParamString);
|
||||
aliasNames.push(moduleDoc.id + '/' + name + typeParamString);
|
||||
}
|
||||
|
||||
var exportDoc = {
|
||||
docType: getExportDocType(exportSymbol),
|
||||
name: name,
|
||||
id: moduleDoc.id + '/' + name,
|
||||
typeParams: typeParamString,
|
||||
heritage: heritageString,
|
||||
decorators: getDecorators(exportSymbol),
|
||||
aliases: aliasNames,
|
||||
moduleDoc: moduleDoc,
|
||||
content: getContent(exportSymbol),
|
||||
fileInfo: getFileInfo(exportSymbol, basePath),
|
||||
location: getLocation(exportSymbol)
|
||||
};
|
||||
|
||||
if (exportDoc.docType === 'var' || exportDoc.docType === 'const') {
|
||||
exportDoc.symbolTypeName = exportSymbol.valueDeclaration.type &&
|
||||
exportSymbol.valueDeclaration.type.typeName &&
|
||||
exportSymbol.valueDeclaration.type.typeName.text;
|
||||
}
|
||||
|
||||
if (exportDoc.docType === 'type-alias') {
|
||||
exportDoc.returnType = getReturnType(typeChecker, exportSymbol);
|
||||
}
|
||||
|
||||
if(exportSymbol.flags & ts.SymbolFlags.Function) {
|
||||
exportDoc.parameters = getParameters(typeChecker, exportSymbol);
|
||||
}
|
||||
if(exportSymbol.flags & ts.SymbolFlags.Value) {
|
||||
exportDoc.returnType = getReturnType(typeChecker, exportSymbol);
|
||||
}
|
||||
if (exportSymbol.flags & ts.SymbolFlags.TypeAlias) {
|
||||
exportDoc.typeDefinition = typeDefinition;
|
||||
}
|
||||
|
||||
// Compute the original module name from the relative file path
|
||||
exportDoc.originalModule = exportDoc.fileInfo.relativePath
|
||||
.replace(new RegExp('\.' + exportDoc.fileInfo.extension + '$'), '');
|
||||
|
||||
return exportDoc;
|
||||
}
|
||||
|
||||
function createMemberDoc(memberSymbol, classDoc, basePath, typeChecker) {
|
||||
var memberDoc = {
|
||||
docType: 'member',
|
||||
classDoc: classDoc,
|
||||
name: memberSymbol.name,
|
||||
decorators: getDecorators(memberSymbol),
|
||||
content: getContent(memberSymbol),
|
||||
fileInfo: getFileInfo(memberSymbol, basePath),
|
||||
location: getLocation(memberSymbol)
|
||||
};
|
||||
|
||||
memberDoc.typeParameters = getTypeParameters(typeChecker, memberSymbol);
|
||||
|
||||
if(memberSymbol.flags & (ts.SymbolFlags.Signature) ) {
|
||||
memberDoc.parameters = getParameters(typeChecker, memberSymbol);
|
||||
memberDoc.returnType = getReturnType(typeChecker, memberSymbol);
|
||||
switch(memberDoc.name) {
|
||||
case '__call':
|
||||
memberDoc.name = '';
|
||||
break;
|
||||
case '__new':
|
||||
memberDoc.name = 'new';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (memberSymbol.flags & ts.SymbolFlags.Method) {
|
||||
// NOTE: we use the property name `parameters` here so we don't conflict
|
||||
// with the `params` property that will be updated by dgeni reading the
|
||||
// `@param` tags from the docs
|
||||
memberDoc.parameters = getParameters(typeChecker, memberSymbol);
|
||||
}
|
||||
|
||||
if (memberSymbol.flags & ts.SymbolFlags.Constructor) {
|
||||
memberDoc.parameters = getParameters(typeChecker, memberSymbol);
|
||||
memberDoc.name = 'constructor';
|
||||
}
|
||||
|
||||
if(memberSymbol.flags & ts.SymbolFlags.Value) {
|
||||
memberDoc.returnType = getReturnType(typeChecker, memberSymbol);
|
||||
}
|
||||
|
||||
if(memberSymbol.flags & ts.SymbolFlags.Optional) {
|
||||
memberDoc.optional = true;
|
||||
}
|
||||
|
||||
return memberDoc;
|
||||
}
|
||||
|
||||
|
||||
function getDecorators(symbol) {
|
||||
var declaration = symbol.valueDeclaration || symbol.declarations[0];
|
||||
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||
|
||||
var decorators = declaration.decorators && declaration.decorators.map(function(decorator) {
|
||||
decorator = decorator.expression;
|
||||
return {
|
||||
name: decorator.expression ? decorator.expression.text : decorator.text,
|
||||
arguments: decorator.arguments && decorator.arguments.map(function(argument) {
|
||||
return getText(sourceFile, argument).trim();
|
||||
})
|
||||
};
|
||||
});
|
||||
return decorators;
|
||||
}
|
||||
|
||||
function getParameters(typeChecker, symbol) {
|
||||
var declaration = symbol.valueDeclaration || symbol.declarations[0];
|
||||
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||
if (!declaration.parameters) {
|
||||
var location = getLocation(symbol);
|
||||
throw new Error('missing declaration parameters for "' + symbol.name +
|
||||
'" in ' + sourceFile.fileName +
|
||||
' at line ' + location.start.line);
|
||||
}
|
||||
return declaration.parameters.map(function(parameter) {
|
||||
var paramText = '';
|
||||
if (parameter.dotDotDotToken) {
|
||||
paramText += '...';
|
||||
}
|
||||
paramText += getText(sourceFile, parameter.name);
|
||||
if (parameter.questionToken || parameter.initializer) {
|
||||
paramText += '?';
|
||||
}
|
||||
if (parameter.type) {
|
||||
paramText += ':' + getType(sourceFile, parameter.type);
|
||||
} else {
|
||||
paramText += ': any';
|
||||
if (parameter.dotDotDotToken) {
|
||||
paramText += '[]';
|
||||
}
|
||||
}
|
||||
return paramText.trim();
|
||||
});
|
||||
}
|
||||
|
||||
function getTypeParameters(typeChecker, symbol) {
|
||||
var declaration = symbol.valueDeclaration || symbol.declarations[0];
|
||||
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||
if (!declaration.typeParameters) return;
|
||||
var typeParams = declaration.typeParameters.map(function(type) {
|
||||
return getText(sourceFile, type).trim();
|
||||
});
|
||||
return typeParams;
|
||||
}
|
||||
|
||||
function getReturnType(typeChecker, symbol) {
|
||||
var declaration = symbol.valueDeclaration || symbol.declarations[0];
|
||||
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||
if (declaration.type) {
|
||||
return getType(sourceFile, declaration.type).trim();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function expandSourceFiles(sourceFiles, basePath) {
|
||||
var filePaths = [];
|
||||
sourceFiles.forEach(function(sourcePattern) {
|
||||
filePaths = filePaths.concat(glob.sync(sourcePattern, { cwd: basePath }));
|
||||
});
|
||||
return filePaths;
|
||||
}
|
||||
|
||||
|
||||
function getText(sourceFile, node) {
|
||||
return sourceFile.text.substring(node.pos, node.end);
|
||||
}
|
||||
|
||||
|
||||
// Strip any local renamed imports from the front of types
|
||||
function getType(sourceFile, type) {
|
||||
var text = getText(sourceFile, type);
|
||||
while (text.indexOf(".") >= 0) {
|
||||
// Keep namespaced symbols in RxNext
|
||||
if (text.match(/^\s*RxNext\./)) break;
|
||||
// handle the case List<thing.stuff> -> List<stuff>
|
||||
text = text.replace(/([^.<]*)\.([^>]*)/, "$2");
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
function getLocation(symbol) {
|
||||
var node = symbol.valueDeclaration || symbol.declarations[0];
|
||||
var sourceFile = ts.getSourceFileOfNode(node);
|
||||
var location = {
|
||||
start: ts.getLineAndCharacterOfPosition(sourceFile, node.pos),
|
||||
end: ts.getLineAndCharacterOfPosition(sourceFile, node.end)
|
||||
};
|
||||
return location;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function convertToRegexCollection(items) {
|
||||
if (!items) return [];
|
||||
|
||||
// Must be an array
|
||||
if (!_.isArray(items)) {
|
||||
items = [items];
|
||||
}
|
||||
|
||||
// Convert string to exact matching regexes
|
||||
return items.map(function(item) {
|
||||
return _.isString(item) ? new RegExp('^' + item + '$') : item;
|
||||
});
|
||||
}
|
||||
|
||||
function anyMatches(regexes, item) {
|
||||
for(var i=0; i<regexes.length; ++i) {
|
||||
if ( item.match(regexes[i]) ) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
127
docs/typescript-package/processors/readTypeScriptModules.spec.js
Normal file
127
docs/typescript-package/processors/readTypeScriptModules.spec.js
Normal file
@ -0,0 +1,127 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
var path = require('canonical-path');
|
||||
var _ = require('lodash');
|
||||
|
||||
describe('readTypeScriptModules', function() {
|
||||
var dgeni, injector, processor;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
processor = injector.get('readTypeScriptModules');
|
||||
processor.basePath = path.resolve(__dirname, '../mocks/readTypeScriptModules');
|
||||
});
|
||||
|
||||
|
||||
describe('exportDocs', function() {
|
||||
it('should provide the original module if the export is re-exported', function() {
|
||||
processor.sourceFiles = [ 'publicModule.ts' ];
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
|
||||
var exportedDoc = docs[1];
|
||||
expect(exportedDoc.originalModule).toEqual('privateModule');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('ignoreExportsMatching', function() {
|
||||
it('should ignore exports that match items in the `ignoreExportsMatching` property', function() {
|
||||
processor.sourceFiles = [ 'ignoreExportsMatching.ts'];
|
||||
processor.ignoreExportsMatching = [/^_/];
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
|
||||
var moduleDoc = docs[0];
|
||||
expect(moduleDoc.docType).toEqual('module');
|
||||
expect(moduleDoc.exports).toEqual([
|
||||
jasmine.objectContaining({ name: 'OKToExport' }),
|
||||
jasmine.objectContaining({ name: 'thisIsOK' })
|
||||
]);
|
||||
});
|
||||
|
||||
it('should only ignore `___esModule` exports by default', function() {
|
||||
processor.sourceFiles = [ 'ignoreExportsMatching.ts'];
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
|
||||
var moduleDoc = docs[0];
|
||||
expect(moduleDoc.docType).toEqual('module');
|
||||
expect(getNames(moduleDoc.exports)).toEqual([
|
||||
'OKToExport',
|
||||
'_thisIsPrivate',
|
||||
'thisIsOK'
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('interfaces', function() {
|
||||
|
||||
it('should mark optional properties', function() {
|
||||
processor.sourceFiles = [ 'interfaces.ts'];
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
|
||||
var moduleDoc = docs[0];
|
||||
var exportedInterface = moduleDoc.exports[0];
|
||||
var member = exportedInterface.members[0];
|
||||
expect(member.name).toEqual('optionalProperty');
|
||||
expect(member.optional).toEqual(true);
|
||||
});
|
||||
|
||||
|
||||
it('should handle "call" type interfaces', function() {
|
||||
processor.sourceFiles = [ 'interfaces.ts'];
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
|
||||
var moduleDoc = docs[0];
|
||||
var exportedInterface = moduleDoc.exports[0];
|
||||
|
||||
expect(exportedInterface.callMember).toBeDefined();
|
||||
expect(exportedInterface.callMember.parameters).toEqual(['param: T']);
|
||||
expect(exportedInterface.callMember.returnType).toEqual('U');
|
||||
expect(exportedInterface.callMember.typeParameters).toEqual(['T', 'U extends Findable<T>']);
|
||||
expect(exportedInterface.newMember).toBeDefined();
|
||||
expect(exportedInterface.newMember.parameters).toEqual(['param: number']);
|
||||
expect(exportedInterface.newMember.returnType).toEqual('MyInterface');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('ordering of members', function() {
|
||||
it('should order class members in order of appearance (by default)', function() {
|
||||
processor.sourceFiles = ['orderingOfMembers.ts'];
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
var classDoc = _.find(docs, { docType: 'class' });
|
||||
expect(classDoc.docType).toEqual('class');
|
||||
expect(getNames(classDoc.members)).toEqual([
|
||||
'firstItem',
|
||||
'otherMethod',
|
||||
'doStuff',
|
||||
]);
|
||||
});
|
||||
|
||||
|
||||
it('should not order class members if not sortClassMembers is false', function() {
|
||||
processor.sourceFiles = ['orderingOfMembers.ts'];
|
||||
processor.sortClassMembers = false;
|
||||
var docs = [];
|
||||
processor.$process(docs);
|
||||
var classDoc = _.find(docs, { docType: 'class' });
|
||||
expect(classDoc.docType).toEqual('class');
|
||||
expect(getNames(classDoc.members)).toEqual([
|
||||
'firstItem',
|
||||
'otherMethod',
|
||||
'doStuff'
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function getNames(collection) {
|
||||
return collection.map(function(item) { return item.name; });
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
var _ = require('lodash');
|
||||
|
||||
module.exports = function convertPrivateClassesToInterfaces() {
|
||||
return function(exportDocs, addInjectableReference) {
|
||||
_.forEach(exportDocs, function(exportDoc) {
|
||||
|
||||
// Search for classes with a constructor marked as `@private`
|
||||
if (exportDoc.docType === 'class' && exportDoc.constructorDoc && exportDoc.constructorDoc.private) {
|
||||
|
||||
// Convert this class to an interface with no constructor
|
||||
exportDoc.docType = 'interface';
|
||||
exportDoc.constructorDoc = null;
|
||||
|
||||
if (exportDoc.heritage) {
|
||||
// convert the heritage since interfaces use `extends` not `implements`
|
||||
exportDoc.heritage = exportDoc.heritage.replace('implements', 'extends');
|
||||
}
|
||||
|
||||
if (addInjectableReference) {
|
||||
// Add the `declare var SomeClass extends InjectableReference` construct
|
||||
exportDocs.push({
|
||||
docType: 'var',
|
||||
name: exportDoc.name,
|
||||
id: exportDoc.id,
|
||||
returnType: 'InjectableReference'
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
};
|
@ -0,0 +1,76 @@
|
||||
var mockPackage = require('../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
var _ = require('lodash');
|
||||
|
||||
describe('readTypeScriptModules', function() {
|
||||
var dgeni, injector, convertPrivateClassesToInterfaces;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
convertPrivateClassesToInterfaces = injector.get('convertPrivateClassesToInterfaces');
|
||||
});
|
||||
|
||||
it('should convert private class docs to interface docs', function() {
|
||||
var docs = [
|
||||
{
|
||||
docType: 'class',
|
||||
name: 'privateClass',
|
||||
id: 'privateClass',
|
||||
constructorDoc: { private: true }
|
||||
}
|
||||
];
|
||||
convertPrivateClassesToInterfaces(docs, false);
|
||||
expect(docs[0].docType).toEqual('interface');
|
||||
});
|
||||
|
||||
|
||||
it('should not touch non-private class docs', function() {
|
||||
var docs = [
|
||||
{
|
||||
docType: 'class',
|
||||
name: 'privateClass',
|
||||
id: 'privateClass',
|
||||
constructorDoc: { }
|
||||
}
|
||||
];
|
||||
convertPrivateClassesToInterfaces(docs, false);
|
||||
expect(docs[0].docType).toEqual('class');
|
||||
});
|
||||
|
||||
|
||||
it('should convert the heritage since interfaces use `extends` not `implements`', function() {
|
||||
var docs = [
|
||||
{
|
||||
docType: 'class',
|
||||
name: 'privateClass',
|
||||
id: 'privateClass',
|
||||
constructorDoc: { private: true },
|
||||
heritage: 'implements parentInterface'
|
||||
}
|
||||
];
|
||||
convertPrivateClassesToInterfaces(docs, false);
|
||||
expect(docs[0].heritage).toEqual('extends parentInterface');
|
||||
});
|
||||
|
||||
|
||||
it('should add new injectable reference types, if specified, to the passed in collection', function() {
|
||||
var docs = [
|
||||
{
|
||||
docType: 'class',
|
||||
name: 'privateClass',
|
||||
id: 'privateClass',
|
||||
constructorDoc: { private: true },
|
||||
heritage: 'implements parentInterface'
|
||||
}
|
||||
];
|
||||
convertPrivateClassesToInterfaces(docs, true);
|
||||
expect(docs[1]).toEqual({
|
||||
docType : 'var',
|
||||
name : 'privateClass',
|
||||
id : 'privateClass',
|
||||
returnType : 'InjectableReference'
|
||||
});
|
||||
});
|
||||
|
||||
});
|
3
docs/typescript-package/services/modules.js
Normal file
3
docs/typescript-package/services/modules.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = function modules() {
|
||||
return {};
|
||||
};
|
@ -0,0 +1,75 @@
|
||||
var ts = require('typescript');
|
||||
var fs = require('fs');
|
||||
var path = require('canonical-path');
|
||||
|
||||
// We need to provide our own version of CompilerHost because we want to set the
|
||||
// base directory and specify what extensions to consider when trying to load a source
|
||||
// file
|
||||
module.exports = function createCompilerHost(log) {
|
||||
|
||||
return function createCompilerHost(options, baseDir, extensions) {
|
||||
|
||||
return {
|
||||
getSourceFile: function(fileName, languageVersion, onError) {
|
||||
var text, resolvedPath, resolvedPathWithExt;
|
||||
|
||||
// Strip off the extension and resolve relative to the baseDir
|
||||
baseFilePath = fileName.replace(/\.[^.]+$/, '');
|
||||
resolvedPath = path.resolve(baseDir, baseFilePath);
|
||||
|
||||
// Iterate through each possible extension and return the first source file that is actually found
|
||||
for(var i=0; i<extensions.length; i++) {
|
||||
|
||||
// Try reading the content from files using each of the given extensions
|
||||
try {
|
||||
resolvedPathWithExt = resolvedPath + extensions[i];
|
||||
log.silly('getSourceFile:', resolvedPathWithExt);
|
||||
text = fs.readFileSync(resolvedPathWithExt, { encoding: options.charset });
|
||||
log.debug('found source file:', fileName, resolvedPathWithExt);
|
||||
return ts.createSourceFile(baseFilePath + extensions[i], text, languageVersion);
|
||||
}
|
||||
catch(e) {
|
||||
// Try again if the file simply did not exist, otherwise report the error as a warning
|
||||
if(e.code !== 'ENOENT') {
|
||||
if (onError) onError(e.message);
|
||||
log.warn('Error reading ' + resolvedPathWithExt + ' : ' + e.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
getDefaultLibFileName: function(options) {
|
||||
return path.resolve(path.dirname(ts.sys.getExecutingFilePath()), ts.getDefaultLibFileName(options));
|
||||
},
|
||||
writeFile: function(fileName, data, writeByteOrderMark, onError) {
|
||||
// no-op
|
||||
},
|
||||
getCurrentDirectory: function() {
|
||||
return baseDir;
|
||||
},
|
||||
useCaseSensitiveFileNames: function() {
|
||||
return ts.sys.useCaseSensitiveFileNames;
|
||||
},
|
||||
getCanonicalFileName: function(fileName) {
|
||||
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
|
||||
// otherwise use toLowerCase as a canonical form.
|
||||
return ts.sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
|
||||
},
|
||||
getNewLine: function() {
|
||||
return ts.sys.newLine;
|
||||
},
|
||||
fileExists: function(fileName) {
|
||||
var resolvedPath = path.resolve(baseDir, fileName);
|
||||
try {
|
||||
fs.statSync(resolvedPath);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
readFile: function(fileName) {
|
||||
var resolvedPath = path.resolve(baseDir, fileName);
|
||||
return fs.readFileSync(resolvedPath, { encoding: options.charset });
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
@ -0,0 +1,80 @@
|
||||
var mockPackage = require('../../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
var path = require('canonical-path');
|
||||
var ts = require('typescript');
|
||||
|
||||
describe('createCompilerHost', function() {
|
||||
var dgeni, injector, options, host, baseDir, extensions;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
var createCompilerHost = injector.get('createCompilerHost');
|
||||
|
||||
options = { charset: 'utf8' };
|
||||
baseDir = path.resolve(__dirname, '../../mocks/tsParser');
|
||||
extensions = ['.ts', '.js'];
|
||||
|
||||
host = createCompilerHost(options, baseDir, extensions);
|
||||
});
|
||||
|
||||
describe('getSourceFile', function() {
|
||||
it('should return a SourceFile object for a given path, with fileName relative to baseDir', function() {
|
||||
var sourceFile = host.getSourceFile('testSrc.ts');
|
||||
expect(sourceFile.fileName).toEqual('testSrc.ts');
|
||||
expect(sourceFile.pos).toEqual(0);
|
||||
expect(sourceFile.text).toEqual(jasmine.any(String));
|
||||
});
|
||||
|
||||
it('should try each of the configured extensions and update the filename to the correct extension', function() {
|
||||
var sourceFile = host.getSourceFile('testSrc.js');
|
||||
expect(sourceFile.fileName).toEqual('testSrc.ts');
|
||||
|
||||
sourceFile = host.getSourceFile('../mockPackage.ts');
|
||||
expect(sourceFile.fileName).toEqual('../mockPackage.js');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getDefaultLibFileName', function() {
|
||||
it('should return a path to the default library', function() {
|
||||
expect(host.getDefaultLibFileName(options)).toContain('typescript/lib/lib.d.ts');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('writeFile', function() {
|
||||
it('should do nothing', function() {
|
||||
host.writeFile();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getCurrentDirectory', function() {
|
||||
it('should return the baseDir', function() {
|
||||
expect(host.getCurrentDirectory()).toEqual(baseDir);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('useCaseSensitiveFileNames', function() {
|
||||
it('should return true if the OS is case sensitive', function() {
|
||||
expect(host.useCaseSensitiveFileNames()).toBe(ts.sys.useCaseSensitiveFileNames);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getCanonicalFileName', function() {
|
||||
it('should lower case the filename', function() {
|
||||
var expectedFilePath = host.useCaseSensitiveFileNames() ? 'SomeFile.ts' : 'somefile.ts';
|
||||
expect(host.getCanonicalFileName('SomeFile.ts')).toEqual(expectedFilePath);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
describe('getNewLine', function() {
|
||||
it('should return the newline character for the OS', function() {
|
||||
expect(host.getNewLine()).toEqual(require('os').EOL);
|
||||
});
|
||||
});
|
||||
});
|
49
docs/typescript-package/services/tsParser/getContent.js
Normal file
49
docs/typescript-package/services/tsParser/getContent.js
Normal file
@ -0,0 +1,49 @@
|
||||
var ts = require('typescript');
|
||||
var LEADING_STAR = /^[^\S\r\n]*\*[^\S\n\r]?/gm;
|
||||
|
||||
module.exports = function getContent() {
|
||||
return function(symbol) {
|
||||
|
||||
var content = "";
|
||||
|
||||
if (!symbol.declarations) return content;
|
||||
|
||||
symbol.declarations.forEach(function(declaration) {
|
||||
|
||||
// If this is left side of dotted module declaration, there is no doc comment associated with this declaration
|
||||
if (declaration.kind === ts.SyntaxKind.ModuleDeclaration && declaration.body.kind === ts.SyntaxKind.ModuleDeclaration) {
|
||||
return content;
|
||||
}
|
||||
|
||||
// If this is dotted module name, get the doc comments from the parent
|
||||
while (declaration.kind === ts.SyntaxKind.ModuleDeclaration && declaration.parent.kind === ts.SyntaxKind.ModuleDeclaration) {
|
||||
declaration = declaration.parent;
|
||||
}
|
||||
|
||||
// If this is a variable declaration then we get the doc comments from the grand parent
|
||||
if (declaration.kind === ts.SyntaxKind.VariableDeclaration) {
|
||||
declaration = declaration.parent.parent;
|
||||
}
|
||||
|
||||
// Get the source file of this declaration
|
||||
var sourceFile = ts.getSourceFileOfNode(declaration);
|
||||
var commentRanges = ts.getJsDocComments(declaration, sourceFile);
|
||||
|
||||
if (commentRanges) {
|
||||
commentRanges.forEach(function(commentRange) {
|
||||
content += sourceFile.text
|
||||
.substring(commentRange.pos+ '/**'.length, commentRange.end - '*/'.length)
|
||||
.replace(LEADING_STAR, '')
|
||||
.trim();
|
||||
if (commentRange.hasTrailingNewLine) {
|
||||
content += '\n';
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
content += '\n';
|
||||
});
|
||||
|
||||
return content;
|
||||
};
|
||||
};
|
@ -0,0 +1,54 @@
|
||||
var ts = require('typescript');
|
||||
|
||||
module.exports = function getExportDocType(log) {
|
||||
|
||||
return function(symbol) {
|
||||
if(symbol.flags & ts.SymbolFlags.Function) {
|
||||
return 'function';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.Class) {
|
||||
return 'class';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.Interface) {
|
||||
return 'interface';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.ConstEnum) {
|
||||
return 'enum';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.RegularEnum) {
|
||||
return 'enum';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.Property) {
|
||||
return 'module-property';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.TypeAlias) {
|
||||
return 'type-alias';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.FunctionScopedVariable) {
|
||||
return 'var';
|
||||
}
|
||||
if(symbol.flags & ts.SymbolFlags.BlockScopedVariable) {
|
||||
return getBlockScopedVariableDocType(symbol);
|
||||
}
|
||||
|
||||
log.warn('getExportDocType(): Unknown symbol type', {
|
||||
symbolName: symbol.name,
|
||||
symbolType: symbol.flags,
|
||||
symbolTarget: symbol.target,
|
||||
file: ts.getSourceFileOfNode(symbol.declarations[0]).fileName
|
||||
});
|
||||
return 'unknown';
|
||||
};
|
||||
|
||||
function getBlockScopedVariableDocType(symbol) {
|
||||
|
||||
var node = symbol.valueDeclaration;
|
||||
while(node) {
|
||||
if ( node.flags & 0x2000 /* const */) {
|
||||
return 'const';
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return 'let';
|
||||
}
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user