chore: remove dart source and tooling

This commit is contained in:
Jeremy Elbourn
2016-04-05 09:45:27 -07:00
parent c8f87a427a
commit 69512c2f6a
28 changed files with 12 additions and 1688 deletions
-6
View File
@@ -1,6 +1,3 @@
# TODO(hansl): When we're ready to test for Dart, readd every mention of Dart to this file.
# Base the Dart config on the main repo travis.yml file.
language: node_js
sudo: false
@@ -26,8 +23,6 @@ env:
- BROWSER_STACK_USERNAME=angularteam1
- BROWSER_STACK_ACCESS_KEY=BWCd4SynLzdDcv8xtzsB
- ARCH=linux-x64
- DART_DEV_VERSION=latest
- DART_STABLE_VERSION=latest
- BROWSER_PROVIDER_READY_FILE=/tmp/angular-material2-build/readyfile
# Token for tsd to increase github rate limit
# See https://github.com/DefinitelyTyped/tsd#tsdrc
@@ -44,7 +39,6 @@ env:
- MODE=e2e
- MODE=saucelabs_required
- MODE=browserstack_required
- MODE=dart_required DART_CHANNEL=stable DART_VERSION=$DART_STABLE_VERSION
- MODE=saucelabs_optional
- MODE=browserstack_optional
+1 -1
View File
@@ -103,7 +103,7 @@ Before you submit your Pull Request (PR) consider the following guidelines:
* In GitHub, send a pull request to `material2:master`.
* If we suggest changes then:
* Make the required updates.
* Re-run the Angular Material test suites for JS and Dart to ensure tests are still passing.
* Re-run the Angular Material test suites to ensure tests are still passing.
* Rebase your branch and force push to your GitHub repository (this will update your Pull
Request):
+1 -1
View File
@@ -46,7 +46,7 @@ Also see our [`Good for community contribution`](https://github.com/angular/mate
## The goal of Angular Material
Our goal is to build a set of high-quality UI components built with Angular 2 and TypeScript,
following the Material Design spec, that are consumable by both JavaScript and Dart. These
following the Material Design spec. These
components will serve as an example of how to write Angular code following best practices.
### What do we mean by "high-quality"?
@@ -1,48 +0,0 @@
# Writing Dart Compatible TypeScript
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.
Because of this, there's certain things to keep in mind.
## Requirements
This document refers to the following concepts, but do not explain them:
* The Dart language: https://www.dartlang.org
* The `pub` Dart packages management: https://pub.dartlang.org/
* The `angular-cli` toolchain: https://github.com/angular/angular-cli
## Dart Toolchain
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`.
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:
* `dist/components/awesome/awesome.ts`. The original copy.
* `dist/components/awesome/awesome.js`. The Javascript code.
* `dist/components/awesome/awesome.js.map`. Sourcemap.
* `dist/components/awesome/awesome.dart`. The Dart code, transpiled by `ts2dart` and formatted by `dartfmt`.
* `dist/dart/lib/components/awesome/awesome.dart`. The same file, copied from above into a directory structure compatible with `pub`.
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.
## Gotchas
Here's a list of gotchas to keep in mind when writing TypeScript code that will be compiled to Dart:
* **Unused imports are enforced in Dart.** Importing a file but not using it is an error, not a warning.
* **`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`.
* **There's no global execution.** Every executed code need to be in a function.
* **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.
* **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) {}`.
* **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.
* **Union types are a no-go.** Dart has them on its roadmap, but for now we must avoid them.
* **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.
* **Default values need to be constants.** This mean that code like `function myFunction(arg1: string = callToSomething()) {}` will not compile.
* **The const keyword must have a const value.** Because of that, we cannot do `const x = a + b;` even if the value of `x`, `a` and `b` will not change.
* **Lambdas need to abide to the type required.** Meaning that if a function requires a function that takes one argument, the lambda cannot be `() => {}`. Use `_` for temporary parameters. This is notable in Promises.
* **Dynamic return values fat arrows can't return non-primitive types without casting.** For example, a fat arrow that return a promise (or Future) generates a warning if using directly, like so: `promiseA.then(() => promiseB)`. In this case simply using a block works as expected; `promiseA.then(() => { return promiseB; })`.
* **Dart does not have [generic methods](http://www.typescriptlang.org/docs/handbook/generics.html)** ([issue](https://github.com/dart-lang/sdk/issues/254)).
* **Dart does not have destructuring** but it does have a [proposal](https://github.com/dart-lang/dart_enhancement_proposals/issues/24) for it.
* **Dart does not support type aliases.** Code like `type Nop = () => void` will not compile.
* **Dart does not support [tagged template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals#Tagged_template_literals)**.
+8 -72
View File
@@ -1,32 +1,16 @@
'use strict';
var fs = require('fs');
var path = require('path');
const fs = require('fs');
const path = require('path');
// Import the require hook. Enables us to require TS files natively.
require('ts-node/register');
const detect = require('./tools/build/dart').detect;
var mergeTrees = require('broccoli-merge-trees');
var Angular2App = require('angular-cli/lib/broccoli/angular2-app');
var BroccoliSass = require('broccoli-sass');
var broccoliAutoprefixer = require('broccoli-autoprefixer');
const BroccoliTs2Dart = require('./tools/broccoli/broccoli-ts2dart').default;
const BroccoliDartFmt = require('./tools/broccoli/broccoli-dartfmt').default;
const mergeTrees = require('broccoli-merge-trees');
const BroccoliFunnel = require('broccoli-funnel');
var autoprefixerOptions = require('./build/autoprefixer-options');
/**
* Almost the same as using a plain string for a tree; but unlike a plain
* string, Broccoli won't watch this. Used only internally.
*/
class UnwatchedTree {
constructor(dir) { this.dir = dir; }
read() { return this.dir; }
cleanup() { /* DoNothing */ }
}
const Angular2App = require('angular-cli/lib/broccoli/angular2-app');
const BroccoliSass = require('broccoli-sass');
const broccoliAutoprefixer = require('broccoli-autoprefixer');
const autoprefixerOptions = require('./build/autoprefixer-options');
module.exports = function(defaults) {
@@ -38,63 +22,15 @@ module.exports = function(defaults) {
vendorNpmFiles: []
});
var dartAppTree = getDartTree('src/');
return mergeTrees([
angularAppTree.toTree(),
componentCssTree,
mainCssTree,
demoAppCssTree,
demoCssTree
].concat(dartAppTree || []));
]);
};
/** Gets the Dart tree - Transpile Dart files and format them afterward. */
function getDartTree(root) {
const dartSDK = detect();
if (!dartSDK) {
console.warn('---------------------------------------');
console.warn('You do not have the Dart SDK installed.');
console.warn('In order to contribute to this repo, please refer to');
console.warn('https://github.com/angular/material2/blob/master/CONTRIBUTING.md');
console.warn('');
console.warn('You can still build and serve the demo app without dart support.');
return null;
}
const ts2dart = new BroccoliTs2Dart([root], {
generateLibraryName: true,
generateSourceMap: false,
translateBuiltins: true,
basePath: path.join(__dirname, root),
typingsRoot: '../typings/browser/ambient/',
additionalFiles: [path.join(process.cwd(), root, 'typings.d.ts')]
});
const formatter = new BroccoliDartFmt([ts2dart], { dartSDK });
const dartSources = new BroccoliFunnel(root, {
include: ['**/*.dart'],
destDir: 'dart/lib',
});
const allDartFiles = mergeTrees([
dartSources,
formatter
]);
const pubSpecTree = new BroccoliFunnel(new UnwatchedTree('.'), {
files: ['pubspec.yaml'],
destDir: 'dart'
});
// Publishes the Dart files and pubspec inside a
return mergeTrees([
pubSpecTree,
new BroccoliFunnel(formatter, { destDir: 'dart/lib' }),
allDartFiles
]);
}
/** Gets the tree for all of the components' CSS. */
function getCssTree(folder) {
var srcPath = `src/${folder}/`;
-3
View File
@@ -10,7 +10,6 @@
"scripts": {
"ci:forbidden-identifiers": "node ./scripts/ci/forbidden-identifiers.js",
"build": "ng build",
"dartanalyzer": "cd dist/dart && pub install && cd ../.. && ts-node scripts/ci/dart_analyzer",
"demo-app": "ng serve",
"test": "karma start test/karma.conf.js",
"tslint": "tslint -c tslint.json 'src/**/*.ts'",
@@ -55,7 +54,6 @@
"karma": "^0.13.15",
"karma-browserstack-launcher": "^0.1.7",
"karma-chrome-launcher": "^0.2.1",
"karma-dart": "^0.3.0",
"karma-firefox-launcher": "^0.1.7",
"karma-jasmine": "^0.3.6",
"karma-sauce-launcher": "^0.2.14",
@@ -63,7 +61,6 @@
"strip-ansi": "^3.0.0",
"symlink-or-copy": "^1.0.1",
"ts-node": "^0.5.5",
"ts2dart": "^0.7.27",
"tslint": "^3.5.0",
"typescript": "^1.7.5",
"typings": "^0.6.8",
-16
View File
@@ -1,16 +0,0 @@
name: material2
environment:
sdk: '>=1.12.0-dev.5.10 <2.0.0'
dependencies:
observe: '^0.13.1'
angular2: '2.0.0-beta.0'
dev_dependencies:
guinness: '^0.1.18'
intl: '^0.12.4'
unittest: '^0.11.5+4'
quiver: '^0.21.4'
transformers:
- angular2:
platform_directives: 'package:angular2/src/common/directives.dart#CORE_DIRECTIVES'
entry_points:
- lib/demo-app/demo-app.dart
-5
View File
@@ -5,8 +5,3 @@ This directory contains scripts that are related to CI only.
### `build-and-test.sh`
The main script. Setup the tests environment, build the files using the `angular-cli` tool and run the tests.
### `install_dart.sh`
Only run in Dart environments. Install Dart locally on the CI.
-10
View File
@@ -10,24 +10,14 @@ cd $(dirname $0)/../..
source scripts/ci/sources/mode.sh
source scripts/ci/sources/tunnel.sh
# Setup environment.
if is_dart; then
./scripts/ci/install_dart.sh
source scripts/ci/sources/env_dart.sh
fi
start_tunnel
npm run build
npm run inline-resources
echo
is_dart && pub install
wait_for_tunnel
if is_lint; then
npm run tslint
npm run ci:forbidden-identifiers
elif is_dart; then
npm run dartanalyzer
elif is_e2e; then
ng serve &
sleep 20
-17
View File
@@ -1,17 +0,0 @@
import {analyze} from '../../tools/build/dart_analyzer';
import {detect} from '../../tools/build/dart';
const command = detect()['ANALYZER'];
analyze('dist/dart', command, true)
.then((err) => {
if (err) {
throw err;
}
console.log('Done.');
})
.catch((err) => {
console.error('Error:', err);
process.exit(1);
});
-33
View File
@@ -1,33 +0,0 @@
#!/bin/bash
set -e -x
if [ -z "${DART_CHANNEL}" -o -z "${DART_VERSION}" -o -z "${ARCH}" ]; then
echo "No Dart necessary. Not installing."
exit 0
fi
AVAILABLE_DART_VERSION=$(curl "https://storage.googleapis.com/dart-archive/channels/${DART_CHANNEL}/release/${DART_VERSION}/VERSION" | python -c \
'import sys, json; print(json.loads(sys.stdin.read())["version"])')
echo Fetch Dart channel: ${DART_CHANNEL}
URL_PREFIX=https://storage.googleapis.com/dart-archive/channels/${DART_CHANNEL}/release/${DART_VERSION}
DART_SDK_URL="$URL_PREFIX/sdk/dartsdk-$ARCH-release.zip"
DARTIUM_URL="$URL_PREFIX/dartium/dartium-$ARCH-release.zip"
download_and_unzip() {
ZIPFILE=${1/*\//}
curl -O -L $1 && unzip -q $ZIPFILE && rm $ZIPFILE
}
# TODO: do these downloads in parallel
download_and_unzip $DART_SDK_URL
download_and_unzip $DARTIUM_URL
echo Fetched new dart version $(<dart-sdk/version)
if [[ -n $DARTIUM_URL ]]; then
mv dartium-* chromium
fi
-95
View File
@@ -1,95 +0,0 @@
#!/bin/bash
set -e -o pipefail
if [[ -z $ENV_SET ]]; then
export ENV_SET=1
unset DART
PLATFORM="$(uname -s)"
case "$PLATFORM" in
(Darwin)
path=$(readlink ${BASH_SOURCE[0]}||echo './scripts/env.sh')
export NGDART_SCRIPT_DIR=$(dirname $path)
;;
(Linux)
export NGDART_SCRIPT_DIR=$(dirname $(readlink -f ${BASH_SOURCE[0]}))
;;
(*)
echo Unsupported platform $PLATFORM. Exiting ... >&2
exit 3
;;
esac
export NGDART_BASE_DIR=$(dirname $NGDART_SCRIPT_DIR)
# Try to find the SDK alongside the dart command first.
if [[ -z "$DART_SDK" ]]; then
DART=$(which dart) || true
if [[ -x "$DART" ]]; then
DART_SDK="${DART/dart-sdk\/*/dart-sdk}"
if [[ ! -e "$DART_SDK" ]]; then
unset DART DART_SDK
fi
fi
fi
# Fallback: Assume it's alongside the current directory (e.g. Travis).
if [[ -z "$DART_SDK" ]]; then
DART_SDK="$(pwd)/dart-sdk"
fi
: "${DART:=$DART_SDK/bin/dart}"
if [[ ! -x "$DART" ]]; then
echo Unable to locate the dart binary / SDK. Exiting >&2
exit 3
fi
if [[ -z "$DARTIUM" ]]; then
dartiumRoot="$DART_SDK/../chromium"
if [[ -e "$dartiumRoot" ]]; then
case "$PLATFORM" in
(Linux) export DARTIUM="$dartiumRoot/chrome" ;;
(Darwin) export DARTIUM="$dartiumRoot/Chromium.app/Contents/MacOS/Chromium" ;;
(*) echo Unsupported platform $PLATFORM. Exiting ... >&2 ; exit 3 ;;
esac
fi
fi
case "$PLATFORM" in
(Linux) export DART_SDK_LIB_SEARCH_PATH="$DART_SDK" ;;
(Darwin) export DART_SDK_LIB_SEARCH_PATH="$DART_SDK/libexec" ;;
(*) echo Unsupported platform $PLATFORM. Exiting ... >&2 ; exit 3 ;;
esac
export DART_SDK
export DARTSDK
export DART
export PUB=${PUB:-"$DART_SDK/bin/pub"}
if [ -z "$PUB_CACHE" ]; then
export PUB_CACHE=$DART_SDK/pub-cache
fi
export DARTANALYZER=${DARTANALYZER:-"$DART_SDK/bin/dartanalyzer"}
export DARTDOC=${DARTDOC:-"$DART_SDK/bin/dartdoc"}
export DART_DOCGEN=${DART_DOCGEN:-"$DART_SDK/bin/docgen"}
export DART_VM_OPTIONS="--old_gen_heap_size=2048"
export DARTIUM_BIN=${DARTIUM_BIN:-"$DARTIUM"}
export CHROME_BIN=${CHROME_BIN:-"google-chrome"}
export PATH=$PATH:$DART_SDK/bin
echo '*********'
echo '** ENV **'
echo '*********'
echo DART_SDK=$DART_SDK
echo DART_SDK_LIB_SEARCH_PATH=$DART_SDK_LIB_SEARCH_PATH
echo DART=$DART
echo PUB=$PUB
echo DARTANALYZER=$DARTANALYZER
echo DARTDOC=$DARTDOC
echo DART_DOCGEN=$DART_DOCGEN
echo DARTIUM_BIN=$DARTIUM_BIN
echo CHROME_BIN=$CHROME_BIN
echo PATH=$PATH
echo NGDART_BASE_DIR=$NGDART_BASE_DIR
echo NGDART_SCRIPT_DIR=$NGDART_SCRIPT_DIR
fi
+1 -5
View File
@@ -1,14 +1,10 @@
#!/usr/bin/env bash
source ./scripts/ci/sources/tunnel.sh
is_dart() {
[[ "$MODE" = dart* ]]
}
is_e2e() {
[[ "$MODE" = e2e ]]
}
is_lint() {
[[ "$MODE" = lint ]]
}
}
-1
View File
@@ -4,7 +4,6 @@
echo "Connecting to Sauce Labs"
while [ ! -f $BROWSER_PROVIDER_READY_FILE ]; do
printf "."
#dart2js takes longer than the travis 10 min timeout to complete
sleep .5
done
echo
-6
View File
@@ -1,6 +0,0 @@
/**
* Annotation for a @BooleanFieldValue() property.
*/
class BooleanFieldValue {
const BooleanFieldValue();
}
@@ -1 +0,0 @@
-7
View File
@@ -1,7 +0,0 @@
/**
* Annotation for a @OneOf([]) property. For now, this only works in TypeScript.
* TODO(hansl): Implement this properly in Dart.
*/
class OneOf {
const OneOf(List<String> values);
}
-5
View File
@@ -1,5 +0,0 @@
import "dart:html";
CssStyleDeclaration getComputedStyle(element, [String pseudoElement]) {
return element.getComputedStyle(pseudoElement);
}
-132
View File
@@ -1,132 +0,0 @@
library testing.matchers;
import 'dart:async';
import 'package:guinness/guinness.dart' as gns;
import 'package:angular2/src/platform/dom/dom_adapter.dart' show DOM;
import 'package:angular2/src/facade/lang.dart' show isString;
Expect expect(actual, [matcher]) {
final expect = new Expect(actual);
if (matcher != null) expect.to(matcher);
return expect;
}
const _u = const Object();
bool elementContainsStyle(element, styles) {
var allPassed = true;
if (isString(styles)) {
allPassed = DOM.hasStyle(element, styles);
} else {
styles.forEach((prop, style) {
allPassed = allPassed && DOM.hasStyle(element, prop, style);
});
}
return allPassed;
}
expectErrorMessage(actual, expectedMessage) {
expect(actual.toString()).toContain(expectedMessage);
}
expectException(Function actual, expectedMessage) {
try {
actual();
} catch (e, s) {
expectErrorMessage(e, expectedMessage);
}
}
class Expect extends gns.Expect {
Expect(actual) : super(actual);
NotExpect get not => new NotExpect(actual);
void toEqual(expected) => toHaveSameProps(expected);
void toContainError(message) => expectErrorMessage(this.actual, message);
void toThrowError([message = ""]) => toThrowWith(message: message);
void toThrowErrorWith(message) => expectException(this.actual, message);
void toBePromise() => gns.guinness.matchers.toBeTrue(actual is Future);
void toHaveCssClass(className) =>
gns.guinness.matchers.toBeTrue(DOM.hasClass(actual, className));
void toHaveCssStyle(styles) {
gns.guinness.matchers.toBeTrue(elementContainsStyle(actual, styles));
}
void toImplement(expected) => toBeA(expected);
void toBeNaN() =>
gns.guinness.matchers.toBeTrue(double.NAN.compareTo(actual) == 0);
void toHaveText(expected) => _expect(elementText(actual), expected);
void toHaveBeenCalledWith([a = _u, b = _u, c = _u, d = _u, e = _u, f = _u]) =>
_expect(_argsMatch(actual, a, b, c, d, e, f), true,
reason: 'method invoked with correct arguments');
Function get _expect => gns.guinness.matchers.expect;
// TODO(tbosch): move this hack into Guinness
_argsMatch(spyFn, [a0 = _u, a1 = _u, a2 = _u, a3 = _u, a4 = _u, a5 = _u]) {
var calls = spyFn.calls;
final toMatch = _takeDefined([a0, a1, a2, a3, a4, a5]);
if (calls.isEmpty) {
return false;
} else {
gns.SamePropsMatcher matcher = new gns.SamePropsMatcher(toMatch);
for (var i = 0; i < calls.length; i++) {
var call = calls[i];
// TODO: create a better error message, not just 'Expected: <true> Actual: <false>'.
// For hacking this is good:
// print(call.positionalArguments);
if (matcher.matches(call.positionalArguments, null)) {
return true;
}
}
return false;
}
}
List _takeDefined(List iter) => iter.takeWhile((_) => _ != _u).toList();
}
class NotExpect extends gns.NotExpect {
NotExpect(actual) : super(actual);
void toEqual(expected) => toHaveSameProps(expected);
void toBePromise() => gns.guinness.matchers.toBeFalse(actual is Future);
void toHaveCssClass(className) =>
gns.guinness.matchers.toBeFalse(DOM.hasClass(actual, className));
void toHaveCssStyle(styles) {
gns.guinness.matchers.toBeFalse(elementContainsStyle(actual, styles));
}
void toBeNull() => gns.guinness.matchers.toBeFalse(actual == null);
Function get _expect => gns.guinness.matchers.expect;
}
String elementText(n) {
hasNodes(n) {
var children = DOM.childNodes(n);
return children != null && children.length > 0;
}
if (n is Iterable) {
return n.map(elementText).join("");
}
if (DOM.isCommentNode(n)) {
return '';
}
if (DOM.isElementNode(n) && DOM.tagName(n) == 'CONTENT') {
return elementText(DOM.getDistributedNodes(n));
}
if (DOM.hasShadowRoot(n)) {
return elementText(DOM.childNodesAsList(DOM.getShadowRoot(n)));
}
if (hasNodes(n)) {
return elementText(DOM.childNodesAsList(n));
}
return DOM.getText(n);
}
-166
View File
@@ -1,166 +0,0 @@
library angular2.src.testing.testing_internal;
import 'dart:async';
import 'package:guinness/guinness.dart' as gns;
export 'package:guinness/guinness.dart'
hide
Expect,
expect,
NotExpect,
beforeEach,
it,
iit,
xit,
SpyObject,
SpyFunction;
export 'matchers.dart' show expect, Expect, NotExpect;
import 'package:angular2/src/core/reflection/reflection.dart';
import 'package:angular2/src/core/reflection/reflection_capabilities.dart';
import 'package:angular2/src/core/di/provider.dart' show bind;
import 'package:angular2/src/facade/collection.dart' show StringMapWrapper;
import 'test_injector.dart';
export 'test_injector.dart' show inject;
TestInjector _testInjector = getTestInjector();
bool _isCurrentTestAsync;
Future _currentTestFuture;
bool _inIt = false;
class AsyncTestCompleter {
final _completer = new Completer();
AsyncTestCompleter() {
_currentTestFuture = this.future;
}
void done() {
_completer.complete();
}
Future get future => _completer.future;
}
void testSetup() {
reflector.reflectionCapabilities = new ReflectionCapabilities();
// beforeEach configuration:
// - Priority 3: clear the bindings before each test,
// - Priority 2: collect the bindings before each test, see beforeEachProviders(),
// - Priority 1: create the test injector to be used in beforeEach() and it()
gns.beforeEach(() {
_testInjector.reset();
_currentTestFuture = null;
}, priority: 3);
var completerProvider = bind(AsyncTestCompleter).toFactory(() {
// Mark the test as async when an AsyncTestCompleter is injected in an it(),
if (!_inIt) throw 'AsyncTestCompleter can only be injected in an "it()"';
_isCurrentTestAsync = true;
return new AsyncTestCompleter();
});
gns.beforeEach(() {
_isCurrentTestAsync = false;
_testInjector.addProviders([completerProvider]);
}, priority: 1);
}
/**
* Allows overriding default providers defined in test_injector.js.
*
* The given function must return a list of DI providers.
*
* Example:
*
* beforeEachProviders(() => [
* bind(Compiler).toClass(MockCompiler),
* bind(SomeToken).toValue(myValue),
* ]);
*/
void beforeEachProviders(Function fn) {
gns.beforeEach(() {
var providers = fn();
if (providers != null) _testInjector.addProviders(providers);
}, priority: 2);
}
@Deprecated('using beforeEachProviders instead')
void beforeEachBindings(Function fn) {
beforeEachProviders(fn);
}
void beforeEach(fn) {
if (fn is! FunctionWithParamTokens) fn =
new FunctionWithParamTokens([], fn, false);
gns.beforeEach(() {
_testInjector.execute(fn);
});
}
void _it(gnsFn, name, fn) {
if (fn is! FunctionWithParamTokens) fn =
new FunctionWithParamTokens([], fn, false);
gnsFn(name, () {
_inIt = true;
_testInjector.execute(fn);
_inIt = false;
if (_isCurrentTestAsync) return _currentTestFuture;
});
}
void it(name, fn, [timeOut = null]) {
_it(gns.it, name, fn);
}
void iit(name, fn, [timeOut = null]) {
_it(gns.iit, name, fn);
}
void xit(name, fn, [timeOut = null]) {
_it(gns.xit, name, fn);
}
class SpyFunction extends gns.SpyFunction {
SpyFunction(String name) : super(name);
// TODO: vsavkin move to guinness
andReturn(value) {
return andCallFake(([a0, a1, a2, a3, a4, a5]) => value);
}
}
class SpyObject extends gns.SpyObject {
final Map<String, SpyFunction> _spyFuncs = {};
SpyObject([arg]) {}
SpyFunction spy(String funcName) =>
_spyFuncs.putIfAbsent(funcName, () => new SpyFunction(funcName));
void prop(String funcName, value) {
_spyFuncs
.putIfAbsent("get:${funcName}", () => new SpyFunction(funcName))
.andReturn(value);
}
static stub([object = null, config = null, overrides = null]) {
if (object is! SpyObject) {
overrides = config;
config = object;
object = new SpyObject();
}
var m = StringMapWrapper.merge(config, overrides);
StringMapWrapper.forEach(m, (value, key) {
object.spy(key).andReturn(value);
});
return object;
}
}
bool isInInnerZone() => Zone.current['_innerZone'] == true;
@@ -1,536 +0,0 @@
library angular.core.facade.dom;
import 'dart:html';
import 'package:angular2/platform/common_dom.dart' show setRootDomAdapter;
import 'generic_browser_adapter.dart' show GenericBrowserDomAdapter;
import 'package:angular2/src/facade/browser.dart';
import 'package:angular2/src/facade/lang.dart' show isBlank, isPresent;
import 'dart:js' as js;
// WARNING: Do not expose outside this class. Parsing HTML using this
// sanitizer is a security risk.
class _IdentitySanitizer implements NodeTreeSanitizer {
void sanitizeTree(Node node) {}
}
final _identitySanitizer = new _IdentitySanitizer();
final _keyCodeToKeyMap = const {
8: 'Backspace',
9: 'Tab',
12: 'Clear',
13: 'Enter',
16: 'Shift',
17: 'Control',
18: 'Alt',
19: 'Pause',
20: 'CapsLock',
27: 'Escape',
32: ' ',
33: 'PageUp',
34: 'PageDown',
35: 'End',
36: 'Home',
37: 'ArrowLeft',
38: 'ArrowUp',
39: 'ArrowRight',
40: 'ArrowDown',
45: 'Insert',
46: 'Delete',
65: 'a',
66: 'b',
67: 'c',
68: 'd',
69: 'e',
70: 'f',
71: 'g',
72: 'h',
73: 'i',
74: 'j',
75: 'k',
76: 'l',
77: 'm',
78: 'n',
79: 'o',
80: 'p',
81: 'q',
82: 'r',
83: 's',
84: 't',
85: 'u',
86: 'v',
87: 'w',
88: 'x',
89: 'y',
90: 'z',
91: 'OS',
93: 'ContextMenu',
96: '0',
97: '1',
98: '2',
99: '3',
100: '4',
101: '5',
102: '6',
103: '7',
104: '8',
105: '9',
106: '*',
107: '+',
109: '-',
110: '.',
111: '/',
112: 'F1',
113: 'F2',
114: 'F3',
115: 'F4',
116: 'F5',
117: 'F6',
118: 'F7',
119: 'F8',
120: 'F9',
121: 'F10',
122: 'F11',
123: 'F12',
144: 'NumLock',
145: 'ScrollLock'
};
final bool _supportsTemplateElement = () {
try {
return new TemplateElement().content != null;
} catch (_) {
return false;
}
}();
class BrowserDomAdapter extends GenericBrowserDomAdapter {
js.JsFunction _setProperty;
js.JsFunction _getProperty;
js.JsFunction _hasProperty;
Map<String, bool> _hasPropertyCache;
BrowserDomAdapter() {
_hasPropertyCache = new Map();
_setProperty = js.context.callMethod(
'eval', ['(function(el, prop, value) { el[prop] = value; })']);
_getProperty = js.context
.callMethod('eval', ['(function(el, prop) { return el[prop]; })']);
_hasProperty = js.context
.callMethod('eval', ['(function(el, prop) { return prop in el; })']);
}
static void makeCurrent() {
setRootDomAdapter(new BrowserDomAdapter());
}
bool hasProperty(Element element, String name) {
// Always return true as the serverside version html_adapter.dart does so.
// TODO: change this once we have schema support.
// Note: This nees to kept in sync with html_adapter.dart!
return true;
}
void setProperty(Element element, String name, Object value) {
var cacheKey = "${element.tagName}.${name}";
var hasProperty = this._hasPropertyCache[cacheKey];
if (hasProperty == null) {
hasProperty = this._hasProperty.apply([element, name]);
this._hasPropertyCache[cacheKey] = hasProperty;
}
if (hasProperty) {
_setProperty.apply([element, name, value]);
}
}
getProperty(Element element, String name) =>
_getProperty.apply([element, name]);
invoke(Element element, String methodName, List args) =>
this.getProperty(element, methodName).apply(args, thisArg: element);
// TODO(tbosch): move this into a separate environment class once we have it
logError(error) {
window.console.error(error);
}
log(error) {
window.console.log(error);
}
logGroup(error) {
window.console.group(error);
this.logError(error);
}
logGroupEnd() {
window.console.groupEnd();
}
@override
Map<String, String> get attrToPropMap => const <String, String>{
'class': 'className',
'innerHtml': 'innerHTML',
'readonly': 'readOnly',
'tabindex': 'tabIndex',
};
Element query(String selector) => document.querySelector(selector);
Element querySelector(el, String selector) => el.querySelector(selector);
ElementList querySelectorAll(el, String selector) =>
el.querySelectorAll(selector);
void on(EventTarget element, String event, callback(arg)) {
// due to https://code.google.com/p/dart/issues/detail?id=17406
// addEventListener misses zones so we use element.on.
element.on[event].listen(callback);
}
Function onAndCancel(EventTarget element, String event, callback(arg)) {
// due to https://code.google.com/p/dart/issues/detail?id=17406
// addEventListener misses zones so we use element.on.
var subscription = element.on[event].listen(callback);
return subscription.cancel;
}
void dispatchEvent(EventTarget el, Event evt) {
el.dispatchEvent(evt);
}
MouseEvent createMouseEvent(String eventType) =>
new MouseEvent(eventType, canBubble: true);
Event createEvent(String eventType) => new Event(eventType, canBubble: true);
void preventDefault(Event evt) {
evt.preventDefault();
}
bool isPrevented(Event evt) {
return evt.defaultPrevented;
}
String getInnerHTML(Element el) => el.innerHtml;
String getOuterHTML(Element el) => el.outerHtml;
void setInnerHTML(Element el, String value) {
el.innerHtml = value;
}
String nodeName(Node el) => el.nodeName;
String nodeValue(Node el) => el.nodeValue;
String type(InputElement el) => el.type;
Node content(TemplateElement el) =>
_supportsTemplateElement ? el.content : el;
Node firstChild(el) => el.firstChild;
Node nextSibling(Node el) => el.nextNode;
Element parentElement(Node el) => el.parentNode;
List<Node> childNodes(Node el) => el.childNodes;
List childNodesAsList(Node el) => childNodes(el).toList();
void clearNodes(Node el) {
el.nodes = const [];
}
void appendChild(Node el, Node node) {
el.append(node);
}
void removeChild(el, Node node) {
node.remove();
}
void replaceChild(Node el, Node newNode, Node oldNode) {
oldNode.replaceWith(newNode);
}
ChildNode remove(ChildNode el) {
return el..remove();
}
void insertBefore(Node el, node) {
el.parentNode.insertBefore(node, el);
}
void insertAllBefore(Node el, Iterable<Node> nodes) {
el.parentNode.insertAllBefore(nodes, el);
}
void insertAfter(Node el, Node node) {
el.parentNode.insertBefore(node, el.nextNode);
}
String getText(Node el) => el.text;
void setText(Node el, String value) {
el.text = value;
}
String getValue(el) => el.value;
void setValue(el, String value) {
el.value = value;
}
bool getChecked(InputElement el) => el.checked;
void setChecked(InputElement el, bool isChecked) {
el.checked = isChecked;
}
Comment createComment(String text) {
return new Comment(text);
}
TemplateElement createTemplate(String html) {
var t = new TemplateElement();
// We do not sanitize because templates are part of the application code
// not user code.
t.setInnerHtml(html, treeSanitizer: _identitySanitizer);
return t;
}
Element createElement(String tagName, [HtmlDocument doc = null]) {
if (doc == null) doc = document;
return doc.createElement(tagName);
}
Element createElementNS(String ns, String tagName, [HtmlDocument doc = null]) {
if (doc == null) doc = document;
return doc.createElementNS(ns, tagName);
}
Text createTextNode(String text, [HtmlDocument doc = null]) {
return new Text(text);
}
createScriptTag(String attrName, String attrValue,
[HtmlDocument doc = null]) {
if (doc == null) doc = document;
var el = doc.createElement('SCRIPT');
el.setAttribute(attrName, attrValue);
return el;
}
StyleElement createStyleElement(String css, [HtmlDocument doc = null]) {
if (doc == null) doc = document;
var el = doc.createElement('STYLE');
el.text = css;
return el;
}
ShadowRoot createShadowRoot(Element el) => el.createShadowRoot();
ShadowRoot getShadowRoot(Element el) => el.shadowRoot;
Element getHost(Element el) => (el as ShadowRoot).host;
clone(Node node) => node.clone(true);
List<Node> getElementsByClassName(Element element, String name) =>
element.getElementsByClassName(name);
List<Node> getElementsByTagName(Element element, String name) =>
element.querySelectorAll(name);
List<String> classList(Element element) => element.classes.toList();
void addClass(Element element, String className) {
element.classes.add(className);
}
void removeClass(Element element, String className) {
element.classes.remove(className);
}
bool hasClass(Element element, String className) =>
element.classes.contains(className);
void setStyle(Element element, String styleName, String styleValue) {
element.style.setProperty(styleName, styleValue);
}
bool hasStyle(Element element, String styleName, [String styleValue]) {
var value = this.getStyle(element, styleName);
return isPresent(styleValue) ? value == styleValue : value.length > 0;
}
void removeStyle(Element element, String styleName) {
element.style.removeProperty(styleName);
}
String getStyle(Element element, String styleName) {
return element.style.getPropertyValue(styleName);
}
String tagName(Element element) => element.tagName;
Map<String, String> attributeMap(Element element) {
var result = {};
result.addAll(element.attributes);
// TODO(tbosch): element.getNamespacedAttributes() somehow does not return the attribute value
var xlinkHref = element.getAttributeNS('http://www.w3.org/1999/xlink', 'href');
if (xlinkHref != null) {
result['xlink:href'] = xlinkHref;
}
return result;
}
bool hasAttribute(Element element, String attribute) =>
element.attributes.containsKey(attribute);
bool hasAttributeNS(Element element, String ns, String attribute) =>
element.getAttributeNS(ns, attribute) != null;
String getAttribute(Element element, String attribute) =>
element.getAttribute(attribute);
String getAttributeNS(Element element, String ns, String attribute) =>
element.getAttributeNS(ns, attribute);
void setAttribute(Element element, String name, String value) {
element.setAttribute(name, value);
}
void setAttributeNS(Element element, String ns, String name, String value) {
element.setAttributeNS(ns, name, value);
}
void removeAttribute(Element element, String name) {
//there is no removeAttribute method as of now in Dart:
//https://code.google.com/p/dart/issues/detail?id=19934
element.attributes.remove(name);
}
void removeAttributeNS(Element element, String ns, String name) {
element.getNamespacedAttributes(ns).remove(name);
}
Node templateAwareRoot(Element el) => el is TemplateElement ? el.content : el;
HtmlDocument createHtmlDocument() =>
document.implementation.createHtmlDocument('fakeTitle');
HtmlDocument defaultDoc() => document;
Rectangle getBoundingClientRect(el) => el.getBoundingClientRect();
String getTitle() => document.title;
void setTitle(String newTitle) {
document.title = newTitle;
}
bool elementMatches(n, String selector) =>
n is Element && n.matches(selector);
bool isTemplateElement(Element el) => el is TemplateElement;
bool isTextNode(Node node) => node.nodeType == Node.TEXT_NODE;
bool isCommentNode(Node node) => node.nodeType == Node.COMMENT_NODE;
bool isElementNode(Node node) => node.nodeType == Node.ELEMENT_NODE;
bool hasShadowRoot(Node node) {
return node is Element && node.shadowRoot != null;
}
bool isShadowRoot(Node node) {
return node is ShadowRoot;
}
Node importIntoDoc(Node node) {
return document.importNode(node, true);
}
Node adoptNode(Node node) {
return document.adoptNode(node);
}
String getHref(AnchorElement element) {
return element.href;
}
String getEventKey(KeyboardEvent event) {
int keyCode = event.keyCode;
return _keyCodeToKeyMap.containsKey(keyCode)
? _keyCodeToKeyMap[keyCode]
: 'Unidentified';
}
getGlobalEventTarget(String target) {
if (target == "window") {
return window;
} else if (target == "document") {
return document;
} else if (target == "body") {
return document.body;
}
}
getHistory() {
return window.history;
}
getLocation() {
return window.location;
}
String getBaseHref() {
var href = getBaseElementHref();
if (href == null) {
return null;
}
return _relativePath(href);
}
resetBaseElement() {
baseElement = null;
}
String getUserAgent() {
return window.navigator.userAgent;
}
void setData(Element element, String name, String value) {
element.dataset[name] = value;
}
String getData(Element element, String name) {
return element.dataset[name];
}
getComputedStyle(elem) => elem.getComputedStyle();
// TODO(tbosch): move this into a separate environment class once we have it
setGlobalVar(String path, value) {
var parts = path.split('.');
var obj = js.context;
while (parts.length > 1) {
var name = parts.removeAt(0);
if (obj.hasProperty(name)) {
obj = obj[name];
} else {
obj = obj[name] = new js.JsObject(js.context['Object']);
}
}
obj[parts.removeAt(0)] = value;
}
requestAnimationFrame(callback) {
return window.requestAnimationFrame(callback);
}
cancelAnimationFrame(id) {
window.cancelAnimationFrame(id);
}
num performanceNow() {
return window.performance.now();
}
parse(s) {
throw 'not implemented';
}
}
var baseElement = null;
String getBaseElementHref() {
if (baseElement == null) {
baseElement = document.querySelector('base');
if (baseElement == null) {
return null;
}
}
return baseElement.getAttribute('href');
}
// based on urlUtils.js in AngularJS 1
AnchorElement _urlParsingNode = null;
String _relativePath(String url) {
if (_urlParsingNode == null) {
_urlParsingNode = new AnchorElement();
}
_urlParsingNode.href = url;
var pathname = _urlParsingNode.pathname;
return (pathname[0] == '/') ? pathname : '/${pathname}';
}
-9
View File
@@ -1,9 +0,0 @@
import "package:angular2/platform/browser.dart" show bootstrap;
import "./demo-app/demo-app.dart" show DemoApp;
import "package:angular2/router.dart" show ROUTER_PROVIDERS;
import "./core/platform/browser/browser_adapter.dart" show BrowserDomAdapter;
void main() {
BrowserDomAdapter.makeCurrent();
bootstrap(DemoApp, [ROUTER_PROVIDERS]);
}
-3
View File
@@ -52,9 +52,6 @@ const configuration: { [name: string]: ConfigurationInfo } = {
};
export const customLaunchers: { [name: string]: BrowserLauncherInfo } = {
'DartiumWithWebPlatform': {
base: 'Dartium',
flags: ['--enable-experimental-web-platform-features'] },
'ChromeNoSandbox': {
base: 'Chrome',
flags: ['--no-sandbox'] },
+1 -6
View File
@@ -1,11 +1,6 @@
/**
* This file is Node ES6 and will not be translated to Dart.
*/
const path = require('path');
/**
* Setup TypeScript for our tests.
*/
/** Setup TypeScript for our tests. */
require('ts-node/register');
const E2E_BASE_URL = process.env['E2E_BASE_URL'] || 'http://localhost:4200';
-106
View File
@@ -1,106 +0,0 @@
/// <reference path="../typings/node/node.d.ts" />
/// <reference path="../typings/fs-extra/fs-extra.d.ts" />
/// <reference path="./broccoli.d.ts" />
interface BroccoliCachingWriterPlugin extends BroccoliTree {
listFiles(): string[];
listEntries(): any[];
}
interface Constructor {
new (...args: any[]): BroccoliCachingWriterPlugin;
}
interface CacheEntry {
version: number;
}
import fs = require('fs');
import fse = require('fs-extra');
import path = require('path');
const Plugin: Constructor = require('broccoli-caching-writer');
const exec = require('child_process').exec;
const promiseExec = (cmd: string): Promise<void> => {
return new Promise<void>((resolve, reject) => {
exec(cmd, (err, stdout, stderr) => {
if (err) {
console.error(shortenFormatterOutput(stderr));
reject('Formatting failed.');
} else {
resolve();
}
});
});
};
export default class DartFormatter extends Plugin {
private DARTFMT: string;
private cache: {[filePath: string]: CacheEntry} = Object.create(null);
constructor(inputPaths: any[], options: any) {
super(inputPaths, options);
if (!options.dartSDK) throw new Error("Missing Dart SDK");
this.DARTFMT = options.dartSDK.DARTFMT;
}
build(): Promise<any> {
const dartEntries = this.listEntries().filter(entry => entry.relativePath.match(/\.dart$/));
const changedEntries: any[] = dartEntries.map(entry => {
const filePath = entry.relativePath;
const inputPath = path.join(this.inputPaths[0], filePath);
const cachePath = path.join(this.cachePath, filePath);
if (!this.cache[inputPath]) {
this.cache[inputPath] = { version: entry.mtime };
} else if (this.cache[inputPath].version >= entry.mtime) {
// Ignore this, cache is as young as input.
return;
}
fse.copySync(inputPath, cachePath);
}).filter(x => !!x);
return Promise.all(
changedEntries.map(entry => {
const filePath = entry.relativePath;
const cachePath = path.join(this.cachePath, filePath);
return promiseExec(this.DARTFMT + ' ' + cachePath);
}))
.then(() => Promise.all(
Object.keys(this.cache).map(filePath => {
const cachePath = filePath.replace(this.inputPaths[0], this.cachePath);
const outputPath = filePath.replace(this.inputPaths[0], this.outputPath);
return new Promise(resolve => {
fse.mkdirsSync(path.dirname(outputPath));
fs.linkSync(cachePath, outputPath);
resolve();
});
})
));
}
}
var ARROW_LINE = /^(\s+)\^+/;
var BEFORE_CHARS = 15;
var stripAnsi = require('strip-ansi');
function shortenFormatterOutput(formatterOutput) {
var lines = formatterOutput.split('\n');
var match, line;
for (var i = 0; i < lines.length; i += 1) {
line = lines[i];
if (match = stripAnsi(line).match(ARROW_LINE)) {
let leadingWhitespace = match[1].length;
let leadingCodeChars = Math.min(leadingWhitespace, BEFORE_CHARS);
lines[i] = line.substr(leadingWhitespace - leadingCodeChars);
lines[i - 1] = lines[i - 1].substr(leadingWhitespace - leadingCodeChars, 80) + '…';
}
}
return lines.join('\n');
}
-98
View File
@@ -1,98 +0,0 @@
/// <reference path="../typings/node/node.d.ts" />
/// <reference path="../typings/fs-extra/fs-extra.d.ts" />
/// <reference path="./broccoli.d.ts" />
interface BroccoliCachingWriterPlugin extends BroccoliTree {
listFiles(): string[];
listEntries(): any[];
}
interface Constructor {
new (...args: any[]): BroccoliCachingWriterPlugin;
}
interface CacheEntry {
version: number;
}
import fs = require('fs');
import fse = require('fs-extra');
import path = require('path');
const Plugin: Constructor = require('broccoli-caching-writer');
import TS2Dart = require('ts2dart');
export default class TSToDartTranspiler extends Plugin {
private transpiler: TS2Dart.Transpiler;
private additionalFiles: string[];
private basePath: string;
private cache: {[filePath: string]: CacheEntry} = Object.create(null);
constructor(inputPaths: any[], public options: any /*ts2dart.TranspilerOptions*/) {
super(inputPaths, {});
// Additional files to include in the transpile call. These files could include, e.g.,
// .d.ts files. They will always be included in the transpile call below, even if they
// weren't modified.
this.additionalFiles = options.additionalFiles || [];
// Delete additionalFiles as the transpiler does not support that option.
delete options.additionalFiles;
this.basePath = options.basePath;
this.transpiler = new TS2Dart.Transpiler(options);
}
build(): Promise<any> {
const inputPath = this.inputPaths[0];
const basePath = this.basePath || inputPath;
const getDartFilePath = (path: string) => path.replace(/((\.js)|(\.ts))$/i, '.dart');
// List all the changed TS files. The `toEmit` variable will contain the list
// of relative paths to the basePath of files that have changed.
// For an initial run this is basically all the files.
const toEmit = this.listEntries()
.filter(entry => entry.relativePath.match(/\.ts$/) && !entry.relativePath.match(/\.d\.ts$/))
.map(entry => {
const fullPath = path.resolve(inputPath, entry.relativePath);
const dartInputFilePath = getDartFilePath(fullPath);
// If a dart file exist, just ignore the TS source.
if (fs.existsSync(dartInputFilePath)) {
return;
}
if (!this.cache[fullPath]) {
this.cache[fullPath] = { version: entry.mtime };
} else if (this.cache[fullPath].version >= entry.mtime) {
// Do nothing. Cache is as recent as the original input.
return;
}
return path.normalize(fullPath.replace(inputPath, basePath));
})
.filter(x => !!x);
this.transpiler.transpile(this.additionalFiles.concat(toEmit), this.cachePath);
const dirs: {[p: string]: boolean} = Object.create(null);
// Make a symbolic link in the output for the cache.
return Promise.all(
Object.keys(this.cache).map(filePath => {
return new Promise(resolve => {
const cachePath = getDartFilePath(filePath.replace(inputPath, this.cachePath));
const outputPath = getDartFilePath(filePath.replace(inputPath, this.outputPath));
const dirPath = path.dirname(outputPath);
if (!dirs[dirPath]) {
dirs[dirPath] = true;
fse.mkdirsSync(path.dirname(outputPath));
}
fs.linkSync(cachePath, outputPath);
resolve();
});
})
);
}
}
-51
View File
@@ -1,51 +0,0 @@
/// <reference path="../typings/node/node.d.ts" />
// TODO(hansl): Get rid of this file. It's unneeded.
const which = require('which');
const child_process = require('child_process');
export type DartSdkExecutableMap = {
ANALYZER: string,
DARTDOCGEN: string,
DARTFMT: string,
PUB: string,
VM: string,
};
/**
* Return a map of {EXECUTABLE => Path} for the Dart SDK.
* The executables are different on Windows / Unix. Returns null if the Dart SDK cannot be
* found.
*/
export function detect(): DartSdkExecutableMap {
let sdk: DartSdkExecutableMap;
try {
const dartExecutable = which.sync('dart');
if (process.platform === 'win32') {
sdk = {
ANALYZER: 'dartanalyzer.bat',
DARTDOCGEN: 'dartdoc.bat',
DARTFMT: 'dartfmt.bat',
PUB: 'pub.bat',
VM: 'dart.exe'
};
} else {
sdk = {
ANALYZER: 'dartanalyzer',
DARTDOCGEN: 'dartdoc',
DARTFMT: 'dartfmt',
PUB: 'pub',
VM: 'dart'
};
}
console.log('Dart SDK detected:', dartExecutable);
console.log('- dart: ' + child_process.spawnSync(sdk.VM, ['--version']).stderr.toString().replace(/\n/g, ''));
console.log('- pub: ' + child_process.spawnSync(sdk.PUB, ['--version']).stdout.toString().replace(/\n/g, ''));
return sdk;
} catch (e) {
console.log('Dart SDK is not available.');
return null;
}
}
-249
View File
@@ -1,249 +0,0 @@
/// <reference path="../typings/es6-promise/es6-promise.d.ts" />
/// <reference path="../typings/node/node.d.ts" />
import {travisFoldStart} from '../travis/fold';
import readline = require('readline');
import child_process = require('child_process');
import path = require('path');
import fs = require('fs');
const glob = require('glob');
const yaml = require('js-yaml');
const tempFile = '_analyzer.dart';
/**
* Call the Dart Analyzer on every dart files below.
* Specialized for Travis.
*
* @param dir The directory to scan.
* @param command The command to use for dartanalyzer.
* @param use_ddc Enable strong static type checking (see https://goo.gl/DqcBsw).
*/
export function analyze(dir: string, command: string, use_ddc: boolean = false): Promise<any> {
var travisFoldEnd = travisFoldStart(`dartanalyzer-${use_ddc ? 'ddc' : ''}-${dir}`);
var pubspecContents = fs.readFileSync(path.join(dir, 'pubspec.yaml'));
var pubspec = yaml.safeLoad(pubspecContents);
var packageName = pubspec.name;
var libFiles = [].slice.call(glob.sync('lib/**/*.dart', {cwd: dir}));
var webFiles = [].slice.call(glob.sync('web/**/*.dart', {cwd: dir}));
var testFiles = [].slice.call(glob.sync('test/**/*_spec.dart', {cwd: dir}));
var analyzeFile = ['library _analyzer;'];
libFiles.concat(testFiles).concat(webFiles).forEach((fileName, index) => {
if (fileName !== tempFile && fileName.indexOf("/packages/") === -1) {
if (fileName.indexOf('lib') == 0) {
fileName = 'package:' + packageName + '/' +
path.relative('lib', fileName).replace(/\\/g, '/');
}
analyzeFile.push('import "' + fileName + '" as mod' + index + ';');
}
});
fs.writeFileSync(path.join(dir, tempFile), analyzeFile.join('\n'));
return new Promise<void>((resolve, reject) => {
_analyze(command, dir, resolve, use_ddc);
});
}
function _analyze(command, dirName, done, useDdc) {
// TODO remove --package-warnings once dartanalyzer handles transitive libraries
var flags = ['--fatal-warnings', '--format=machine'];
if (useDdc) {
console.log('Using DDC analyzer to analyze', dirName);
flags.push('--strong');
}
var args = flags.concat(tempFile);
var stream = child_process.spawn(command, args, {
// inherit stdin and stderr, but filter stdout
stdio: [process.stdin, process.stdout, 'pipe'],
cwd: dirName
});
// Filter out unused imports from our generated file.
// We don't reexports from the generated file
// as this could lead to name clashes when two files
// export the same thing.
var rl =
readline.createInterface({input: stream.stderr, output: process.stdout, terminal: false});
var hintCount = 0;
var errorCount = 0;
var warningCount = 0;
rl.on('line', function(line) {
if (line == "find: > bin [: No such file or directory") {
// Skip bad output from Dart SDK .bat files on Windows
return;
}
var parsedLine = _AnalyzerOutputLine.parse(line);
if (!parsedLine) {
errorCount++;
console.log('Unexpected output: ' + line);
return;
}
// TODO remove once dartanalyzer handles transitive libraries
// skip errors in third-party packages
if (parsedLine.sourcePath.indexOf(dirName) == -1) {
return;
}
if (parsedLine.shouldIgnore()) {
return;
}
if (parsedLine.isHint) {
hintCount++;
} else if (parsedLine.isWarning) {
warningCount++;
} else {
errorCount++;
}
console.log(dirName + ':' + parsedLine);
});
stream.on('close', function() {
var error;
var report = [];
if (errorCount > 0) {
report.push(errorCount + ' error(s)');
}
if (warningCount > 0) {
report.push(warningCount + ' warning(s)');
}
if (hintCount > 0) {
report.push(hintCount + ' hint(s)');
}
if (report.length > 0) {
error = 'Dartanalyzer showed ' + report.join(', ');
}
done(error);
});
stream.on('error', function(error) { done(error); });
}
// See https://github.com/dart-lang/analyzer_cli/blob/master/lib/src/error_formatter.dart
class _AnalyzerOutputLine {
severity: string;
errorType: string;
errorCode: string;
sourcePath: string;
lineNum: number;
colNum: string;
asciiLineLength: number;
errorMsg: string;
isError: boolean;
isHint: boolean;
isWarning: boolean;
constructor(result: any[]) {
this.severity = result[1];
this.errorType = result[2];
this.errorCode = result[3];
this.sourcePath = result[4];
this.lineNum = parseInt(result[5], 10);
this.colNum = result[6];
this.asciiLineLength = parseInt(result[7], 10);
this.errorMsg = result[8];
this.isError = Boolean(this.severity.match(/ERROR/i));
this.isHint = Boolean(this.severity.match(/INFO/i));
this.isWarning = Boolean(this.severity.match(/WARNING/i));
}
static parse(line: string) {
const result = this._analyzerParseRegExp.exec(line);
return result ? new this(result) : null;
}
private static _analyzerParseRegExp =
new RegExp('([^\|]+)\\|' + // #1, severity (NONE, INFO, WARNING, ERROR)
'([^\|]+)\\|' + // #2, errorCode.type (HINT, *_WARNING, *_ERROR, etc)
'([^\|]+)\\|' + // #3, errorCode (UNUSED_IMPORT, UNUSED_CATCH_STACK, etc)
'([^\|]+[^\|\\\\])\\|' + // #4, sourcePath with '|' chars backslash-escaped.
'([^\|]+)\\|' + // #5, line number
'([^\|]+)\\|' + // #6, column number
'([^\|]+)\\|' + // #7, length of the ASCII line to draw
'(.*)$'); // #8, error message
/* Maps file path (as string) to file source (an array of strings, one per line). */
private static _cache = {};
private static ERR_NO_SOURCE = '(Could not find source line).';
toString() {
var sourceLine = this._getSourceLine();
var lineText = _AnalyzerOutputLine.ERR_NO_SOURCE;
if (sourceLine) {
var repeat = function(str, num) {
if (str.repeat) return str.repeat(num);
return Array.prototype.join.call({length: num}, str);
};
lineText =
'\n' + sourceLine + '\n' + repeat(' ', this.colNum) + repeat('^', this.asciiLineLength);
}
return '[' + this.severity + '] type: ' + this.errorType + ' ' +
this.errorMsg + ' (' + this.sourcePath + ', line ' + this.lineNum +
', col ' + this.colNum + ')' + lineText;
}
shouldIgnore() {
if (this.errorCode.match(/UNUSED_IMPORT/i)) {
if (this.sourcePath.match(/_analyzer\.dart/)) {
return true;
}
// TODO remove it once ts2dart properly generates abstract getters
if (this.errorMsg.match(/unimplemented/)) {
return true;
}
}
if (this.errorCode.match(/DEPRECATED_MEMBER_USE/i)) {
return true;
}
// TODO: https://github.com/angular/ts2dart/issues/168
if (this.errorCode.match(/UNUSED_CATCH_STACK/i)) {
return true;
}
// TODOs shouldn't break our build...
if (this.errorCode.match(/TODO/i)) {
return true;
}
// Don't worry about hints in generated files.
if (this.isHint && this.sourcePath.match(/generated/i)) {
return true;
}
return false;
}
// Reads the source file for the Analyzer output, caching it for future use.
_getSourceLine() {
var cache = _AnalyzerOutputLine._cache;
var sourceLines = null;
if (cache.hasOwnProperty(this.sourcePath)) {
sourceLines = cache[this.sourcePath];
} else {
try {
sourceLines = String(fs.readFileSync(this.sourcePath));
sourceLines = sourceLines.split('\n');
} catch (e) {
sourceLines = null;
} finally {
// Even if this fails, cache `null` so we don't try again.
cache[this.sourcePath] = sourceLines;
}
}
return (sourceLines && this.lineNum <= sourceLines.length) ? sourceLines[this.lineNum - 1] : null;
}
};