Skip to content

Commit 3a1d518

Browse files
committed
feat(): Dartanalyzer running on travis.
1 parent f167934 commit 3a1d518

25 files changed

+894
-279
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,13 @@
88
/node_modules
99
/bower_components
1010

11+
# Dart
12+
/.pub
13+
/.packages
14+
/packages
15+
/pubspec.lock
16+
17+
1118
# IDEs
1219
/.idea
1320

.travis.yml

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ node_js:
1010
cache:
1111
directories:
1212
- node_modules
13+
- $HOME/.pub-cache
1314

1415
env:
1516
global:
@@ -19,6 +20,8 @@ env:
1920
- BROWSER_STACK_USERNAME=angularteam1
2021
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
2122
- ARCH=linux-x64
23+
- DART_DEV_VERSION=latest
24+
- DART_STABLE_VERSION=latest
2225
# Token for tsd to increase github rate limit
2326
# See https://github.com/DefinitelyTyped/tsd#tsdrc
2427
# This does not use http://docs.travis-ci.com/user/environment-variables/#Secure-Variables
@@ -32,6 +35,7 @@ env:
3235
# Order: a slower build first, so that we don't occupy an idle travis worker waiting for others to complete.
3336
- MODE=saucelabs_required
3437
- MODE=browserstack_required
38+
- MODE=dart_required DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
3539
- MODE=saucelabs_optional
3640
- MODE=browserstack_optional
3741

@@ -40,6 +44,10 @@ matrix:
4044
- env: "MODE=saucelabs_optional"
4145
- env: "MODE=browserstack_optional"
4246

47+
before_install:
48+
- ./scripts/ci/install_dart.sh
49+
50+
4351
install:
4452
- npm install
4553

@@ -52,7 +60,7 @@ before_script:
5260

5361

5462
script:
55-
- ./scripts/ci/build-and-test.sh ${MODE}
63+
- ./scripts/ci/build-and-test.sh
5664

5765
cache:
5866
directories:
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Writing Dart Compatible TypeScript
2+
3+
When writing TypeScript files in Material 2, it is important to keep in mind that these files will be automatically compiled and verified in Dart. There is valid TypeScript that will work in Angular 2, but will be transpiled to invalid Dart code.
4+
5+
Because of this, there's certain things to keep in mind.
6+
7+
## Requirements
8+
9+
This document refers to the following concepts, but do not explain them:
10+
11+
* The Dart language: https://www.dartlang.org
12+
* The `pub` Dart packages management: https://pub.dartlang.org/
13+
* The `angular-cli` toolchain: https://github.com/angular/angular-cli
14+
15+
## Dart Toolchain
16+
17+
When running `ng build` (or `ng server` which also builds), a Broccoli tree will automatically compile and format your TypeScript code into Dart. These files live along the JavaScript output of the build process, and also are moved into a special directory structure that is compatible with `pub`.
18+
19+
For example, let say you have a `md-awesome` component for Material, which contains the `awesome.ts` implementation. This file is contained in the source code as `src/components/awesome/awesome.ts`. Building this component (assuming no specs or `scss`) will result in the following files:
20+
21+
* `dist/components/awesome/awesome.ts`. The original copy.
22+
* `dist/components/awesome/awesome.js`. The Javascript code.
23+
* `dist/components/awesome/awesome.js.map`. Sourcemap.
24+
* `dist/components/awesome/awesome.dart`. The Dart code, transpiled by `ts2dart` and formatted by `dartfmt`.
25+
* `dist/dart/lib/components/awesome/awesome.dart`. The same file, copied from above into a directory structure compatible with `pub`.
26+
27+
If you have transpilation errors (ie. your TypeScript is invalid in Dart), these will fail the `ng build` step now and will output the errors in the console.
28+
29+
## Gotchas
30+
31+
Here's a list of gotchas to keep in mind when writing TypeScript code that will be compiled to Dart:
32+
33+
* **Unused imports are enforced in Dart.** Importing a file but not using it is an error, not a warning.
34+
* **`void` is not a proper type for templates.** This is important when creating `EventEmitter<>` or other templates. Instead of `void`, use `Object` and pass in `null`.
35+
* **There's no global execution.** Every executed code need to be in a function.
36+
* **Unit tests need to live inside a `main()` function.** Because of the point above, `describe()` is technically executed code and has to live in a function. Additionally, spec files are programs in Dart and as such much have a `void main() {}` function containing the test code.
37+
* **Boolean expressions are required to be boolean.** There's no type coercion or truthiness concept in Dart. Code like this: `if (!aNumber) {}` must be refactored to be `if (aNumber != 0) {}`.
38+
* **Accessing any platform primitive must be done through a Facade.** For example, Promises or DOM manipulation. Facades are going to be provided on a need-to-have basis.
39+
* **Union types are a no-go.** Dart has them on its roadmap, but for now we must avoid them.
40+
* **Dart files cannot have the same name as a reserved keyword.** For example, `for.dart`, `switch.dart` or `class.dart` are all invalid names. Since the TypeScript files have the same name when transpiled to Dart, they also have the same restriction.

