Compare commits
1 Commits
2.0.0-beta
...
2.0.0-alph
Author | SHA1 | Date | |
---|---|---|---|
7374153db5 |
4
.bowerrc
4
.bowerrc
@ -1,3 +1,3 @@
|
||||
{
|
||||
"directory" : "bower_components"
|
||||
}
|
||||
"directory": "bower_components"
|
||||
}
|
9
.gitignore
vendored
9
.gitignore
vendored
@ -29,11 +29,8 @@ tmp
|
||||
pubspec.lock
|
||||
.c9
|
||||
.idea/
|
||||
.settings/
|
||||
*.swo
|
||||
modules/.settings
|
||||
.vscode
|
||||
modules/.vscode
|
||||
|
||||
# Don't check in secret files
|
||||
*secret.js
|
||||
@ -42,9 +39,3 @@ modules/.vscode
|
||||
npm-debug.log
|
||||
|
||||
/docs/bower_components/
|
||||
|
||||
# build-analytics
|
||||
.build-analytics
|
||||
|
||||
# built dart payload tests
|
||||
/modules_dart/payload/**/build
|
||||
|
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
|
||||
}
|
||||
}
|
86
.travis.yml
86
.travis.yml
@ -1,7 +1,7 @@
|
||||
language: node_js
|
||||
sudo: false
|
||||
node_js:
|
||||
- '4.2.1'
|
||||
- '0.12'
|
||||
|
||||
branches:
|
||||
except:
|
||||
@ -19,11 +19,7 @@ env:
|
||||
- LOGS_DIR=/tmp/angular-build/logs
|
||||
- SAUCE_USERNAME=angular-ci
|
||||
- SAUCE_ACCESS_KEY=9b988f434ff8-fbca-8aa4-4ae3-35442987
|
||||
- BROWSER_STACK_USERNAME=angularteam1
|
||||
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
|
||||
- ARCH=linux-x64
|
||||
- DART_DEV_VERSION=latest
|
||||
- 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
|
||||
@ -34,70 +30,51 @@ env:
|
||||
# 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.
|
||||
- MODE=dart DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack_required DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=browserstack_optional 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=build_only DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
- MODE=lint DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION
|
||||
- MODE=payload DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
|
||||
# Order: slowest build on top, so that we don't hog VMs while waiting for others to complete.
|
||||
- MODE=dart DART_CHANNEL=stable
|
||||
- MODE=dart DART_CHANNEL=dev
|
||||
- MODE=saucelabs DART_CHANNEL=dev
|
||||
- MODE=dart_experimental DART_CHANNEL=dev
|
||||
- MODE=js DART_CHANNEL=dev
|
||||
- MODE=router DART_CHANNEL=dev
|
||||
- MODE=lint DART_CHANNEL=dev
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- env: "MODE=saucelabs_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=browserstack_optional DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=dart_experimental DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
# TODO(alxhub): remove when dartdoc #1039 is in dev channel
|
||||
- env: "MODE=dart DART_CHANNEL=dev DART_VERSION=$DART_DEV_VERSION"
|
||||
- env: "MODE=saucelabs DART_CHANNEL=dev"
|
||||
- env: "MODE=dart_experimental DART_CHANNEL=dev"
|
||||
|
||||
addons:
|
||||
firefox: "38.0"
|
||||
|
||||
before_install:
|
||||
- node tools/analytics/build-analytics start ci job
|
||||
- node tools/analytics/build-analytics start ci 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}
|
||||
- ./scripts/ci/install_dart.sh ${DART_CHANNEL} ${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'
|
||||
- node tools/analytics/build-analytics success ci before_install
|
||||
|
||||
install:
|
||||
- node tools/analytics/build-analytics start ci install
|
||||
# Update npm
|
||||
- npm install -g npm@2.9.1
|
||||
- npm --version
|
||||
# Check the size of caches
|
||||
- du -sh ./node_modules || true
|
||||
# Install npm dependecies
|
||||
- npm install
|
||||
- node tools/analytics/build-analytics success ci install
|
||||
|
||||
before_script:
|
||||
- node tools/analytics/build-analytics start ci before_script
|
||||
- mkdir -p $LOGS_DIR
|
||||
- ./scripts/ci/presubmit-queue-setup.sh
|
||||
- node tools/analytics/build-analytics success ci before_script
|
||||
|
||||
script:
|
||||
- node tools/analytics/build-analytics start ci script
|
||||
- ./scripts/ci/build_and_test.sh ${MODE}
|
||||
- node tools/analytics/build-analytics success ci script
|
||||
|
||||
after_script:
|
||||
- node tools/analytics/build-analytics start ci after_script
|
||||
- ./scripts/ci/print-logs.sh
|
||||
- ./scripts/ci/after-script.sh
|
||||
- ./scripts/publish/publish-build-artifacts.sh
|
||||
- node tools/analytics/build-analytics success ci after_script
|
||||
- if [[ $TRAVIS_TEST_RESULT -eq 0 ]]; then node tools/analytics/build-analytics success ci job; else node tools/analytics/build-analytics error ci job; fi
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
@ -111,3 +88,36 @@ notifications:
|
||||
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"
|
||||
|
1306
CHANGELOG.md
1306
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)
|
||||
|
@ -48,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:
|
||||
|
||||
@ -179,9 +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, CI configuration or external dependencies (example scopes: gulp, broccoli, npm)
|
||||
* **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
|
||||
|
76
DEVELOPER.md
76
DEVELOPER.md
@ -7,7 +7,6 @@ JS and Dart versions. It also explains the basic mechanics of using `git`, `node
|
||||
* [Getting the Sources](#getting-the-sources)
|
||||
* [Environment Variable Setup](#environment-variable-setup)
|
||||
* [Installing NPM Modules and Dart Packages](#installing-npm-modules-and-dart-packages)
|
||||
* [Build commands](#build-commands)
|
||||
* [Running Tests Locally](#running-tests-locally)
|
||||
* [Formatting](#clang-format)
|
||||
* [Project Information](#project-information)
|
||||
@ -23,23 +22,21 @@ 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
|
||||
* [Dart](https://www.dartlang.org) (version ` >=1.10.0-dev.1.10 <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).`
|
||||
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).
|
||||
|
||||
* [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 `>=4.2.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.7 <3.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
* [Node.js](http://nodejs.org), (version `>=0.12.0 <0.13.0`) 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.0 <3.0`), which comes with Node. Depending on your system, you can install Node either from
|
||||
source or as a pre-packaged bundle.
|
||||
|
||||
* [Chrome Canary](https://www.google.com/chrome/browser/canary.html), a version of Chrome with
|
||||
@ -96,14 +93,6 @@ export DART_SDK="$DART_EDITOR_DIR/dart-sdk"
|
||||
PATH+=":$DART_SDK/bin"
|
||||
```
|
||||
|
||||
And specify where the pub’s dependencies are downloaded. By default, this directory is located under .pub_cache
|
||||
in your home directory (on Mac and Linux), or in AppData\Roaming\Pub\Cache (on Windows).
|
||||
|
||||
```shell
|
||||
# PUB_CACHE: location of pub dependencies
|
||||
export PUB_CACHE="/Users/<user>/.pub-cache"
|
||||
```
|
||||
|
||||
## Installing NPM Modules and Dart Packages
|
||||
|
||||
Next, install the JavaScript modules and Dart packages needed to build and test Angular:
|
||||
@ -146,6 +135,12 @@ You can selectively build either the JS or Dart versions as follows:
|
||||
* `$(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
|
||||
$(npm bin)/gulp docs/typings
|
||||
```
|
||||
|
||||
To clean out the `dist` folder, run:
|
||||
|
||||
```shell
|
||||
@ -190,27 +185,6 @@ 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.
|
||||
|
||||
### Unit tests with Sauce Labs or Browser Stack
|
||||
|
||||
First, in a terminal, create a tunnel with [Sauce Connect](https://docs.saucelabs.com/reference/sauce-connect/) or [Browser Stack Local](https://www.browserstack.com/local-testing#command-line), and valid credentials.
|
||||
|
||||
Then, in another terminal:
|
||||
- Define the credentials as environment variables, e.g.:
|
||||
```
|
||||
export SAUCE_USERNAME='my_user'; export SAUCE_ACCESS_KEY='my_key';
|
||||
export BROWSER_STACK_USERNAME='my_user'; export BROWSER_STACK_ACCESS_KEY='my_key';
|
||||
```
|
||||
- Then run `gulp test.unit.js.(saucelabs|browserstack) --browsers=option1,option2,..,optionN`
|
||||
The options are any mix of browsers and aliases which are defined in the [browser-providers.conf.js](https://github.com/angular/angular/blob/master/browser-providers.conf.js) file.
|
||||
They are case insensitive, and the `SL_` or `BS_` prefix must not be added for browsers.
|
||||
|
||||
Some examples of commands:
|
||||
```
|
||||
gulp test.unit.js.saucelabs --browsers=Safari8,ie11 //run in Sauce Labs with Safari 8 and IE11
|
||||
gulp test.unit.js.browserstack --browsers=Safari,IE //run in Browser Stack with Safari 7, Safari 8, Safari 9, IE 9, IE 10 and IE 11
|
||||
gulp test.unit.js.saucelabs --browsers=IOS,safari8,android5.1 //run in Sauce Labs with iOS 7, iOS 8, iOs 9, Safari 8 and Android 5.1
|
||||
```
|
||||
|
||||
### E2E tests
|
||||
|
||||
1. `$(npm bin)/gulp build.js.cjs` (builds benchpress and tests into `dist/js/cjs` folder).
|
||||
@ -249,7 +223,12 @@ Your life will be easier if you include the formatter in your standard workflow.
|
||||
likely forget to check the formatting, and waste time waiting for a build on Travis that fails due
|
||||
to some whitespace difference.
|
||||
|
||||
* Use `$(npm bin)/clang-format -i [file name]` to format a file (or multiple).
|
||||
* 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
|
||||
@ -271,27 +250,12 @@ to some whitespace difference.
|
||||
- Synchronize files after execution: checked
|
||||
- Open console: not checked
|
||||
- Show in: Editor menu
|
||||
- Program: `$ProjectFileDir$/node_modules/.bin/clang-format`
|
||||
- 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
|
||||
$(npm bin)/gulp docs/angular.io
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
### Folder structure
|
||||
|
14
README.md
14
README.md
@ -4,7 +4,6 @@
|
||||
[](http://issuestats.com/github/angular/angular)
|
||||
[](http://badge.fury.io/js/angular2)
|
||||
[](https://npmjs.org/package/angular2)
|
||||
[](https://saucelabs.com/u/angular2-ci)
|
||||
|
||||
Angular
|
||||
=========
|
||||
@ -12,12 +11,20 @@ Angular
|
||||
Angular is a development platform for building mobile and desktop web applications. This is the
|
||||
repository for [Angular 2][ng2], both the JavaScript (JS) and [Dart][dart] versions.
|
||||
|
||||
Angular 2 is currently in **Beta**.
|
||||
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?
|
||||
|
||||
@ -28,7 +35,8 @@ guidelines for [contributing][contributing] and then check out one of our issues
|
||||
[contributing]: http://github.com/angular/angular/blob/master/CONTRIBUTING.md
|
||||
[dart]: http://www.dartlang.org
|
||||
[dartium]: http://www.dartlang.org/tools/dartium
|
||||
[quickstart]: https://angular.io/docs/ts/latest/quickstart.html
|
||||
[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
|
||||
|
2
TOOLS.md
2
TOOLS.md
@ -1,4 +1,4 @@
|
||||
# Developer Tools for Angular 2
|
||||
|
||||
- [JavaScript](TOOLS_JS.md)
|
||||
- JavaScript (TBD)
|
||||
- [Dart](TOOLS_DART.md)
|
||||
|
299
TOOLS_DART.md
299
TOOLS_DART.md
@ -1,75 +1,22 @@
|
||||
# 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/platform/browser.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:
|
||||
|
||||
```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/. -->
|
||||
|
||||
Here you will find a collection of tools and tips for keeping your application
|
||||
perform well and contain fewer bugs.
|
||||
|
||||
## Code size
|
||||
|
||||
Code must be downloaded, parsed, and executed. Too much code can lead to
|
||||
Code needs to be downloaded, parsed and executed. Too much code could 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.
|
||||
The tools below will help you identify contributors to code size and keep them
|
||||
in check.
|
||||
|
||||
### 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
|
||||
|
||||
#### Use --dump-info
|
||||
|
||||
The `--dump-info` option of `dart2js` outputs information about what happened
|
||||
during compilation. You can specify `--dump-info` in `pubspec.yaml`:
|
||||
`dart2js` has an option `--dump-info` that outputs information about what
|
||||
happened during compilation. Enable this option in your transformer options
|
||||
like this:
|
||||
|
||||
```yaml
|
||||
transformers:
|
||||
@ -79,83 +26,35 @@ transformers:
|
||||
- --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/).
|
||||
Use the [visualizer](https://github.com/dart-lang/dump-info-visualizer) to
|
||||
analyze the output or any of the command-line tools documented
|
||||
[here](http://dart-lang.github.io/dart2js_info/doc/api/index.html).
|
||||
|
||||
#### Use ng2soyc.dart
|
||||
#### 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
|
||||
library. It also assumes your library names follow
|
||||
"package.library.sub-library..." convention and gives code size breakdown at
|
||||
each level. To reduce noise in the output (for very large apps) it also provides
|
||||
an option to hide libraries that are too small, so you can focus on the biggest
|
||||
contributors.
|
||||
|
||||
#### Find unused reflection data
|
||||
#### Track unused reflection data
|
||||
|
||||
Your app might have types that are annotated with `@Component` or `@Injectable`
|
||||
but never used.
|
||||
To find these unused types, use `reflector.trackUsage()` and then,
|
||||
after exercising your app, `reflector.listUnusedKeys()`.
|
||||
For example:
|
||||
|
||||
```
|
||||
import 'package:angular2/src/core/reflection/reflection.dart';
|
||||
...
|
||||
main() async {
|
||||
reflector.trackUsage();
|
||||
await bootstrap(AppComponent);
|
||||
print('Unused keys: ${reflector.listUnusedKeys()}');
|
||||
}
|
||||
```
|
||||
|
||||
When you run that code (in Dartium or another browser),
|
||||
you'll see a list of types that Angular _can_ inject but hasn't needed to.
|
||||
Consider removing those types or their `@Component`/`@Injectable` annotation
|
||||
to decrease your app's code size.
|
||||
|
||||
Three conditions must be true for `listUnusedKeys()` to return helpful data:
|
||||
|
||||
1. The angular2 transformer must run on the app.
|
||||
2. If you're running a JavaScript version of the app,
|
||||
the app must not be minified, so that the names are readable.
|
||||
3. You must exercise your app in as many ways as possible
|
||||
before calling `listUnusedKeys()`.
|
||||
Otherwise, you might get false positives:
|
||||
keys that haven't been used only because you didn't exercise
|
||||
the relevant feature of the app.
|
||||
|
||||
To run the angular2 transformer, first specify it in `pubspec.yaml`:
|
||||
|
||||
```
|
||||
name: hello_world
|
||||
...
|
||||
transformers:
|
||||
- angular2:
|
||||
entry_points: web/main.dart
|
||||
```
|
||||
|
||||
Then use pub to run the transformer. If you use `pub serve`,
|
||||
it provides both Dart and unminified (by default) JavaScript versions.
|
||||
If you want to serve actual files, then use `pub build` in debug mode
|
||||
to generate Dart and unminified JavaScript files:
|
||||
`pub build --mode=debug`.
|
||||
|
||||
The `reflector.trackUsage()` method makes Angular track the reflection
|
||||
information used by the app. Reflection information (`ReflectionInfo`) is a data
|
||||
structure that stores information that Angular uses for locating DI factories
|
||||
and for generating change detectors and other code related to a
|
||||
given type.
|
||||
Call `reflector.trackUsage()` to cause it 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 was 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
|
||||
When running in Dartium (or in 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
|
||||
[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.
|
||||
|
||||
@ -164,16 +63,10 @@ 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.
|
||||
therefore do not 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
|
||||
@ -206,19 +99,19 @@ example:
|
||||
/// This function decides which serialization format to use
|
||||
void setupSerializers() {
|
||||
if (server.doYouSupportProtocolBuffers()) {
|
||||
useProtobufSerializers();
|
||||
useProtobufSerializaers();
|
||||
} else {
|
||||
useJsonSerializers();
|
||||
useJsonSerializaers();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
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.
|
||||
format it uses and dynamically chooses one or the other. `dart2js` could never
|
||||
tell whether the server responds with yes or no and so it must retain both
|
||||
kinds of serializers. However, you, as the developer of the application, may
|
||||
know in advance that your server supports protocol buffers and so you could
|
||||
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.
|
||||
|
||||
@ -240,7 +133,7 @@ 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`.
|
||||
These options are specified in `pubspec.yaml`.
|
||||
|
||||
Example:
|
||||
|
||||
@ -252,125 +145,3 @@ transformers:
|
||||
- --trust-type-annotations
|
||||
- --trust-primitives
|
||||
```
|
||||
|
||||
## Performance
|
||||
|
||||
### Change detection profiler
|
||||
|
||||
If your application is janky (it misses frames) or is slow according to other
|
||||
metrics, you need to find out why. This tool helps by measuring the average
|
||||
speed of _change detection_, a phase in Angular's
|
||||
lifecycle that detects changes in values that are bound to the UI.
|
||||
Janky UI updates can result from slowness either in _computing_ the changes or
|
||||
in _applying_ those changes to the UI.
|
||||
|
||||
For your app to be performant, the process of _computing_ changes must be very
|
||||
fast—preferably **under 3 milliseconds**.
|
||||
Fast change computation leaves room for
|
||||
the application logic, UI updates, and browser rendering pipeline
|
||||
to fit within a 16 ms frame (assuming a target frame rate of 60 FPS).
|
||||
|
||||
The 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
|
||||
(in milliseconds) to perform a single cycle of change detection and
|
||||
prints that 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
|
||||
|
||||
Before running the profiler, enable the debugging tools
|
||||
and put the app into the state you want to measure:
|
||||
|
||||
1. If you haven't already done so,
|
||||
[enable the debugging tools](#enabling-the-debugging-tools).
|
||||
2. Navigate the app to a screen whose performance you want to profile.
|
||||
3. Make sure the screen is in a state that you want to measure.
|
||||
For example, you might want to profile the screen several times,
|
||||
with different amounts and kinds of data.
|
||||
|
||||
To run the profiler, enter the following in the dev console:
|
||||
|
||||
```javascript
|
||||
ng.profiler.timeChangeDetection();
|
||||
```
|
||||
|
||||
The results are visible in 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.
|
||||
|
||||
#### 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
140
TOOLS_JS.md
@ -1,140 +0,0 @@
|
||||
# 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 {enableDebugTools} from 'angular2/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
|
||||
@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,6 +1,6 @@
|
||||
{
|
||||
"name": "angular2",
|
||||
"dependencies": {
|
||||
"polymer": "Polymer/polymer"
|
||||
"polymer": "dart-lang/polymer_js#0.8.0-preview"
|
||||
}
|
||||
}
|
||||
|
@ -1,317 +0,0 @@
|
||||
// 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}},
|
||||
'ChromeBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'FirefoxBeta': { unitTest: {target: 'SL', required: true}, e2e: {target: null, required: true}},
|
||||
'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: 'SL', required: true}, 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}},
|
||||
'iOS7': { unitTest: {target: 'BS', required: true}, e2e: {target: null, required: true}},
|
||||
'iOS8': { unitTest: {target: 'BS', required: false}, e2e: {target: null, required: true}},
|
||||
// TODO(mlaval): iOS9 deactivated as not reliable, reactivate after https://github.com/angular/angular/issues/5408
|
||||
'iOS9': { unitTest: {target: null, 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: '46'
|
||||
},
|
||||
'SL_CHROMEBETA': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: 'beta'
|
||||
},
|
||||
'SL_CHROMEDEV': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'chrome',
|
||||
version: 'dev'
|
||||
},
|
||||
'SL_FIREFOX': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'firefox',
|
||||
version: '42'
|
||||
},
|
||||
'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'
|
||||
},
|
||||
'SL_SAFARI8': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.10',
|
||||
version: '8'
|
||||
},
|
||||
'SL_SAFARI9': {
|
||||
base: 'SauceLabs',
|
||||
browserName: 'safari',
|
||||
platform: 'OS X 10.11',
|
||||
version: '9.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.1'
|
||||
},
|
||||
'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: '20.10240'
|
||||
},
|
||||
'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_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.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'],
|
||||
'MOBILE': ['SL_ANDROID4.1', 'SL_ANDROID4.2', 'SL_ANDROID4.3', 'SL_ANDROID4.4', 'SL_ANDROID5', 'SL_IOS7', 'SL_IOS8', 'SL_IOS9'],
|
||||
'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'],
|
||||
'SAFARI': ['SL_SAFARI7', 'SL_SAFARI8', 'SL_SAFARI9'],
|
||||
'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'],
|
||||
'MOBILE': ['BS_ANDROID4.3', 'BS_ANDROID4.4', 'BS_IOS7', 'BS_IOS8', 'BS_IOS9', 'BS_WINDOWSPHONE'],
|
||||
'ANDROID': ['BS_ANDROID4.3', 'BS_ANDROID4.4'],
|
||||
'IE': ['BS_IE9', 'BS_IE10', 'BS_IE11'],
|
||||
'IOS': ['BS_IOS7', 'BS_IOS8', 'BS_IOS9'],
|
||||
'SAFARI': ['BS_SAFARI7', 'BS_SAFARI8', 'BS_SAFARI9'],
|
||||
'CI_REQUIRED': buildConfiguration('unitTest', 'BS', true),
|
||||
'CI_OPTIONAL': buildConfiguration('unitTest', 'BS', false)
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
customLaunchers: customLaunchers,
|
||||
sauceAliases: sauceAliases,
|
||||
browserstackAliases: browserstackAliases
|
||||
}
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
process.env.SAUCE_ACCESS_KEY = process.env.SAUCE_ACCESS_KEY.split('').reverse().join('');
|
||||
process.env.BROWSER_STACK_ACCESS_KEY = process.env.BROWSER_STACK_ACCESS_KEY.split('').reverse().join('');
|
||||
}
|
||||
|
||||
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) => {
|
||||
return target + '_' + item.toUpperCase();
|
||||
});
|
||||
}
|
64
docs/angular.io-package/index.js
Normal file
64
docs/angular.io-package/index.js
Normal file
@ -0,0 +1,64 @@
|
||||
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'))
|
||||
|
||||
// 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(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')]));
|
||||
});
|
||||
|
||||
|
@ -0,0 +1,77 @@
|
||||
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(/\r?\n|\r/g,"")
|
||||
}];
|
||||
|
||||
// GET DATA FOR EACH PAGE (CLASS, VARS, FUNCTIONS)
|
||||
var modulePageInfo = _.map(doc.exports, function(exportDoc) {
|
||||
return {
|
||||
name: exportDoc.name + '-' + exportDoc.docType,
|
||||
title: exportDoc.name,
|
||||
varType: exportDoc.symbolTypeName && titleCase(exportDoc.symbolTypeName)
|
||||
};
|
||||
});
|
||||
|
||||
//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);
|
||||
}
|
||||
};
|
||||
};
|
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(encodeCodeBlock) {
|
||||
return {
|
||||
name: 'trimBlankLines',
|
||||
process: function(str) {
|
||||
var lines = str.split(/\r?\n/);
|
||||
while(lines[0] === '') {
|
||||
lines.shift();
|
||||
}
|
||||
return lines.join('\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.moduleDoc.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 $}
|
||||
|
||||
{% 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 $}{% 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 %}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
{%- 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 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"
|
||||
}
|
||||
}
|
118
docs/docs-package/index.js
Normal file
118
docs/docs-package/index.js
Normal file
@ -0,0 +1,118 @@
|
||||
require('../../tools/transpiler/index.js').init();
|
||||
|
||||
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/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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
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;
|
||||
};
|
||||
};
|
29
docs/public-docs-package/index.js
Normal file
29
docs/public-docs-package/index.js
Normal file
@ -0,0 +1,29 @@
|
||||
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/metadata.ts',
|
||||
'angular2/change_detection.ts',
|
||||
'angular2/core.ts',
|
||||
'angular2/di.ts',
|
||||
'angular2/directives.ts',
|
||||
'angular2/http.ts',
|
||||
'angular2/forms.ts',
|
||||
'angular2/router.ts',
|
||||
'angular2/test.ts',
|
||||
'angular2/pipes.ts'
|
||||
];
|
||||
readTypeScriptModules.hidePrivateMembers = true;
|
||||
})
|
||||
|
||||
.config(function(getLinkInfo) {
|
||||
getLinkInfo.useFirstAmbiguousLink = false;
|
||||
})
|
||||
|
||||
// Configure file writing
|
||||
.config(function(writeFilesProcessor) {
|
||||
writeFilesProcessor.outputFolder = 'dist/public_docs';
|
||||
});
|
112
docs/typescript-definition-package/index.js
Normal file
112
docs/typescript-definition-package/index.js
Normal file
@ -0,0 +1,112 @@
|
||||
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'
|
||||
];
|
||||
readTypeScriptModules.basePath = path.resolve(path.resolve(__dirname, '../../modules'));
|
||||
|
||||
createTypeDefinitionFile.typeDefinitions = [
|
||||
{
|
||||
id: 'angular2/angular2',
|
||||
references: ['../es6-promise/es6-promise.d.ts', '../rx/rx.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'},
|
||||
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'},
|
||||
modules: {'angular2/http': {namespace: 'ngHttp', id: 'angular2/http'}}
|
||||
}
|
||||
];
|
||||
})
|
||||
|
||||
|
||||
.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 {}; });
|
||||
|
||||
};
|
40
docs/typescript-definition-package/processors/code_gen.js
Normal file
40
docs/typescript-definition-package/processors/code_gen.js
Normal file
@ -0,0 +1,40 @@
|
||||
module.exports = {
|
||||
|
||||
signature: function(remap) {
|
||||
return function(ast) {
|
||||
try {
|
||||
var text = [];
|
||||
if (ast.isStatic) text.push('static ');
|
||||
text.push(ast.name);
|
||||
if (ast.optional) text.push('?');
|
||||
if (ast.typeParameters) {
|
||||
text.push('<');
|
||||
text.push(ast.typeParameters.join(', '));
|
||||
text.push('>');
|
||||
}
|
||||
if (ast.parameters) {
|
||||
text.push('(');
|
||||
text.push(ast.parameters.join(', '));
|
||||
text.push(')');
|
||||
}
|
||||
if (ast.returnType) {
|
||||
text.push(': ', ast.returnType);
|
||||
} else if (ast.parameters) {
|
||||
text.push(': void');
|
||||
} else {
|
||||
text.push(': any');
|
||||
}
|
||||
var string = text.join('');
|
||||
for (var key in remap) {
|
||||
if (remap.hasOwnProperty(key)) {
|
||||
string = string.replace(new RegExp('\\b' + key + '\\b', 'gm'), remap[key]);
|
||||
}
|
||||
}
|
||||
return string;
|
||||
} catch (e) {
|
||||
console.log(e.toString(), e.stack);
|
||||
return 'ERROR: ' + e.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
@ -0,0 +1,94 @@
|
||||
var _ = require('lodash');
|
||||
var path = require('canonical-path');
|
||||
var codeGen = require('./code_gen.js');
|
||||
|
||||
module.exports = function createTypeDefinitionFile(log) {
|
||||
|
||||
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
|
||||
};
|
||||
}),
|
||||
signature: codeGen.signature(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;
|
||||
}
|
||||
_.forEach(modDoc.doc.exports, 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');
|
||||
}
|
||||
|
||||
// Add the `declare var SomeClass extends InjectableReference` construct
|
||||
modDoc.doc.exports.push({
|
||||
docType: 'var',
|
||||
name: exportDoc.name,
|
||||
id: exportDoc.id,
|
||||
heritage: ': InjectableReference'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
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,18 @@
|
||||
{% extends '../type-definition.template.html' %}
|
||||
{% block staticDeclarations %}
|
||||
|
||||
interface Map<K,V> {}
|
||||
interface StringMap<K,V> extends 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,80 @@
|
||||
|
||||
{%- 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 -%}
|
||||
|
||||
|
||||
{%- macro memberInfo(signature, member) -%}
|
||||
{$ commentBlock(member, 5) $}
|
||||
{$ signature(member) $};
|
||||
{%- 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 -%}
|
||||
{%- if export.content -%}
|
||||
{$ commentBlock(export, 3) $}
|
||||
{%- endif %}
|
||||
{$ export.docType $} {$ export.name $}{$ export.typeParams $}{%- if export.heritage == ' extends Directive' %} extends DirectiveAnnotation{% else %}{$ export.heritage $}{% endif %}
|
||||
{%- if export.docType == 'class' or export.docType == 'interface' %} {
|
||||
{%- if export.newMember %}
|
||||
{$ memberInfo(doc.signature, export.newMember) $}
|
||||
{% endif %}
|
||||
{%- if export.callMember %}
|
||||
{$ memberInfo(doc.signature, export.callMember) $}
|
||||
{% endif -%}
|
||||
{%- for static in export.statics %}
|
||||
{$ memberInfo(doc.signature, static) $}
|
||||
{%- endfor -%}
|
||||
{%- for member in export.members %}
|
||||
{$ memberInfo(doc.signature, member) $}
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
{%- elif export.docType == 'enum' %} {
|
||||
{%- for member in export.members %}
|
||||
{$ commentBlock(member, 5) $}
|
||||
{$ member.name $}{% if not loop.last %},
|
||||
{%- endif -%}
|
||||
{%- endfor %}
|
||||
}
|
||||
|
||||
{%- else -%}
|
||||
{% if export.parameters %}({% for param in export.parameters %}{$ param $}{% if not loop.last %}, {% endif %}{% endfor %}){%- endif %}
|
||||
{%- if export.returnType %} : {$ export.returnType $} {% endif -%}
|
||||
;
|
||||
{%- endif %}
|
||||
{% 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 @@
|
||||
require('../../tools/transpiler/index.js').init();
|
||||
|
||||
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('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() {}
|
||||
}
|
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;
|
389
docs/typescript-package/processors/readTypeScriptModules.js
Normal file
389
docs/typescript-package/processors/readTypeScriptModules.js
Normal file
@ -0,0 +1,389 @@
|
||||
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 = '';
|
||||
|
||||
exportSymbol.declarations.forEach(function(decl) {
|
||||
var sourceFile = ts.getSourceFileOfNode(decl);
|
||||
|
||||
if (decl.typeParameters) {
|
||||
typeParamString = '<' + getText(sourceFile, decl.typeParameters) + '>';
|
||||
}
|
||||
|
||||
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(exportSymbol.flags & ts.SymbolFlags.Function) {
|
||||
exportDoc.parameters = getParameters(typeChecker, exportSymbol);
|
||||
}
|
||||
if(exportSymbol.flags & ts.SymbolFlags.Value) {
|
||||
exportDoc.returnType = getReturnType(typeChecker, exportSymbol);
|
||||
}
|
||||
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 Rx
|
||||
if (text.match(/^\s*Rx\./)) 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;
|
||||
}
|
115
docs/typescript-package/processors/readTypeScriptModules.spec.js
Normal file
115
docs/typescript-package/processors/readTypeScriptModules.spec.js
Normal file
@ -0,0 +1,115 @@
|
||||
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('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; });
|
||||
}
|
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,62 @@
|
||||
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;
|
||||
}
|
||||
};
|
||||
};
|
||||
};
|
@ -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/bin/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';
|
||||
}
|
||||
};
|
20
docs/typescript-package/services/tsParser/getFileInfo.js
Normal file
20
docs/typescript-package/services/tsParser/getFileInfo.js
Normal file
@ -0,0 +1,20 @@
|
||||
var path = require('canonical-path');
|
||||
var ts = require('typescript');
|
||||
|
||||
module.exports = function getFileInfo(log) {
|
||||
|
||||
return function (symbol, basePath) {
|
||||
var fileName = ts.getSourceFileOfNode(symbol.declarations[0]).fileName;
|
||||
|
||||
var file = path.resolve(basePath, fileName);
|
||||
var fileInfo = {
|
||||
filePath: file,
|
||||
baseName: path.basename(file, path.extname(file)),
|
||||
extension: path.extname(file).replace(/^\./, ''),
|
||||
basePath: basePath,
|
||||
relativePath: fileName,
|
||||
projectRelativePath: fileName
|
||||
};
|
||||
return fileInfo;
|
||||
};
|
||||
};
|
74
docs/typescript-package/services/tsParser/index.js
Normal file
74
docs/typescript-package/services/tsParser/index.js
Normal file
@ -0,0 +1,74 @@
|
||||
var ts = require('typescript');
|
||||
var path = require('canonical-path');
|
||||
|
||||
module.exports = function tsParser(createCompilerHost, log) {
|
||||
|
||||
return {
|
||||
|
||||
// These are the extension that we should consider when trying to load a module
|
||||
// During migration from Traceur, there is a mix of `.ts`, `.es6` and `.js` (atScript)
|
||||
// files in the project and the TypeScript compiler only looks for `.ts` files when trying
|
||||
// to load imports.
|
||||
extensions: ['.ts', '.js'],
|
||||
|
||||
// The options for the TS compiler
|
||||
options: {
|
||||
allowNonTsExtensions: true,
|
||||
charset: 'utf8'
|
||||
},
|
||||
|
||||
parse: function(fileNames, baseDir) {
|
||||
|
||||
// "Compile" a program from the given module filenames, to get hold of a
|
||||
// typeChecker that can be used to interrogate the modules, exports and so on.
|
||||
var host = createCompilerHost(this.options, baseDir, this.extensions);
|
||||
var program = ts.createProgram(fileNames, this.options, host);
|
||||
var typeChecker = program.getTypeChecker();
|
||||
|
||||
// Create an array of module symbols for each file we were given
|
||||
var moduleSymbols = [];
|
||||
fileNames.forEach(function(fileName) {
|
||||
var sourceFile = program.getSourceFile(fileName);
|
||||
|
||||
if (!sourceFile) {
|
||||
throw new Error('Invalid source file: ' + fileName);
|
||||
} else if (!sourceFile.symbol) {
|
||||
// Some files contain only a comment and no actual module code
|
||||
log.warn('No module code found in ' + fileName);
|
||||
} else {
|
||||
moduleSymbols.push(sourceFile.symbol);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
moduleSymbols.forEach(function(tsModule) {
|
||||
|
||||
// The type checker has a nice helper function that returns an array of Symbols
|
||||
// representing the exports for a given module
|
||||
tsModule.exportArray = typeChecker.getExportsOfModule(tsModule);
|
||||
|
||||
// Although 'star' imports (e.g. `export * from 'some/module';) get resolved automatically
|
||||
// by the compiler/binder, it seems that explicit imports (e.g. `export {SomeClass} from 'some/module'`)
|
||||
// do not so we have to do a little work.
|
||||
tsModule.exportArray.forEach(function(moduleExport) {
|
||||
if (moduleExport.flags & ts.SymbolFlags.Alias) {
|
||||
// To maintain the alias information (particularly the alias name)
|
||||
// we just attach the original "resolved" symbol to the alias symbol
|
||||
moduleExport.resolvedSymbol = typeChecker.getAliasedSymbol(moduleExport);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
moduleSymbols.typeChecker = typeChecker;
|
||||
|
||||
return {
|
||||
moduleSymbols: moduleSymbols,
|
||||
typeChecker: typeChecker,
|
||||
program: program,
|
||||
host: host
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
};
|
21
docs/typescript-package/services/tsParser/index.spec.js
Normal file
21
docs/typescript-package/services/tsParser/index.spec.js
Normal file
@ -0,0 +1,21 @@
|
||||
var mockPackage = require('../../mocks/mockPackage');
|
||||
var Dgeni = require('dgeni');
|
||||
var path = require('canonical-path');
|
||||
|
||||
describe('tsParser', function() {
|
||||
var dgeni, injector, parser;
|
||||
|
||||
beforeEach(function() {
|
||||
dgeni = new Dgeni([mockPackage()]);
|
||||
injector = dgeni.configureInjector();
|
||||
parser = injector.get('tsParser');
|
||||
});
|
||||
|
||||
it("should parse a TS file", function() {
|
||||
var parseInfo = parser.parse(['testSrc.ts'], path.resolve(__dirname, '../../mocks/tsParser'));
|
||||
var tsModules = parseInfo.moduleSymbols;
|
||||
expect(tsModules.length).toEqual(1);
|
||||
expect(tsModules[0].exportArray.length).toEqual(3);
|
||||
expect(tsModules[0].exportArray.map(function(i) { return i.name; })).toEqual(['MyClass', 'myFn', 'x']);
|
||||
});
|
||||
});
|
1650
gulpfile.js
1650
gulpfile.js
File diff suppressed because it is too large
Load Diff
@ -1,86 +0,0 @@
|
||||
// This module provides a customFileHandler for karma
|
||||
// that serves files with urls like /packages_<timestamp>/...
|
||||
// with maximum cache.
|
||||
// We are using these urls when we spawn isolates
|
||||
// so that the isolates don't reload files every time.
|
||||
|
||||
var common = require('karma/lib/middleware/common');
|
||||
var fs = require('fs');
|
||||
|
||||
var DART_EVAL_PATH_RE = /.*\/packages_\d+\/(.*)$/;
|
||||
|
||||
module.exports = createFactory;
|
||||
|
||||
function createFactory(proxyPaths) {
|
||||
return {
|
||||
'framework:dart-evalcache': ['factory', dartEvalCacheFactory]
|
||||
};
|
||||
|
||||
function dartEvalCacheFactory(emitter, logger, customFileHandlers) {
|
||||
var filesPromise = new common.PromiseContainer();
|
||||
emitter.on('file_list_modified', function(files) {
|
||||
filesPromise.set(Promise.resolve(files));
|
||||
});
|
||||
|
||||
var serveFile = common.createServeFile(fs);
|
||||
var log = logger.create('dart-evalcache');
|
||||
|
||||
customFileHandlers.push({
|
||||
urlRegex: DART_EVAL_PATH_RE,
|
||||
handler: handler
|
||||
});
|
||||
|
||||
// See source_files handler
|
||||
function handler(request, response, fa, fb, basePath) {
|
||||
return filesPromise.then(function(files) {
|
||||
try {
|
||||
var requestedFilePath = mapUrlToFile(request.url, proxyPaths, basePath, log);
|
||||
// TODO(vojta): change served to be a map rather then an array
|
||||
var file = findByPath(files.served, requestedFilePath);
|
||||
if (file) {
|
||||
serveFile(file.contentPath || file.path, response, function() {
|
||||
common.setHeavyCacheHeaders(response);
|
||||
}, file.content);
|
||||
} else {
|
||||
response.writeHead(404);
|
||||
response.end('Not found');
|
||||
}
|
||||
} catch (e) {
|
||||
log.error(e.stack);
|
||||
response.writeHead(500);
|
||||
response.end('Error', e.stack);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function mapUrlToFile(url, proxyPaths, basePath, log) {
|
||||
var originalUrl = url;
|
||||
url = url.indexOf('?') > -1 ? url.substring(0, url.indexOf('?')) : url;
|
||||
var match = DART_EVAL_PATH_RE.exec(url);
|
||||
var packagePath = match[1];
|
||||
var result = null;
|
||||
var lastProxyFromLength = 0;
|
||||
Object.keys(proxyPaths).forEach(function(proxyFrom) {
|
||||
if (startsWith(packagePath, proxyFrom) && proxyFrom.length > lastProxyFromLength) {
|
||||
lastProxyFromLength = proxyFrom.length;
|
||||
result = proxyPaths[proxyFrom] + packagePath.substring(proxyFrom.length);
|
||||
}
|
||||
});
|
||||
return basePath + '/' + result;
|
||||
}
|
||||
|
||||
function startsWith(string, subString) {
|
||||
return string.length >= subString.length && string.slice(0, subString.length) === subString;
|
||||
}
|
||||
|
||||
function findByPath(files, path) {
|
||||
for (var i = 0; i < files.length; i++) {
|
||||
if (files[i].path === path) {
|
||||
return files[i];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@ -1,41 +1,11 @@
|
||||
var browserProvidersConf = require('./browser-providers.conf.js');
|
||||
|
||||
var packageSources = {
|
||||
// Dependencies installed with `pub install`.
|
||||
'unittest': 'packages/unittest',
|
||||
'guinness': 'packages/guinness',
|
||||
'matcher': 'packages/matcher',
|
||||
'stack_trace': 'packages/stack_trace',
|
||||
'collection': 'packages/collection',
|
||||
'path': 'packages/path',
|
||||
'observe': 'packages/observe',
|
||||
'quiver': 'packages/quiver',
|
||||
'intl': 'packages/intl',
|
||||
'smoke': 'packages/smoke',
|
||||
'logging': 'packages/logging',
|
||||
'utf': 'packages/utf',
|
||||
|
||||
// Local dependencies, transpiled from the source.
|
||||
'angular2': 'dist/dart/angular2/lib',
|
||||
'angular2/test/': 'dist/dart/angular2/test/',
|
||||
'http': 'dist/dart/http/lib',
|
||||
'angular2_material': 'dist/dart/angular2_material/lib',
|
||||
'benchpress': 'dist/dart/benchpress/lib',
|
||||
'examples': 'dist/dart/examples/lib'
|
||||
};
|
||||
|
||||
var proxyPaths = {};
|
||||
Object.keys(packageSources).map(function(packageName) {
|
||||
var filePath = packageSources[packageName];
|
||||
proxyPaths['/packages/'+packageName] = '/base/'+filePath;
|
||||
});
|
||||
var sauceConf = require('./sauce.conf');
|
||||
|
||||
// Karma configuration
|
||||
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
|
||||
module.exports = function(config) {
|
||||
config.set({
|
||||
|
||||
frameworks: ['dart-unittest', 'dart-evalcache'],
|
||||
frameworks: ['dart-unittest'],
|
||||
|
||||
files: [
|
||||
// Init and configure guiness.
|
||||
@ -65,18 +35,27 @@ module.exports = function(config) {
|
||||
},
|
||||
|
||||
// Map packages to the correct urls where Karma serves them.
|
||||
proxies: proxyPaths,
|
||||
proxies: {
|
||||
// Dependencies installed with `pub install`.
|
||||
'/packages/unittest': '/base/packages/unittest',
|
||||
'/packages/guinness': '/base/packages/guinness',
|
||||
'/packages/matcher': '/base/packages/matcher',
|
||||
'/packages/stack_trace': '/base/packages/stack_trace',
|
||||
'/packages/collection': '/base/packages/collection',
|
||||
'/packages/path': '/base/packages/path',
|
||||
|
||||
customLaunchers: browserProvidersConf.customLaunchers,
|
||||
// Local dependencies, transpiled from the source.
|
||||
'/packages/angular2/test/': '/base/dist/dart/angular2/test/',
|
||||
'/packages/angular2': '/base/dist/dart/angular2/lib',
|
||||
'/packages/http': '/base/dist/dart/http/lib',
|
||||
'/packages/angular2_material': '/base/dist/dart/angular2_material/lib',
|
||||
'/packages/benchpress': '/base/dist/dart/benchpress/lib',
|
||||
'/packages/examples': '/base/dist/dart/examples/lib'
|
||||
},
|
||||
|
||||
customLaunchers: sauceConf.customLaunchers,
|
||||
browsers: ['DartiumWithWebPlatform'],
|
||||
|
||||
port: 9877,
|
||||
|
||||
plugins: [
|
||||
require('karma-dart'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-sauce-launcher'),
|
||||
require('./karma-dart-evalcache')(packageSources)
|
||||
]
|
||||
port: 9877
|
||||
});
|
||||
};
|
||||
|
@ -1,5 +1,4 @@
|
||||
var browserProvidersConf = require('./browser-providers.conf.js');
|
||||
var internalAngularReporter = require('./tools/karma/reporter.js');
|
||||
var sauceConf = require('./sauce.conf');
|
||||
|
||||
// Karma configuration
|
||||
// Generated on Thu Sep 25 2014 11:52:02 GMT-0700 (PDT)
|
||||
@ -13,85 +12,55 @@ module.exports = function(config) {
|
||||
// Loaded through the System loader, in `test-main.js`.
|
||||
{pattern: 'dist/js/dev/es5/**', included: false, watched: false},
|
||||
|
||||
'node_modules/es6-shim/es6-shim.js',
|
||||
// include Angular v1 for upgrade module testing
|
||||
'node_modules/angular/angular.min.js',
|
||||
|
||||
// zone-microtask must be included first as it contains a Promise monkey patch
|
||||
'node_modules/zone.js/dist/zone-microtask.js',
|
||||
'node_modules/zone.js/dist/long-stack-trace-zone.js',
|
||||
'node_modules/zone.js/dist/jasmine-patch.js',
|
||||
|
||||
'node_modules/traceur/bin/traceur-runtime.js',
|
||||
// Including systemjs because it defines `__eval`, which produces correct stack traces.
|
||||
'modules/angular2/src/testing/shims_for_IE.js',
|
||||
'modules/angular2/src/test_lib/shims_for_IE.js',
|
||||
'node_modules/systemjs/dist/system.src.js',
|
||||
{pattern: 'node_modules/rxjs/**', included: false, watched: false, served: true},
|
||||
{pattern: 'node_modules/rx/dist/rx.js', included: false, watched: false, served: true},
|
||||
'node_modules/reflect-metadata/Reflect.js',
|
||||
'tools/build/file2modulename.js',
|
||||
'test-main.js',
|
||||
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false}
|
||||
{pattern: 'modules/**/test/**/static_assets/**', included: false, watched: false}
|
||||
],
|
||||
|
||||
exclude: ['dist/js/dev/es5/**/e2e_test/**', 'dist/js/dev/es5/angular2/examples/**', 'dist/angular1_router.js'],
|
||||
|
||||
customLaunchers: browserProvidersConf.customLaunchers,
|
||||
|
||||
plugins: [
|
||||
'karma-jasmine',
|
||||
'karma-browserstack-launcher',
|
||||
'karma-sauce-launcher',
|
||||
'karma-chrome-launcher',
|
||||
'karma-sourcemap-loader',
|
||||
'karma-dart',
|
||||
internalAngularReporter
|
||||
exclude: [
|
||||
'dist/js/dev/es5/**/e2e_test/**',
|
||||
'dist/angular1_router.js'
|
||||
],
|
||||
|
||||
preprocessors: {
|
||||
'**/*.js': ['sourcemap']
|
||||
},
|
||||
customLaunchers: sauceConf.customLaunchers,
|
||||
|
||||
reporters: ['internal-angular'],
|
||||
sauceLabs: {
|
||||
testName: 'Angular2',
|
||||
startConnect: false,
|
||||
recordVideo: false,
|
||||
recordScreenshots: false,
|
||||
options: {
|
||||
'selenium-version': '2.48.2',
|
||||
'command-timeout': 600,
|
||||
'idle-timeout': 600,
|
||||
'max-duration': 5400
|
||||
options: {
|
||||
'selenium-version': '2.45.0',
|
||||
'command-timeout': 600,
|
||||
'idle-timeout': 600,
|
||||
'max-duration': 5400
|
||||
}
|
||||
},
|
||||
|
||||
browserStack: {
|
||||
project: 'Angular2',
|
||||
startTunnel: false,
|
||||
retryLimit: 1,
|
||||
timeout: 600,
|
||||
pollingTimeout: 10000
|
||||
},
|
||||
|
||||
browsers: ['Chrome'],
|
||||
browsers: ['ChromeCanary'],
|
||||
|
||||
port: 9876
|
||||
});
|
||||
|
||||
if (process.env.TRAVIS) {
|
||||
var buildId = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
if (process.env.MODE.startsWith('saucelabs')) {
|
||||
config.sauceLabs.build = buildId;
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
config.sauceLabs.build = 'TRAVIS #' + process.env.TRAVIS_BUILD_NUMBER + ' (' + process.env.TRAVIS_BUILD_ID + ')';
|
||||
config.sauceLabs.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
|
||||
// TODO(mlaval): remove once SauceLabs supports websockets.
|
||||
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
|
||||
console.log('>>>> setting socket.io transport to polling <<<<');
|
||||
config.transports = ['polling'];
|
||||
}
|
||||
|
||||
if (process.env.MODE.startsWith('browserstack')) {
|
||||
config.browserStack.build = buildId;
|
||||
config.browserStack.tunnelIdentifier = process.env.TRAVIS_JOB_NUMBER;
|
||||
}
|
||||
// TODO(mlaval): remove once SauceLabs supports websockets.
|
||||
// This speeds up the capturing a bit, as browsers don't even try to use websocket.
|
||||
config.transports = ['xhr-polling'];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
98
modules/angular1_router/build.js
vendored
98
modules/angular1_router/build.js
vendored
@ -6,13 +6,12 @@ var ts = require('typescript');
|
||||
var files = [
|
||||
'lifecycle_annotations_impl.ts',
|
||||
'url_parser.ts',
|
||||
'route_recognizer.ts',
|
||||
'path_recognizer.ts',
|
||||
'route_config_impl.ts',
|
||||
'async_route_handler.ts',
|
||||
'sync_route_handler.ts',
|
||||
'component_recognizer.ts',
|
||||
'route_recognizer.ts',
|
||||
'instruction.ts',
|
||||
'path_recognizer.ts',
|
||||
'route_config_nomalizer.ts',
|
||||
'route_lifecycle_reflector.ts',
|
||||
'route_registry.ts',
|
||||
@ -22,28 +21,80 @@ var files = [
|
||||
var PRELUDE = '(function(){\n';
|
||||
var POSTLUDE = '\n}());\n';
|
||||
var FACADES = fs.readFileSync(__dirname + '/lib/facades.es5', 'utf8');
|
||||
var DIRECTIVES = fs.readFileSync(__dirname + '/src/ng_outlet.ts', 'utf8');
|
||||
var moduleTemplate = fs.readFileSync(__dirname + '/src/module_template.js', 'utf8');
|
||||
|
||||
var TRACEUR_RUNTIME = fs.readFileSync(__dirname + '/../../node_modules/traceur/bin/traceur-runtime.js', 'utf8');
|
||||
var DIRECTIVES = fs.readFileSync(__dirname + '/src/ng_outlet.js', 'utf8');
|
||||
function main() {
|
||||
var dir = __dirname + '/../angular2/src/router/';
|
||||
var sharedCode = files.reduce(function (prev, file) {
|
||||
return prev + transform(fs.readFileSync(dir + file, 'utf8'));
|
||||
}, '');
|
||||
|
||||
var out = moduleTemplate.replace('//{{FACADES}}', FACADES).replace('//{{SHARED_CODE}}', sharedCode);
|
||||
return PRELUDE + transform(DIRECTIVES) + out + POSTLUDE;
|
||||
var out = '';
|
||||
|
||||
var sharedCode = '';
|
||||
files.forEach(function (file) {
|
||||
var moduleName = 'router/' + file.replace(/\.ts$/, '');
|
||||
|
||||
sharedCode += transform(moduleName, fs.readFileSync(dir + file, 'utf8'));
|
||||
});
|
||||
|
||||
out += "angular.module('ngComponentRouter')";
|
||||
out += angularFactory('$router', ['$q', '$location', '$$controllerIntrospector',
|
||||
'$browser', '$rootScope', '$injector'], [
|
||||
FACADES,
|
||||
"var exports = {Injectable: function () {}};",
|
||||
"var require = function () {return exports;};",
|
||||
sharedCode,
|
||||
"var RouteConfig = exports.RouteConfig;",
|
||||
"angular.annotations = {RouteConfig: RouteConfig, CanActivate: exports.CanActivate};",
|
||||
"angular.stringifyInstruction = exports.stringifyInstruction;",
|
||||
"var RouteRegistry = exports.RouteRegistry;",
|
||||
"var RootRouter = exports.RootRouter;",
|
||||
//TODO: move this code into a templated JS file
|
||||
"var registry = new RouteRegistry();",
|
||||
"var location = new Location();",
|
||||
|
||||
"$$controllerIntrospector(function (name, constructor) {",
|
||||
"if (constructor.$canActivate) {",
|
||||
"constructor.annotations = constructor.annotations || [];",
|
||||
"constructor.annotations.push(new angular.annotations.CanActivate(function (instruction) {",
|
||||
"return $injector.invoke(constructor.$canActivate, constructor, {",
|
||||
"$routeParams: instruction.component ? instruction.component.params : instruction.params",
|
||||
"});",
|
||||
"}));",
|
||||
"}",
|
||||
"if (constructor.$routeConfig) {",
|
||||
"constructor.annotations = constructor.annotations || [];",
|
||||
"constructor.annotations.push(new angular.annotations.RouteConfig(constructor.$routeConfig));",
|
||||
"}",
|
||||
"if (constructor.annotations) {",
|
||||
"constructor.annotations.forEach(function(annotation) {",
|
||||
"if (annotation instanceof RouteConfig) {",
|
||||
"annotation.configs.forEach(function (config) {",
|
||||
"registry.config(constructor, config);",
|
||||
"});",
|
||||
"}",
|
||||
"});",
|
||||
"}",
|
||||
"});",
|
||||
|
||||
"var router = new RootRouter(registry, undefined, location, new Object());",
|
||||
"$rootScope.$watch(function () { return $location.path(); }, function (path) {",
|
||||
"if (router.lastNavigationAttempt !== path) {",
|
||||
"router.navigate(path);",
|
||||
"}",
|
||||
"});",
|
||||
|
||||
"return router;"
|
||||
].join('\n'));
|
||||
|
||||
return PRELUDE + TRACEUR_RUNTIME + DIRECTIVES + out + POSTLUDE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Given a directory name and a file's TypeScript content, return an object with the ES5 code,
|
||||
* sourcemap, and exported variable identifier name for the content.
|
||||
* sourcemap, anf exported variable identifier name for the content.
|
||||
*/
|
||||
var IMPORT_RE = new RegExp("import \\{?([\\w\\n_, ]+)\\}? from '(.+)';?", 'g');
|
||||
var INJECT_RE = new RegExp("@Inject\\(ROUTER_PRIMARY_COMPONENT\\)", 'g');
|
||||
var IMJECTABLE_RE = new RegExp("@Injectable\\(\\)", 'g');
|
||||
function transform(contents) {
|
||||
contents = contents.replace(INJECT_RE, '').replace(IMJECTABLE_RE, '');
|
||||
function transform(dir, contents) {
|
||||
contents = contents.replace(IMPORT_RE, function (match, imports, includePath) {
|
||||
//TODO: remove special-case
|
||||
if (isFacadeModule(includePath) || includePath === './router_outlet') {
|
||||
@ -53,10 +104,21 @@ function transform(contents) {
|
||||
});
|
||||
return ts.transpile(contents, {
|
||||
target: ts.ScriptTarget.ES5,
|
||||
module: ts.ModuleKind.CommonJS
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
sourceRoot: dir
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function angularFactory(name, deps, body) {
|
||||
return ".factory('" + name + "', [" +
|
||||
deps.map(function (service) {
|
||||
return "'" + service + "', ";
|
||||
}).join('') +
|
||||
"function (" + deps.join(', ') + ") {\n" + body + "\n}])";
|
||||
}
|
||||
|
||||
|
||||
function isFacadeModule(modulePath) {
|
||||
return modulePath.indexOf('facade') > -1 ||
|
||||
modulePath === 'angular2/src/core/reflection/reflection';
|
||||
@ -67,5 +129,5 @@ module.exports = function () {
|
||||
if (!fs.existsSync(dist)) {
|
||||
fs.mkdirSync(dist);
|
||||
}
|
||||
fs.writeFileSync(dist + '/angular_1_router.js', main());
|
||||
fs.writeFileSync(dist + '/angular_1_router.js', main(files));
|
||||
};
|
||||
|
@ -14,7 +14,7 @@
|
||||
angular.module('myApp', ['ngComponentRouter'])
|
||||
.controller('MyCtrl', ['$router', function ($router) {
|
||||
console.log($router);
|
||||
$router.navigateByUrl('/')
|
||||
$router.navigate('/')
|
||||
.then(console.log.bind(console, 'resolve'), console.log.bind(console, 'reject'));
|
||||
}]);
|
||||
</script>
|
||||
|
@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
var browserProvidersConf = require('../../browser-providers.conf.js');
|
||||
var sauceConf = require('../../sauce.conf');
|
||||
|
||||
// This runs the tests for the router in Angular 1.x
|
||||
|
||||
@ -9,21 +9,19 @@ module.exports = function (config) {
|
||||
frameworks: ['jasmine'],
|
||||
|
||||
files: [
|
||||
'../../node_modules/es6-shim/es6-shim.js',
|
||||
'../../node_modules/angular/angular.js',
|
||||
'../../node_modules/angular-animate/angular-animate.js',
|
||||
'../../node_modules/angular-mocks/angular-mocks.js',
|
||||
|
||||
'../../dist/angular_1_router.js',
|
||||
'src/ng_route_shim.js',
|
||||
|
||||
'test/*.es5.js',
|
||||
'test/**/*_spec.js'
|
||||
],
|
||||
|
||||
customLaunchers: browserProvidersConf.customLaunchers,
|
||||
customLaunchers: sauceConf.customLaunchers,
|
||||
|
||||
browsers: ['Chrome']
|
||||
browsers: ['ChromeCanary']
|
||||
};
|
||||
|
||||
config.set(options);
|
||||
|
@ -32,10 +32,6 @@ function isArray(obj) {
|
||||
return Array.isArray(obj);
|
||||
}
|
||||
|
||||
function getTypeNameForDebugging (fn) {
|
||||
return fn.name || 'Root';
|
||||
}
|
||||
|
||||
var PromiseWrapper = {
|
||||
resolve: function (reason) {
|
||||
return $q.when(reason);
|
||||
@ -132,7 +128,7 @@ var StringMapWrapper = {
|
||||
},
|
||||
|
||||
forEach: function (m, fn) {
|
||||
for (var prop in m) {
|
||||
for (prop in m) {
|
||||
if (m.hasOwnProperty(prop)) {
|
||||
fn(m[prop], prop);
|
||||
}
|
||||
@ -173,10 +169,6 @@ var StringMapWrapper = {
|
||||
|
||||
var List = Array;
|
||||
var ListWrapper = {
|
||||
clear: function (l) {
|
||||
l.length = 0;
|
||||
},
|
||||
|
||||
create: function () {
|
||||
return [];
|
||||
},
|
||||
@ -195,10 +187,6 @@ var ListWrapper = {
|
||||
return array[0];
|
||||
},
|
||||
|
||||
last: function(array) {
|
||||
return (array && array.length) > 0 ? array[array.length - 1] : null;
|
||||
},
|
||||
|
||||
map: function (l, fn) {
|
||||
return l.map(fn);
|
||||
},
|
||||
@ -255,10 +243,18 @@ var StringWrapper = {
|
||||
return s.split(re);
|
||||
},
|
||||
|
||||
substring: function(s, start, end) {
|
||||
return s.substr(start, end);
|
||||
},
|
||||
|
||||
replaceAll: function(s, from, replace) {
|
||||
return s.replace(from, replace);
|
||||
},
|
||||
|
||||
startsWith: function(s, start) {
|
||||
return s.startsWith(start);
|
||||
},
|
||||
|
||||
replaceAllMapped: function(s, from, cb) {
|
||||
return s.replace(from, function(matches) {
|
||||
// Remove offset & string from the result array
|
||||
@ -276,21 +272,14 @@ var StringWrapper = {
|
||||
|
||||
//TODO: implement?
|
||||
// I think it's too heavy to ask 1.x users to bring in Rx for the router...
|
||||
function EventEmitter() {}
|
||||
function EventEmitter() {
|
||||
|
||||
}
|
||||
|
||||
var BaseException = Error;
|
||||
|
||||
var ObservableWrapper = {
|
||||
callNext: function(ob, val) {
|
||||
ob.fn(val);
|
||||
},
|
||||
callEmit: function(ob, val) {
|
||||
ob.fn(val);
|
||||
},
|
||||
|
||||
subscribe: function(ob, fn) {
|
||||
ob.fn = fn;
|
||||
}
|
||||
callNext: function(){}
|
||||
};
|
||||
|
||||
// TODO: https://github.com/angular/angular.js/blob/master/src/ng/browser.js#L227-L265
|
||||
|
71
modules/angular1_router/src/module_template.js
vendored
71
modules/angular1_router/src/module_template.js
vendored
@ -1,71 +0,0 @@
|
||||
|
||||
angular.module('ngComponentRouter').
|
||||
value('$route', null). // can be overloaded with ngRouteShim
|
||||
// Because Angular 1 has no notion of a root component, we use an object with unique identity
|
||||
// to represent this. Can be overloaded with a component name
|
||||
value('$routerRootComponent', new Object()).
|
||||
factory('$router', ['$q', '$location', '$$directiveIntrospector', '$browser', '$rootScope', '$injector', '$routerRootComponent', routerFactory]);
|
||||
|
||||
function routerFactory($q, $location, $$directiveIntrospector, $browser, $rootScope, $injector, $routerRootComponent) {
|
||||
|
||||
// When this file is processed, the line below is replaced with
|
||||
// the contents of `../lib/facades.es5`.
|
||||
//{{FACADES}}
|
||||
|
||||
var exports = {
|
||||
Injectable: function () {},
|
||||
OpaqueToken: function () {},
|
||||
Inject: function () {}
|
||||
};
|
||||
var require = function () {return exports;};
|
||||
|
||||
// When this file is processed, the line below is replaced with
|
||||
// the contents of the compiled TypeScript classes.
|
||||
//{{SHARED_CODE}}
|
||||
|
||||
//TODO: this is a hack to replace the exiting implementation at run-time
|
||||
exports.getCanActivateHook = function (directiveName) {
|
||||
var factory = $$directiveIntrospector.getTypeByName(directiveName);
|
||||
return factory && factory.$canActivate && function (next, prev) {
|
||||
return $injector.invoke(factory.$canActivate, null, {
|
||||
$nextInstruction: next,
|
||||
$prevInstruction: prev
|
||||
});
|
||||
};
|
||||
};
|
||||
|
||||
// This hack removes assertions about the type of the "component"
|
||||
// property in a route config
|
||||
exports.assertComponentExists = function () {};
|
||||
|
||||
angular.stringifyInstruction = function (instruction) {
|
||||
return instruction.toRootUrl();
|
||||
};
|
||||
|
||||
var RouteRegistry = exports.RouteRegistry;
|
||||
var RootRouter = exports.RootRouter;
|
||||
|
||||
var registry = new RouteRegistry($routerRootComponent);
|
||||
var location = new Location();
|
||||
|
||||
$$directiveIntrospector(function (name, factory) {
|
||||
if (angular.isArray(factory.$routeConfig)) {
|
||||
factory.$routeConfig.forEach(function (config) {
|
||||
registry.config(name, config);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
var router = new RootRouter(registry, location, $routerRootComponent);
|
||||
$rootScope.$watch(function () { return $location.path(); }, function (path) {
|
||||
if (router.lastNavigationAttempt !== path) {
|
||||
router.navigateByUrl(path);
|
||||
}
|
||||
});
|
||||
|
||||
router.subscribe(function () {
|
||||
$rootScope.$broadcast('$routeChangeSuccess', {});
|
||||
});
|
||||
|
||||
return router;
|
||||
}
|
415
modules/angular1_router/src/ng_outlet.js
vendored
Normal file
415
modules/angular1_router/src/ng_outlet.js
vendored
Normal file
@ -0,0 +1,415 @@
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* A module for adding new a routing system Angular 1.
|
||||
*/
|
||||
angular.module('ngComponentRouter', [])
|
||||
.factory('$componentMapper', $componentMapperFactory)
|
||||
.directive('ngOutlet', ngOutletDirective)
|
||||
.directive('ngOutlet', ngOutletFillContentDirective)
|
||||
.directive('ngLink', ngLinkDirective)
|
||||
.directive('a', anchorLinkDirective); // TODO: make the anchor link feature configurable
|
||||
|
||||
/*
|
||||
* A module for inspecting controller constructors
|
||||
*/
|
||||
angular.module('ng')
|
||||
.provider('$$controllerIntrospector', $$controllerIntrospectorProvider)
|
||||
.config(controllerProviderDecorator);
|
||||
|
||||
/*
|
||||
* decorates with routing info
|
||||
*/
|
||||
function controllerProviderDecorator($controllerProvider, $$controllerIntrospectorProvider) {
|
||||
var register = $controllerProvider.register;
|
||||
$controllerProvider.register = function (name, ctrl) {
|
||||
$$controllerIntrospectorProvider.register(name, ctrl);
|
||||
return register.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: decorate $controller ?
|
||||
/*
|
||||
* private service that holds route mappings for each controller
|
||||
*/
|
||||
function $$controllerIntrospectorProvider() {
|
||||
var controllers = [];
|
||||
var controllersByName = {};
|
||||
var onControllerRegistered = null;
|
||||
return {
|
||||
register: function (name, constructor) {
|
||||
if (angular.isArray(constructor)) {
|
||||
constructor = constructor[constructor.length - 1];
|
||||
}
|
||||
controllersByName[name] = constructor;
|
||||
constructor.$$controllerName = name;
|
||||
if (onControllerRegistered) {
|
||||
onControllerRegistered(name, constructor);
|
||||
} else {
|
||||
controllers.push({name: name, constructor: constructor});
|
||||
}
|
||||
},
|
||||
$get: ['$componentMapper', function ($componentMapper) {
|
||||
var fn = function (newOnControllerRegistered) {
|
||||
onControllerRegistered = function (name, constructor) {
|
||||
name = $componentMapper.component(name);
|
||||
return newOnControllerRegistered(name, constructor);
|
||||
};
|
||||
while (controllers.length > 0) {
|
||||
var rule = controllers.pop();
|
||||
onControllerRegistered(rule.name, rule.constructor);
|
||||
}
|
||||
};
|
||||
|
||||
fn.getTypeByName = function (name) {
|
||||
return controllersByName[name];
|
||||
};
|
||||
|
||||
return fn;
|
||||
}]
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @name ngOutlet
|
||||
*
|
||||
* @description
|
||||
* An ngOutlet is where resolved content goes.
|
||||
*
|
||||
* ## Use
|
||||
*
|
||||
* ```html
|
||||
* <div ng-outlet="name"></div>
|
||||
* ```
|
||||
*
|
||||
* The value for the `ngOutlet` attribute is optional.
|
||||
*/
|
||||
function ngOutletDirective($animate, $injector, $q, $router, $componentMapper, $controller,
|
||||
$$controllerIntrospector, $templateRequest) {
|
||||
var rootRouter = $router;
|
||||
|
||||
return {
|
||||
restrict: 'AE',
|
||||
transclude: 'element',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
require: ['?^^ngOutlet', 'ngOutlet'],
|
||||
link: outletLink,
|
||||
controller: function () {},
|
||||
controllerAs: '$$ngOutlet'
|
||||
};
|
||||
|
||||
function outletLink(scope, $element, attrs, ctrls, $transclude) {
|
||||
var outletName = attrs.ngOutlet || 'default',
|
||||
parentCtrl = ctrls[0],
|
||||
myCtrl = ctrls[1],
|
||||
router = (parentCtrl && parentCtrl.$$router) || rootRouter;
|
||||
|
||||
var childRouter,
|
||||
currentInstruction,
|
||||
currentScope,
|
||||
currentController,
|
||||
currentElement,
|
||||
previousLeaveAnimation;
|
||||
|
||||
function cleanupLastView() {
|
||||
if (previousLeaveAnimation) {
|
||||
$animate.cancel(previousLeaveAnimation);
|
||||
previousLeaveAnimation = null;
|
||||
}
|
||||
|
||||
if (currentScope) {
|
||||
currentScope.$destroy();
|
||||
currentScope = null;
|
||||
}
|
||||
if (currentElement) {
|
||||
previousLeaveAnimation = $animate.leave(currentElement);
|
||||
previousLeaveAnimation.then(function () {
|
||||
previousLeaveAnimation = null;
|
||||
});
|
||||
currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
router.registerPrimaryOutlet({
|
||||
reuse: function (instruction) {
|
||||
var next = $q.when(true);
|
||||
var previousInstruction = currentInstruction;
|
||||
currentInstruction = instruction;
|
||||
if (currentController.onReuse) {
|
||||
next = $q.when(currentController.onReuse(currentInstruction, previousInstruction));
|
||||
}
|
||||
|
||||
return next;
|
||||
},
|
||||
canReuse: function (nextInstruction) {
|
||||
var result;
|
||||
if (!currentInstruction ||
|
||||
currentInstruction.componentType !== nextInstruction.componentType) {
|
||||
result = false;
|
||||
} else if (currentController.canReuse) {
|
||||
result = currentController.canReuse(nextInstruction, currentInstruction);
|
||||
} else {
|
||||
result = nextInstruction === currentInstruction ||
|
||||
angular.equals(nextInstruction.params, currentInstruction.params);
|
||||
}
|
||||
return $q.when(result);
|
||||
},
|
||||
canDeactivate: function (instruction) {
|
||||
if (currentInstruction && currentController && currentController.canDeactivate) {
|
||||
return $q.when(currentController.canDeactivate(instruction, currentInstruction));
|
||||
}
|
||||
return $q.when(true);
|
||||
},
|
||||
deactivate: function (instruction) {
|
||||
if (currentController && currentController.onDeactivate) {
|
||||
return $q.when(currentController.onDeactivate(instruction, currentInstruction));
|
||||
}
|
||||
return $q.when();
|
||||
},
|
||||
activate: function (instruction) {
|
||||
var previousInstruction = currentInstruction;
|
||||
currentInstruction = instruction;
|
||||
childRouter = router.childRouter(instruction.componentType);
|
||||
|
||||
var controllerConstructor, componentName;
|
||||
controllerConstructor = instruction.componentType;
|
||||
componentName = $componentMapper.component(controllerConstructor.$$controllerName);
|
||||
|
||||
var componentTemplateUrl = $componentMapper.template(componentName);
|
||||
return $templateRequest(componentTemplateUrl).then(function (templateHtml) {
|
||||
myCtrl.$$router = childRouter;
|
||||
myCtrl.$$template = templateHtml;
|
||||
}).then(function () {
|
||||
var newScope = scope.$new();
|
||||
var locals = {
|
||||
$scope: newScope,
|
||||
$router: childRouter,
|
||||
$routeParams: (instruction.params || {})
|
||||
};
|
||||
|
||||
// todo(shahata): controllerConstructor is not minify friendly
|
||||
currentController = $controller(controllerConstructor, locals);
|
||||
|
||||
var clone = $transclude(newScope, function (clone) {
|
||||
$animate.enter(clone, null, currentElement || $element);
|
||||
cleanupLastView();
|
||||
});
|
||||
|
||||
var controllerAs = $componentMapper.controllerAs(componentName) || componentName;
|
||||
newScope[controllerAs] = currentController;
|
||||
currentElement = clone;
|
||||
currentScope = newScope;
|
||||
|
||||
if (currentController.onActivate) {
|
||||
return currentController.onActivate(instruction, previousInstruction);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ngOutletFillContentDirective($compile) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
priority: -400,
|
||||
require: 'ngOutlet',
|
||||
link: function (scope, $element, attrs, ctrl) {
|
||||
var template = ctrl.$$template;
|
||||
$element.html(template);
|
||||
var link = $compile($element.contents());
|
||||
link(scope);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @name ngLink
|
||||
* @description
|
||||
* Lets you link to different parts of the app, and automatically generates hrefs.
|
||||
*
|
||||
* ## Use
|
||||
* The directive uses a simple syntax: `ng-link="componentName({ param: paramValue })"`
|
||||
*
|
||||
* ## Example
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myApp', ['ngFuturisticRouter'])
|
||||
* .controller('AppController', ['$router', function($router) {
|
||||
* $router.config({ path: '/user/:id' component: 'user' });
|
||||
* this.user = { name: 'Brian', id: 123 };
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* ```html
|
||||
* <div ng-controller="AppController as app">
|
||||
* <a ng-link="user({id: app.user.id})">{{app.user.name}}</a>
|
||||
* </div>
|
||||
* ```
|
||||
*/
|
||||
function ngLinkDirective($router, $location, $parse) {
|
||||
var rootRouter = $router;
|
||||
|
||||
return {
|
||||
require: '?^^ngOutlet',
|
||||
restrict: 'A',
|
||||
link: ngLinkDirectiveLinkFn
|
||||
};
|
||||
|
||||
function ngLinkDirectiveLinkFn(scope, elt, attrs, ctrl) {
|
||||
var router = (ctrl && ctrl.$$router) || rootRouter;
|
||||
if (!router) {
|
||||
return;
|
||||
}
|
||||
|
||||
var link = attrs.ngLink || '';
|
||||
|
||||
function getLink(params) {
|
||||
return './' + angular.stringifyInstruction(router.generate(params));
|
||||
}
|
||||
|
||||
var routeParamsGetter = $parse(link);
|
||||
// we can avoid adding a watcher if it's a literal
|
||||
if (routeParamsGetter.constant) {
|
||||
var params = routeParamsGetter();
|
||||
elt.attr('href', getLink(params));
|
||||
} else {
|
||||
scope.$watch(function () {
|
||||
return routeParamsGetter(scope);
|
||||
}, function (params) {
|
||||
elt.attr('href', getLink(params));
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function anchorLinkDirective($router) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function (scope, element) {
|
||||
// If the linked element is not an anchor tag anymore, do nothing
|
||||
if (element[0].nodeName.toLowerCase() !== 'a') {
|
||||
return;
|
||||
}
|
||||
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var hrefAttrName = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
|
||||
element.on('click', function (event) {
|
||||
if (event.which !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var href = element.attr(hrefAttrName);
|
||||
if (href && $router.recognize(href)) {
|
||||
$router.navigate(href);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name $componentMapperFactory
|
||||
* @description
|
||||
*
|
||||
* This lets you configure conventions for what controllers are named and where to load templates from.
|
||||
*
|
||||
* The default behavior is to dasherize and serve from `./components`. A component called `myWidget`
|
||||
* uses a controller named `MyWidgetController` and a template loaded from `./components/my-widget/my-widget.html`.
|
||||
*
|
||||
* A component is:
|
||||
* - a controller
|
||||
* - a template
|
||||
* - an optional router
|
||||
*
|
||||
* This service makes it easy to group all of them into a single concept.
|
||||
*/
|
||||
function $componentMapperFactory() {
|
||||
|
||||
var DEFAULT_SUFFIX = 'Controller';
|
||||
|
||||
var componentToCtrl = function componentToCtrlDefault(name) {
|
||||
return name[0].toUpperCase() + name.substr(1) + DEFAULT_SUFFIX;
|
||||
};
|
||||
|
||||
var componentToTemplate = function componentToTemplateDefault(name) {
|
||||
var dashName = dashCase(name);
|
||||
return './components/' + dashName + '/' + dashName + '.html';
|
||||
};
|
||||
|
||||
var ctrlToComponent = function ctrlToComponentDefault(name) {
|
||||
return name[0].toLowerCase() + name.substr(1, name.length - DEFAULT_SUFFIX.length - 1);
|
||||
};
|
||||
|
||||
var componentToControllerAs = function componentToControllerAsDefault(name) {
|
||||
return name;
|
||||
};
|
||||
|
||||
return {
|
||||
controllerName: function (name) {
|
||||
return componentToCtrl(name);
|
||||
},
|
||||
|
||||
controllerAs: function (name) {
|
||||
return componentToControllerAs(name);
|
||||
},
|
||||
|
||||
template: function (name) {
|
||||
return componentToTemplate(name);
|
||||
},
|
||||
|
||||
component: function (name) {
|
||||
return ctrlToComponent(name);
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setCtrlNameMapping
|
||||
* @description takes a function for mapping component names to component controller names
|
||||
*/
|
||||
setCtrlNameMapping: function (newFn) {
|
||||
componentToCtrl = newFn;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setCtrlAsMapping
|
||||
* @description takes a function for mapping component names to controllerAs name in the template
|
||||
*/
|
||||
setCtrlAsMapping: function (newFn) {
|
||||
componentToControllerAs = newFn;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setComponentFromCtrlMapping
|
||||
* @description takes a function for mapping component controller names to component names
|
||||
*/
|
||||
setComponentFromCtrlMapping: function (newFn) {
|
||||
ctrlToComponent = newFn;
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* @name $componentMapper#setTemplateMapping
|
||||
* @description takes a function for mapping component names to component template URLs
|
||||
*/
|
||||
setTemplateMapping: function (newFn) {
|
||||
componentToTemplate = newFn;
|
||||
return this;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function dashCase(str) {
|
||||
return str.replace(/([A-Z])/g, function ($1) {
|
||||
return '-' + $1.toLowerCase();
|
||||
});
|
||||
}
|
@ -1,297 +0,0 @@
|
||||
///<reference path="../typings/angularjs/angular.d.ts"/>
|
||||
|
||||
/*
|
||||
* decorates $compileProvider so that we have access to routing metadata
|
||||
*/
|
||||
function compilerProviderDecorator($compileProvider,
|
||||
$$directiveIntrospectorProvider: DirectiveIntrospectorProvider) {
|
||||
let directive = $compileProvider.directive;
|
||||
$compileProvider.directive = function(name: string, factory: Function) {
|
||||
$$directiveIntrospectorProvider.register(name, factory);
|
||||
return directive.apply(this, arguments);
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
* private service that holds route mappings for each controller
|
||||
*/
|
||||
class DirectiveIntrospectorProvider {
|
||||
private directiveBuffer: any[] = [];
|
||||
private directiveFactoriesByName: {[name: string]: Function} = {};
|
||||
private onDirectiveRegistered: (name: string, factory: Function) => any = null;
|
||||
|
||||
register(name: string, factory: Function) {
|
||||
if (angular.isArray(factory)) {
|
||||
factory = factory[factory.length - 1];
|
||||
}
|
||||
this.directiveFactoriesByName[name] = factory;
|
||||
if (this.onDirectiveRegistered) {
|
||||
this.onDirectiveRegistered(name, factory);
|
||||
} else {
|
||||
this.directiveBuffer.push({name: name, factory: factory});
|
||||
}
|
||||
}
|
||||
|
||||
$get() {
|
||||
let fn: any = newOnControllerRegistered => {
|
||||
this.onDirectiveRegistered = newOnControllerRegistered;
|
||||
while (this.directiveBuffer.length > 0) {
|
||||
let directive = this.directiveBuffer.pop();
|
||||
this.onDirectiveRegistered(directive.name, directive.factory);
|
||||
}
|
||||
};
|
||||
|
||||
fn.getTypeByName = name => this.directiveFactoriesByName[name];
|
||||
|
||||
return fn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @name ngOutlet
|
||||
*
|
||||
* @description
|
||||
* An ngOutlet is where resolved content goes.
|
||||
*
|
||||
* ## Use
|
||||
*
|
||||
* ```html
|
||||
* <div ng-outlet="name"></div>
|
||||
* ```
|
||||
*
|
||||
* The value for the `ngOutlet` attribute is optional.
|
||||
*/
|
||||
function ngOutletDirective($animate, $q: ng.IQService, $router) {
|
||||
let rootRouter = $router;
|
||||
|
||||
return {
|
||||
restrict: 'AE',
|
||||
transclude: 'element',
|
||||
terminal: true,
|
||||
priority: 400,
|
||||
require: ['?^^ngOutlet', 'ngOutlet'],
|
||||
link: outletLink,
|
||||
controller: class {},
|
||||
controllerAs: '$$ngOutlet'
|
||||
};
|
||||
|
||||
function outletLink(scope, element, attrs, ctrls, $transclude) {
|
||||
class Outlet {
|
||||
constructor(private controller, private router) {}
|
||||
|
||||
private currentController;
|
||||
private currentInstruction;
|
||||
private currentScope;
|
||||
private currentElement;
|
||||
private previousLeaveAnimation;
|
||||
|
||||
private cleanupLastView() {
|
||||
if (this.previousLeaveAnimation) {
|
||||
$animate.cancel(this.previousLeaveAnimation);
|
||||
this.previousLeaveAnimation = null;
|
||||
}
|
||||
|
||||
if (this.currentScope) {
|
||||
this.currentScope.$destroy();
|
||||
this.currentScope = null;
|
||||
}
|
||||
if (this.currentElement) {
|
||||
this.previousLeaveAnimation = $animate.leave(this.currentElement);
|
||||
this.previousLeaveAnimation.then(() => this.previousLeaveAnimation = null);
|
||||
this.currentElement = null;
|
||||
}
|
||||
}
|
||||
|
||||
reuse(instruction) {
|
||||
let next = $q.when(true);
|
||||
let previousInstruction = this.currentInstruction;
|
||||
this.currentInstruction = instruction;
|
||||
if (this.currentController && this.currentController.$routerOnReuse) {
|
||||
next = $q.when(
|
||||
this.currentController.$routerOnReuse(this.currentInstruction, previousInstruction));
|
||||
}
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
routerCanReuse(nextInstruction) {
|
||||
let result;
|
||||
if (!this.currentInstruction ||
|
||||
this.currentInstruction.componentType !== nextInstruction.componentType) {
|
||||
result = false;
|
||||
} else if (this.currentController && this.currentController.$routerCanReuse) {
|
||||
result = this.currentController.$routerCanReuse(nextInstruction, this.currentInstruction);
|
||||
} else {
|
||||
result = nextInstruction === this.currentInstruction ||
|
||||
angular.equals(nextInstruction.params, this.currentInstruction.params);
|
||||
}
|
||||
return $q.when(result);
|
||||
}
|
||||
|
||||
routerCanDeactivate(instruction) {
|
||||
if (this.currentController && this.currentController.$routerCanDeactivate) {
|
||||
return $q.when(
|
||||
this.currentController.$routerCanDeactivate(instruction, this.currentInstruction));
|
||||
}
|
||||
return $q.when(true);
|
||||
}
|
||||
|
||||
deactivate(instruction) {
|
||||
if (this.currentController && this.currentController.$routerOnDeactivate) {
|
||||
return $q.when(
|
||||
this.currentController.$routerOnDeactivate(instruction, this.currentInstruction));
|
||||
}
|
||||
return $q.when();
|
||||
}
|
||||
|
||||
activate(instruction) {
|
||||
let previousInstruction = this.currentInstruction;
|
||||
this.currentInstruction = instruction;
|
||||
|
||||
let componentName = this.controller.$$componentName = instruction.componentType;
|
||||
|
||||
if (typeof componentName !== 'string') {
|
||||
throw new Error('Component is not a string for ' + instruction.urlPath);
|
||||
}
|
||||
|
||||
this.controller.$$routeParams = instruction.params;
|
||||
this.controller.$$template = '<div ' + dashCase(componentName) + '></div>';
|
||||
this.controller.$$router = this.router.childRouter(instruction.componentType);
|
||||
|
||||
let newScope = scope.$new();
|
||||
|
||||
let clone = $transclude(newScope, clone => {
|
||||
$animate.enter(clone, null, this.currentElement || element);
|
||||
this.cleanupLastView();
|
||||
});
|
||||
|
||||
this.currentElement = clone;
|
||||
this.currentScope = newScope;
|
||||
|
||||
// TODO: prefer the other directive retrieving the controller
|
||||
// by debug mode
|
||||
this.currentController = this.currentElement.children().eq(0).controller(componentName);
|
||||
|
||||
if (this.currentController && this.currentController.$routerOnActivate) {
|
||||
return this.currentController.$routerOnActivate(instruction, previousInstruction);
|
||||
}
|
||||
return $q.when();
|
||||
}
|
||||
}
|
||||
|
||||
let parentCtrl = ctrls[0], myCtrl = ctrls[1],
|
||||
router = (parentCtrl && parentCtrl.$$router) || rootRouter;
|
||||
|
||||
myCtrl.$$currentComponent = null;
|
||||
|
||||
router.registerPrimaryOutlet(new Outlet(myCtrl, router));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* This directive is responsible for compiling the contents of ng-outlet
|
||||
*/
|
||||
function ngOutletFillContentDirective($compile) {
|
||||
return {
|
||||
restrict: 'EA',
|
||||
priority: -400,
|
||||
require: 'ngOutlet',
|
||||
link: (scope, element, attrs, ctrl) => {
|
||||
let template = ctrl.$$template;
|
||||
element.html(template);
|
||||
let link = $compile(element.contents());
|
||||
link(scope);
|
||||
|
||||
// TODO: move to primary directive
|
||||
let componentInstance = scope[ctrl.$$componentName];
|
||||
if (componentInstance) {
|
||||
ctrl.$$currentComponent = componentInstance;
|
||||
|
||||
componentInstance.$router = ctrl.$$router;
|
||||
componentInstance.$routeParams = ctrl.$$routeParams;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @name ngLink
|
||||
* @description
|
||||
* Lets you link to different parts of the app, and automatically generates hrefs.
|
||||
*
|
||||
* ## Use
|
||||
* The directive uses a simple syntax: `ng-link="componentName({ param: paramValue })"`
|
||||
*
|
||||
* ### Example
|
||||
*
|
||||
* ```js
|
||||
* angular.module('myApp', ['ngComponentRouter'])
|
||||
* .controller('AppController', ['$router', function($router) {
|
||||
* $router.config({ path: '/user/:id', component: 'user' });
|
||||
* this.user = { name: 'Brian', id: 123 };
|
||||
* });
|
||||
* ```
|
||||
*
|
||||
* ```html
|
||||
* <div ng-controller="AppController as app">
|
||||
* <a ng-link="user({id: app.user.id})">{{app.user.name}}</a>
|
||||
* </div>
|
||||
* ```
|
||||
*/
|
||||
function ngLinkDirective($router, $parse) {
|
||||
let rootRouter = $router;
|
||||
|
||||
return {require: '?^^ngOutlet', restrict: 'A', link: ngLinkDirectiveLinkFn};
|
||||
|
||||
function ngLinkDirectiveLinkFn(scope, element, attrs, ctrl) {
|
||||
let router = (ctrl && ctrl.$$router) || rootRouter;
|
||||
if (!router) {
|
||||
return;
|
||||
}
|
||||
|
||||
let instruction = null;
|
||||
let link = attrs.ngLink || '';
|
||||
|
||||
function getLink(params) {
|
||||
instruction = router.generate(params);
|
||||
return './' + angular.stringifyInstruction(instruction);
|
||||
}
|
||||
|
||||
let routeParamsGetter = $parse(link);
|
||||
// we can avoid adding a watcher if it's a literal
|
||||
if (routeParamsGetter.constant) {
|
||||
let params = routeParamsGetter();
|
||||
element.attr('href', getLink(params));
|
||||
} else {
|
||||
scope.$watch(() => routeParamsGetter(scope), params => element.attr('href', getLink(params)),
|
||||
true);
|
||||
}
|
||||
|
||||
element.on('click', event => {
|
||||
if (event.which !== 1 || !instruction) {
|
||||
return;
|
||||
}
|
||||
|
||||
$router.navigateByInstruction(instruction);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function dashCase(str: string): string {
|
||||
return str.replace(/[A-Z]/g, match => '-' + match.toLowerCase());
|
||||
}
|
||||
|
||||
/*
|
||||
* A module for adding new a routing system Angular 1.
|
||||
*/
|
||||
angular.module('ngComponentRouter', [])
|
||||
.directive('ngOutlet', ngOutletDirective)
|
||||
.directive('ngOutlet', ngOutletFillContentDirective)
|
||||
.directive('ngLink', ngLinkDirective);
|
||||
|
||||
/*
|
||||
* A module for inspecting controller constructors
|
||||
*/
|
||||
angular.module('ng')
|
||||
.provider('$$directiveIntrospector', DirectiveIntrospectorProvider)
|
||||
.config(compilerProviderDecorator);
|
349
modules/angular1_router/src/ng_route_shim.js
vendored
349
modules/angular1_router/src/ng_route_shim.js
vendored
@ -1,349 +0,0 @@
|
||||
/** @license Copyright 2014-2015 Google, Inc. http://github.com/angular/angular/LICENSE */
|
||||
(function () {
|
||||
|
||||
'use strict';
|
||||
|
||||
// keep a reference to compileProvider so we can register new component-directives
|
||||
// on-the-fly based on $routeProvider configuration
|
||||
// TODO: remove this– right now you can only bootstrap one Angular app with this hack
|
||||
var $compileProvider, $q, $injector;
|
||||
|
||||
/**
|
||||
* This module loads services that mimic ngRoute's configuration, and includes
|
||||
* an anchor link directive that intercepts clicks to routing.
|
||||
*
|
||||
* This module is intended to be used as a stop-gap solution for projects upgrading from ngRoute.
|
||||
* It intentionally does not implement all features of ngRoute.
|
||||
*/
|
||||
angular.module('ngRouteShim', [])
|
||||
.provider('$route', $RouteProvider)
|
||||
.config(['$compileProvider', function (compileProvider) {
|
||||
$compileProvider = compileProvider;
|
||||
}])
|
||||
.factory('$routeParams', $routeParamsFactory)
|
||||
.directive('a', anchorLinkDirective)
|
||||
|
||||
// Connects the legacy $routeProvider config shim to Component Router's config.
|
||||
.run(['$route', '$router', function ($route, $router) {
|
||||
$route.$$subscribe(function (routeDefinition) {
|
||||
if (!angular.isArray(routeDefinition)) {
|
||||
routeDefinition = [routeDefinition];
|
||||
}
|
||||
$router.config(routeDefinition);
|
||||
});
|
||||
}]);
|
||||
|
||||
|
||||
/**
|
||||
* A shimmed out provider that provides the same API as ngRoute's $routeProvider, but uses these calls
|
||||
* to configure Component Router.
|
||||
*/
|
||||
function $RouteProvider() {
|
||||
|
||||
var routes = [];
|
||||
var subscriptionFn = null;
|
||||
|
||||
var routeMap = {};
|
||||
|
||||
// Stats for which routes are skipped
|
||||
var skipCount = 0;
|
||||
var successCount = 0;
|
||||
var allCount = 0;
|
||||
|
||||
function consoleMetrics() {
|
||||
return '(' + skipCount + ' skipped / ' + successCount + ' success / ' + allCount + ' total)';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $routeProvider#when
|
||||
*
|
||||
* @param {string} path Route path (matched against `$location.path`). If `$location.path`
|
||||
* contains redundant trailing slash or is missing one, the route will still match and the
|
||||
* `$location.path` will be updated to add or drop the trailing slash to exactly match the
|
||||
* route definition.
|
||||
*
|
||||
* @param {Object} route Mapping information to be assigned to `$route.current` on route
|
||||
* match.
|
||||
*/
|
||||
this.when = function(path, route) {
|
||||
//copy original route object to preserve params inherited from proto chain
|
||||
var routeCopy = angular.copy(route);
|
||||
|
||||
allCount++;
|
||||
|
||||
if (angular.isDefined(routeCopy.reloadOnSearch)) {
|
||||
console.warn('Route for "' + path + '" uses "reloadOnSearch" which is not implemented.');
|
||||
}
|
||||
if (angular.isDefined(routeCopy.caseInsensitiveMatch)) {
|
||||
console.warn('Route for "' + path + '" uses "caseInsensitiveMatch" which is not implemented.');
|
||||
}
|
||||
|
||||
// use new wildcard format
|
||||
path = reformatWildcardParams(path);
|
||||
|
||||
if (path[path.length - 1] == '*') {
|
||||
skipCount++;
|
||||
console.warn('Route for "' + path + '" ignored because it ends with *. Skipping.', consoleMetrics());
|
||||
return this;
|
||||
}
|
||||
|
||||
if (path.indexOf('?') > -1) {
|
||||
skipCount++;
|
||||
console.warn('Route for "' + path + '" ignored because it has optional parameters. Skipping.', consoleMetrics());
|
||||
return this;
|
||||
}
|
||||
|
||||
if (typeof route.redirectTo == 'function') {
|
||||
skipCount++;
|
||||
console.warn('Route for "' + path + '" ignored because lazy redirecting to a function is not yet implemented. Skipping.', consoleMetrics());
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
var routeDefinition = {
|
||||
path: path,
|
||||
data: routeCopy
|
||||
};
|
||||
|
||||
routeMap[path] = routeCopy;
|
||||
|
||||
if (route.redirectTo) {
|
||||
routeDefinition.redirectTo = [routeMap[route.redirectTo].name];
|
||||
} else {
|
||||
if (routeCopy.controller && !routeCopy.controllerAs) {
|
||||
console.warn('Route for "' + path + '" should use "controllerAs".');
|
||||
}
|
||||
|
||||
var directiveName = routeObjToRouteName(routeCopy, path);
|
||||
|
||||
if (!directiveName) {
|
||||
throw new Error('Could not determine a name for route "' + path + '".');
|
||||
}
|
||||
|
||||
routeDefinition.component = directiveName;
|
||||
routeDefinition.name = route.name || upperCase(directiveName);
|
||||
|
||||
var directiveController = routeCopy.controller;
|
||||
|
||||
var directiveDefinition = {
|
||||
scope: false,
|
||||
controller: directiveController,
|
||||
controllerAs: routeCopy.controllerAs,
|
||||
templateUrl: routeCopy.templateUrl,
|
||||
template: routeCopy.template
|
||||
};
|
||||
|
||||
var directiveFactory = function () {
|
||||
return directiveDefinition;
|
||||
};
|
||||
|
||||
// if we have route resolve options, prepare a wrapper controller
|
||||
if (directiveController && routeCopy.resolve) {
|
||||
var originalController = directiveController;
|
||||
var resolvedLocals = {};
|
||||
|
||||
directiveDefinition.controller = ['$injector', '$scope', function ($injector, $scope) {
|
||||
var locals = angular.extend({
|
||||
$scope: $scope
|
||||
}, resolvedLocals);
|
||||
|
||||
var ctrl = $injector.instantiate(originalController, locals);
|
||||
|
||||
if (routeCopy.controllerAs) {
|
||||
locals.$scope[routeCopy.controllerAs] = ctrl;
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}];
|
||||
|
||||
// we take care of controllerAs in the directive controller wrapper
|
||||
delete directiveDefinition.controllerAs;
|
||||
|
||||
// we resolve the locals in a canActivate block
|
||||
directiveFactory.$canActivate = function() {
|
||||
var locals = angular.extend({}, routeCopy.resolve);
|
||||
|
||||
angular.forEach(locals, function(value, key) {
|
||||
locals[key] = angular.isString(value) ?
|
||||
$injector.get(value) : $injector.invoke(value, null, null, key);
|
||||
});
|
||||
|
||||
return $q.all(locals).then(function (locals) {
|
||||
resolvedLocals = locals;
|
||||
}).then(function () {
|
||||
return true;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
// register the dynamically created directive
|
||||
$compileProvider.directive(directiveName, directiveFactory);
|
||||
}
|
||||
if (subscriptionFn) {
|
||||
subscriptionFn(routeDefinition);
|
||||
} else {
|
||||
routes.push(routeDefinition);
|
||||
}
|
||||
successCount++;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
this.otherwise = function(params) {
|
||||
if (typeof params === 'string') {
|
||||
params = {redirectTo: params};
|
||||
}
|
||||
this.when('/*rest', params);
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
this.$get = ['$q', '$injector', function (q, injector) {
|
||||
$q = q;
|
||||
$injector = injector;
|
||||
|
||||
var $route = {
|
||||
routes: routeMap,
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $route#reload
|
||||
*
|
||||
* @description
|
||||
* Causes `$route` service to reload the current route even if
|
||||
* {@link ng.$location $location} hasn't changed.
|
||||
*/
|
||||
reload: function() {
|
||||
throw new Error('Not implemented: $route.reload');
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name $route#updateParams
|
||||
*/
|
||||
updateParams: function(newParams) {
|
||||
throw new Error('Not implemented: $route.updateParams');
|
||||
},
|
||||
|
||||
/**
|
||||
* Runs the given `fn` whenever new configs are added.
|
||||
* Only one subscription is allowed.
|
||||
* Passed `fn` is called synchronously.
|
||||
*/
|
||||
$$subscribe: function(fn) {
|
||||
if (subscriptionFn) {
|
||||
throw new Error('only one subscription allowed');
|
||||
}
|
||||
subscriptionFn = fn;
|
||||
subscriptionFn(routes);
|
||||
routes = [];
|
||||
},
|
||||
|
||||
/**
|
||||
* Runs a string with stats about many route configs were adapted, and how many were
|
||||
* dropped because they are incompatible.
|
||||
*/
|
||||
$$getStats: consoleMetrics
|
||||
};
|
||||
|
||||
return $route;
|
||||
}];
|
||||
|
||||
}
|
||||
|
||||
function $routeParamsFactory($router, $rootScope) {
|
||||
// the identity of this object cannot change
|
||||
var paramsObj = {};
|
||||
|
||||
$rootScope.$on('$routeChangeSuccess', function () {
|
||||
var newParams = $router._currentInstruction && $router._currentInstruction.component.params;
|
||||
|
||||
angular.forEach(paramsObj, function (val, name) {
|
||||
delete paramsObj[name];
|
||||
});
|
||||
angular.forEach(newParams, function (val, name) {
|
||||
paramsObj[name] = val;
|
||||
});
|
||||
});
|
||||
|
||||
return paramsObj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows normal anchor links to kick off routing.
|
||||
*/
|
||||
function anchorLinkDirective($router) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
link: function (scope, element) {
|
||||
// If the linked element is not an anchor tag anymore, do nothing
|
||||
if (element[0].nodeName.toLowerCase() !== 'a') {
|
||||
return;
|
||||
}
|
||||
|
||||
// SVGAElement does not use the href attribute, but rather the 'xlinkHref' attribute.
|
||||
var hrefAttrName = Object.prototype.toString.call(element.prop('href')) === '[object SVGAnimatedString]' ?
|
||||
'xlink:href' : 'href';
|
||||
|
||||
element.on('click', function (event) {
|
||||
if (event.which !== 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
var href = element.attr(hrefAttrName);
|
||||
if (href && $router.recognize(href)) {
|
||||
$router.navigateByUrl(href);
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a route object, attempts to find a unique directive name.
|
||||
*
|
||||
* @param route – route config object passed to $routeProvider.when
|
||||
* @param path – route configuration path
|
||||
* @returns {string|name} – a normalized (camelCase) directive name
|
||||
*/
|
||||
function routeObjToRouteName(route, path) {
|
||||
var name = route.controllerAs;
|
||||
|
||||
var controller = route.controller;
|
||||
if (!name && controller) {
|
||||
if (angular.isArray(controller)) {
|
||||
controller = controller[controller.length - 1];
|
||||
}
|
||||
name = controller.name;
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
var segments = path.split('/');
|
||||
name = segments[segments.length - 1];
|
||||
}
|
||||
|
||||
if (name) {
|
||||
name = name + 'AutoCmp';
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
function upperCase(str) {
|
||||
return str.charAt(0).toUpperCase() + str.substr(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Changes "/:foo*" to "/*foo"
|
||||
*/
|
||||
var WILDCARD_PARAM_RE = new RegExp('\\/:([a-z0-9]+)\\*', 'gi');
|
||||
function reformatWildcardParams(path) {
|
||||
return path.replace(WILDCARD_PARAM_RE, function (m, m1) {
|
||||
return '/*' + m1;
|
||||
});
|
||||
}
|
||||
|
||||
}());
|
77
modules/angular1_router/test/component_mapper_spec.js
vendored
Normal file
77
modules/angular1_router/test/component_mapper_spec.js
vendored
Normal file
@ -0,0 +1,77 @@
|
||||
'use strict';
|
||||
|
||||
describe('$componentMapper', function () {
|
||||
var elt,
|
||||
$compile,
|
||||
$rootScope,
|
||||
$router,
|
||||
$templateCache;
|
||||
|
||||
function Ctrl() {
|
||||
this.message = 'howdy';
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function ($controllerProvider) {
|
||||
$controllerProvider.register('myComponentController', Ctrl);
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a component name to a controller name', inject(function ($componentMapper) {
|
||||
expect($componentMapper.controllerName('foo')).toBe('FooController');
|
||||
}));
|
||||
|
||||
it('should convert a controller name to a component name', inject(function ($componentMapper) {
|
||||
expect($componentMapper.component('FooController')).toBe('foo');
|
||||
}));
|
||||
|
||||
it('should convert a component name to a template URL', inject(function ($componentMapper) {
|
||||
expect($componentMapper.template('foo')).toBe('./components/foo/foo.html');
|
||||
}));
|
||||
|
||||
it('should work with a controller constructor fn and a template url', inject(function ($componentMapper) {
|
||||
var routes = {};
|
||||
$componentMapper.setCtrlNameMapping(function (name) {
|
||||
return routes[name].controller;
|
||||
});
|
||||
$componentMapper.setTemplateMapping(function (name) {
|
||||
return routes[name].templateUrl;
|
||||
});
|
||||
$componentMapper.setCtrlAsMapping(function (name) {
|
||||
return 'ctrl';
|
||||
});
|
||||
|
||||
routes.myComponent = {
|
||||
controller: Ctrl,
|
||||
templateUrl: '/foo'
|
||||
};
|
||||
|
||||
inject(function(_$compile_, _$rootScope_, _$router_, _$templateCache_) {
|
||||
$compile = _$compile_;
|
||||
$rootScope = _$rootScope_;
|
||||
$router = _$router_;
|
||||
$templateCache = _$templateCache_;
|
||||
});
|
||||
|
||||
$templateCache.put('/foo', [200, '{{ctrl.message}}', {}]);
|
||||
|
||||
compile('<ng-outlet></ng-outlet>');
|
||||
|
||||
$router.config([
|
||||
{ path: '/', component: Ctrl }
|
||||
]);
|
||||
|
||||
$router.navigate('/');
|
||||
$rootScope.$digest();
|
||||
|
||||
expect(elt.text()).toBe('howdy');
|
||||
}));
|
||||
|
||||
function compile(template) {
|
||||
elt = $compile('<div>' + template + '</div>')($rootScope);
|
||||
$rootScope.$digest();
|
||||
return elt;
|
||||
}
|
||||
});
|
38
modules/angular1_router/test/controller_introspector_spec.js
vendored
Normal file
38
modules/angular1_router/test/controller_introspector_spec.js
vendored
Normal file
@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
describe('$$controllerIntrospector', function () {
|
||||
|
||||
var $controllerProvider;
|
||||
|
||||
beforeEach(function() {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function(_$controllerProvider_) {
|
||||
$controllerProvider = _$controllerProvider_;
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the introspector function whenever a controller is registered', inject(function ($$controllerIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$controllerIntrospector(spy);
|
||||
function Ctrl(){}
|
||||
$controllerProvider.register('SomeController', Ctrl);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('some', Ctrl);
|
||||
}));
|
||||
|
||||
it('should call the introspector function whenever a controller is registered with array annotations', inject(function ($$controllerIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$controllerIntrospector(spy);
|
||||
function Ctrl(foo){}
|
||||
$controllerProvider.register('SomeController', ['foo', Ctrl]);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('some', Ctrl);
|
||||
}));
|
||||
|
||||
it('should retrieve a constructor', inject(function ($$controllerIntrospector) {
|
||||
function Ctrl(foo){}
|
||||
$controllerProvider.register('SomeController', ['foo', Ctrl]);
|
||||
expect($$controllerIntrospector.getTypeByName('SomeController')).toBe(Ctrl);
|
||||
}));
|
||||
});
|
@ -1,38 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
describe('$$directiveIntrospector', function () {
|
||||
|
||||
var $compileProvider;
|
||||
|
||||
beforeEach(function() {
|
||||
module('ng');
|
||||
module('ngComponentRouter');
|
||||
module(function(_$compileProvider_) {
|
||||
$compileProvider = _$compileProvider_;
|
||||
});
|
||||
});
|
||||
|
||||
it('should call the introspector function whenever a directive factory is registered', inject(function ($$directiveIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$directiveIntrospector(spy);
|
||||
function myDir(){}
|
||||
$compileProvider.directive('myDir', myDir);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('myDir', myDir);
|
||||
}));
|
||||
|
||||
it('should call the introspector function whenever a directive factory is registered with array annotations', inject(function ($$directiveIntrospector) {
|
||||
var spy = jasmine.createSpy();
|
||||
$$directiveIntrospector(spy);
|
||||
function myDir(){}
|
||||
$compileProvider.directive('myDir', ['foo', myDir]);
|
||||
|
||||
expect(spy).toHaveBeenCalledWith('myDir', myDir);
|
||||
}));
|
||||
|
||||
it('should retrieve a factory based on directive name', inject(function ($$directiveIntrospector) {
|
||||
function myDir(){}
|
||||
$compileProvider.directive('myDir', ['foo', myDir]);
|
||||
expect($$directiveIntrospector.getTypeByName('myDir')).toBe(myDir);
|
||||
}));
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user