ember-cli-build.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@ var path = require('path');
44
// Import the require hook. Enables us to require TS files natively.
55
require('ts-node/register');
66

7+
const detect = require('./tools/build/dart').detect;
78
var mergeTrees = require('broccoli-merge-trees');
89
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
910
var BroccoliSass = require('broccoli-sass');
1011
var broccoliAutoprefixer = require('broccoli-autoprefixer');
1112
var BroccoliTs2Dart = require('./tools/broccoli/broccoli-ts2dart').default;
13+
var dartfmt = require('./tools/broccoli/broccoli-dartfmt').default;
1214

1315
var autoprefixerOptions = require('./build/autoprefixer-options');
1416

@@ -17,21 +19,39 @@ module.exports = function(defaults) {
1719
var demoCssTree = getCssTree('demo-app');
1820
var componentCssTree = getCssTree('components');
1921
var angularAppTree = new Angular2App(defaults);
20-
var dartAppTree = new BroccoliTs2Dart('src/', {
21-
generateLibraryName: true,
22-
generateSourceMap: false,
23-
translateBuiltins: true,
24-
});
22+
var dartAppTree = getDartTree('src/');
2523

2624
return mergeTrees([
2725
angularAppTree.toTree(),
2826
componentCssTree,
2927
demoAppCssTree,
3028
demoCssTree,
31-
dartAppTree,
32-
]);
29+
].concat(dartAppTree || []));
3330
};
3431

32+
/** Gets the Dart tree - Transpile Dart files and format them afterward. */
33+
function getDartTree(root) {
34+
const ts2dart = new BroccoliTs2Dart('src/', {
35+
generateLibraryName: true,
36+
generateSourceMap: false,
37+
translateBuiltins: true,
38+
});
39+
40+
const dartSDK = detect();
41+
if (dartSDK) {
42+
// If Dart isn't found, detect() will throw an error.
43+
return dartfmt(ts2dart, { dartSDK });
44+
} else {
45+
console.warn('---------------------------------------');
46+
console.warn('You do not have the Dart SDK installed.');
47+
console.warn('In order to contribute to this repo, please refer to');
48+
console.warn('https://github.com/angular/material2/blob/master/CONTRIBUTING.md');
49+
console.warn('');
50+
console.warn('You can still build and serve the demo app without dart support.');
51+
return null;
52+
}
53+
}
54+
3555
/** Gets the tree for all of the components' CSS. */
3656
function getCssTree(folder) {
3757
var srcPath = `src/${folder}/`;

package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
},
1010
"scripts": {
1111
"build": "ng build",
12+
"dartanalyzer": "ts-node scripts/ci/dart_analyzer",
1213
"demo-app": "cd src && ng serve",
1314
"test": "karma start test/karma.conf.js"
1415
},
@@ -34,17 +35,23 @@
3435
"broccoli-sass": "^0.7.0",
3536
"browserstacktunnel-wrapper": "^1.4.2",
3637
"ember-cli-inject-live-reload": "^1.3.0",
38+
"fs-extra": "^0.26.5",
39+
"glob": "^6.0.4",
3740
"jasmine-core": "^2.3.4",
41+
"js-yaml": "^3.5.2",
3842
"karma": "^0.13.15",
3943
"karma-browserstack-launcher": "^0.1.7",
4044
"karma-chrome-launcher": "^0.2.1",
45+
"karma-dart": "^0.3.0",
4146
"karma-firefox-launcher": "^0.1.7",
4247
"karma-jasmine": "^0.3.6",
4348
"karma-sauce-launcher": "^0.2.14",
49+
"strip-ansi": "^3.0.0",
4450
"symlink-or-copy": "^1.0.1",
4551
"ts-node": "^0.5.5",
4652
"ts2dart": "^0.7.20",
4753
"tslint": "^3.2.2",
48-
"typescript": "^1.7.5"
54+
"typescript": "^1.7.5",
55+
"which": "^1.2.4"
4956
}
5057
}

pubspec.yaml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: material2
2+
environment:
3+
sdk: '>=1.12.0-dev.5.10 <2.0.0'
4+
dependencies:
5+
observe: '^0.13.1'
6+
angular2: '2.0.0-beta.0'
7+
dev_dependencies:
8+
guinness: '^0.1.18'
9+
intl: '^0.12.4'
10+
unittest: '^0.11.5+4'
11+
quiver: '^0.21.4'
12+
transformers:
13+
- angular2:
14+
platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES'
15+
entry_points:
16+
- web/src/demo-app/demo-app.dart

scripts/ci/README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Continuous Integration Scripts
2+
3+
This directory contains scripts that are related to CI only.
4+
5+
### `build-and-test.sh`
6+
7+
The main script. Setup the tests environment, build the files using the `angular-cli` tool and run the tests.
8+
9+
### `install_dart.sh`
10+
11+
Only run in Dart environments. Install Dart locally on the CI.
12+

scripts/ci/build-and-test.sh

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,27 @@
11
#!/usr/bin/env bash
2-
set -ex
32

43
echo "======= Starting build-and-test.sh ========================================"
54

65
# Go to project dir
7-
SCRIPT_DIR=$(dirname $0)
8-
cd ${SCRIPT_DIR}/../..
6+
cd $(dirname $0)/../..
97

8+
# Include sources.
9+
source scripts/ci/sources/mode.sh
10+
source scripts/ci/sources/tunnel.sh
1011

11-
start_tunnel() {
12-
case "$MODE" in
13-
saucelabs*)
14-
./scripts/sauce/sauce_connect_setup.sh
15-
;;
16-
browserstack*)
17-
./scripts/browserstack/start_tunnel.sh
18-
;;
19-
*)
20-
;;
21-
esac
22-
}
23-
24-
wait_for_tunnel() {
25-
case "$MODE" in
26-
saucelabs*)
27-
./scripts/sauce/sauce_connect_block.sh
28-
;;
29-
browserstack*)
30-
./scripts/browserstack/waitfor_tunnel.sh
31-
;;
32-
*)
33-
;;
34-
esac
35-
sleep 10
36-
}
37-
38-
teardown_tunnel() {
39-
case "$MODE" in
40-
saucelabs*)
41-
./scripts/sauce/sauce_connect_teardown.sh
42-
;;
43-
browserstack*)
44-
# ./scripts/browserstack/teardown_tunnel.sh
45-
;;
46-
*)
47-
;;
48-
esac
49-
}
50-
12+
# Setup environment.
13+
is_dart && source scripts/ci/sources/env_dart.sh
5114

5215
start_tunnel
53-
wait_for_tunnel
5416
npm run build
55-
karma start test/karma.conf.js --single-run --no-auto-watch --reporters='dots'
17+
is_dart && pub install
18+
19+
wait_for_tunnel
20+
if is_dart; then
21+
# npm run dartanalyzer
22+
echo 'TODO(hans): Implement dartanalyzer'
23+
else
24+
karma start test/karma.conf.js --single-run --no-auto-watch --reporters='dots'
25+
fi
5626
teardown_tunnel
5727

scripts/ci/dart_analyzer.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import {analyze} from '../../tools/build/dart_analyzer';
2+
import {detect} from '../../tools/build/dart';
3+
4+
5+
const command = detect()['ANALYZER'];
6+
7+
analyze('dist/dart', command, true)
8+
.then(() => {
9+
console.log('Done.');
10+
}, (err) => {
11+
console.error('Error:', err);
12+
});

scripts/ci/install_dart.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#!/bin/bash
2+
3+
set -e -x
4+
5+
6+
if [ -z "${DART_CHANNEL}" -o -z "${DART_VERSION}" -o -z "${ARCH}" ]; then
7+
echo "No Dart necessary. Not installing."
8+
exit 0
9+
fi
10+
11+
AVAILABLE_DART_VERSION=$(curl "https://storage.googleapis.com/dart-archive/channels/${DART_CHANNEL}/release/${DART_VERSION}/VERSION" | python -c \
12+
'import sys, json; print(json.loads(sys.stdin.read())["version"])')
13+
14+
echo Fetch Dart channel: ${DART_CHANNEL}
15+
16+
URL_PREFIX=https://storage.googleapis.com/dart-archive/channels/${DART_CHANNEL}/release/${DART_VERSION}
17+
DART_SDK_URL="$URL_PREFIX/sdk/dartsdk-$ARCH-release.zip"
18+
DARTIUM_URL="$URL_PREFIX/dartium/dartium-$ARCH-release.zip"
19+
20+
download_and_unzip() {
21+
ZIPFILE=${1/*\//}
22+
curl -O -L $1 && unzip -q $ZIPFILE && rm $ZIPFILE
23+
}
24+
25+
# TODO: do these downloads in parallel
26+
download_and_unzip $DART_SDK_URL
27+
download_and_unzip $DARTIUM_URL
28+
29+
echo Fetched new dart version $(<dart-sdk/version)
30+
31+
if [[ -n $DARTIUM_URL ]]; then
32+
mv dartium-* chromium
33+
fi

0 commit comments

Comments
 (0)