From 2aaa8f11d6436968f3c338298f102dcd78adadc4 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Mon, 19 Dec 2016 22:40:48 -0800 Subject: [PATCH 1/3] test(filter): enable type inference in marble diagram - relates to #1633 --- spec/operators/filter-spec.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/spec/operators/filter-spec.ts b/spec/operators/filter-spec.ts index bb3ec60f1a..4c95609d7f 100644 --- a/spec/operators/filter-spec.ts +++ b/spec/operators/filter-spec.ts @@ -1,6 +1,12 @@ import {expect} from 'chai'; import * as Rx from '../../dist/cjs/Rx'; -declare const {hot, cold, asDiagram, expectObservable, expectSubscriptions}; +import marbleTestingSignature = require('../helpers/marble-testing'); // tslint:disable-line:no-require-imports + +declare const { asDiagram }; +declare const hot: typeof marbleTestingSignature.hot; +declare const cold: typeof marbleTestingSignature.cold; +declare const expectObservable: typeof marbleTestingSignature.expectObservable; +declare const expectSubscriptions: typeof marbleTestingSignature.expectSubscriptions; const Observable = Rx.Observable; From 716377dc720cdb197afe1a7b08d9a666e8d07039 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Sat, 4 Feb 2017 13:51:12 -0800 Subject: [PATCH 2/3] chore(danger): setup initial dangerfile --- .travis.yml | 3 ++- dangerfile.js | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 dangerfile.js diff --git a/.travis.yml b/.travis.yml index e44d168e4c..9ac8e7725f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ cache: env: matrix: - NODE_VER=4 FULL_VALIDATE=false - - NODE_VER=6 FULL_VALIDATE=true alias grunt=./node_modules/grunt-cli/bin/grunt + - NODE_VER=6 FULL_VALIDATE=true alias grunt=./node_modules/grunt-cli/bin/grunt danger=./node_modules/danger/distribution/danger - NODE_VER=7 FULL_VALIDATE=false matrix: fast_finish: true @@ -23,6 +23,7 @@ before_install: - nvm install $NODE_VER - npm install -g npm@4 && node -v && npm -v - if [ "$FULL_VALIDATE" == "true" ]; then npm install grunt@0.4.1 grunt-cli grunt-contrib-connect grunt-run; fi + - if [ "$FULL_VALIDATE" == "true" ] && [ -n "DANGER_GITHUB_API_TOKEN" ]; then npm install danger && danger; fi install: - npm install diff --git a/dangerfile.js b/dangerfile.js new file mode 100644 index 0000000000..5c0335b334 --- /dev/null +++ b/dangerfile.js @@ -0,0 +1,56 @@ +var fs = require('fs'); +var path = require('path'); +var _ = require('lodash'); + +//simple regex matcher to detect usage of helper function and its type signature +var hotMatch = /\bhot\(/gi; +var hotSignatureMatch = /\bdeclare const hot: typeof/gi; + +var coldMatch = /\bcold\(/gi; +var coldSignatureMatch = /\bdeclare const cold: typeof/gi; + +var errorCount = 0; + +// Warn when PR size is large +var bigPRThreshold = 600; +if (danger.github.pr.additions + danger.github.pr.deletions > bigPRThreshold) { + warn(':exclamation: Big PR (' + ++errorCount + ')'); + markdown('> (' + errorCount + ') : Pull Request size seems relatively large. If Pull Request contains multiple changes, split each into separate PR will helps faster, easier review.'); +} + +// Check test exclusion (.only) is included +var modifiedSpecFiles = danger.git.modified_files.filter(function (filePath) { + return filePath.match(/-spec.(js|jsx|ts|tsx)$/gi); +}); + +var testFilesIncludeExclusion = modifiedSpecFiles.reduce(function (acc, value) { + var content = fs.readFileSync(value).toString(); + var invalid = _.includes(content, 'it.only') || _.includes(content, 'describe.only'); + if (invalid) { + acc.push(path.basename(value)); + } + return acc; +}, []); + +if (testFilesIncludeExclusion.length > 0) { + fail('an \`only\` was left in tests (' + testFilesIncludeExclusion + ')'); +} + +// Check test cases missing type signature import for test marble helper functions +var testFilesMissingTypes = modifiedSpecFiles.reduce(function (acc, value) { + var content = fs.readFileSync(value).toString(); + + var hotFnMatches = content.match(hotMatch) && content.match(hotSignatureMatch); + var coldFnMatches = content.match(coldMatch) && content.match(coldSignatureMatch); + + if (!hotFnMatches || !coldFnMatches) { + acc.push(path.basename(value)); + } + + return acc; +}, []); + +if (testFilesMissingTypes.length > 0) { + fail('missing type definition import in tests (' + testFilesMissingTypes + ') (' + ++errorCount + ')'); + markdown('> (' + errorCount + ') : It seems updated test cases uses test scheduler interface `hot`, `cold` but miss to import type signature for those.'); +} \ No newline at end of file From e338ca61585f5e34833139a18521b017408444a4 Mon Sep 17 00:00:00 2001 From: OJ Kwon Date: Sat, 4 Feb 2017 15:04:51 -0800 Subject: [PATCH 3/3] style(tslint): update code lint, hint friendly --- package.json | 2 +- src/observable/DeferObservable.ts | 2 +- src/observable/FromEventPatternObservable.ts | 4 ++-- src/observable/FromObservable.ts | 4 ++-- src/observable/dom/WebSocketSubject.ts | 2 +- src/operator/catch.ts | 24 ++++++++++---------- src/operator/concatMapTo.ts | 2 +- src/operator/distinct.ts | 6 ++--- src/operator/distinctUntilChanged.ts | 4 ++-- src/operator/distinctUntilKeyChanged.ts | 6 ++--- src/operator/every.ts | 2 +- src/operator/materialize.ts | 2 +- src/operator/max.ts | 6 ++--- src/operator/mergeMap.ts | 2 +- src/operator/min.ts | 6 ++--- src/operator/zip.ts | 8 +++---- 16 files changed, 41 insertions(+), 41 deletions(-) diff --git a/package.json b/package.json index af64c6692f..a02fb7b450 100644 --- a/package.json +++ b/package.json @@ -189,7 +189,7 @@ "sinon-chai": "^2.8.0", "source-map-support": "^0.4.0", "tslib": "^1.5.0", - "tslint": "^4.2.0", + "tslint": "^4.4.2", "typescript": "~2.0.6", "typings": "^2.0.0", "validate-commit-msg": "^2.3.1", diff --git a/src/observable/DeferObservable.ts b/src/observable/DeferObservable.ts index 23ff9ba112..17bff114c0 100644 --- a/src/observable/DeferObservable.ts +++ b/src/observable/DeferObservable.ts @@ -38,7 +38,7 @@ export class DeferObservable extends Observable { * } * }); * clicksOrInterval.subscribe(x => console.log(x)); - * + * * // Results in the following behavior: * // If the result of Math.random() is greater than 0.5 it will listen * // for clicks anywhere on the "document"; when document is clicked it diff --git a/src/observable/FromEventPatternObservable.ts b/src/observable/FromEventPatternObservable.ts index 5a20c8e00d..4be3ebcd2f 100644 --- a/src/observable/FromEventPatternObservable.ts +++ b/src/observable/FromEventPatternObservable.ts @@ -29,11 +29,11 @@ export class FromEventPatternObservable extends Observable { * function addClickHandler(handler) { * document.addEventListener('click', handler); * } - *   + * * function removeClickHandler(handler) { * document.removeEventListener('click', handler); * } - *   + * * var clicks = Rx.Observable.fromEventPattern( * addClickHandler, * removeClickHandler diff --git a/src/observable/FromObservable.ts b/src/observable/FromObservable.ts index 8e9159a43a..03d9306639 100644 --- a/src/observable/FromObservable.ts +++ b/src/observable/FromObservable.ts @@ -59,7 +59,7 @@ export class FromObservable extends Observable { * i = 2 * i; // double it * } * } - *   + * * var iterator = generateDoubles(3); * var result = Rx.Observable.from(iterator).take(10); * result.subscribe(x => console.log(x)); @@ -71,7 +71,7 @@ export class FromObservable extends Observable { * @see {@link fromEvent} * @see {@link fromEventPattern} * @see {@link fromPromise} - *   + * * @param {ObservableInput} ish A subscribable object, a Promise, an * Observable-like, an Array, an iterable or an array-like object to be * converted. diff --git a/src/observable/dom/WebSocketSubject.ts b/src/observable/dom/WebSocketSubject.ts index 3cae0c1c82..4f92a27f14 100644 --- a/src/observable/dom/WebSocketSubject.ts +++ b/src/observable/dom/WebSocketSubject.ts @@ -57,7 +57,7 @@ export class WebSocketSubject extends AnonymousSubject { * @example Wraps WebSocket from nodejs-websocket (using node.js) * * import { w3cwebsocket } from 'websocket'; - * + * * let socket = new WebSocketSubject({ * url: 'ws://localhost:8081', * WebSocketCtor: w3cwebsocket diff --git a/src/operator/catch.ts b/src/operator/catch.ts index 730f54a309..2fb91ffbd5 100644 --- a/src/operator/catch.ts +++ b/src/operator/catch.ts @@ -9,15 +9,15 @@ import { subscribeToResult } from '../util/subscribeToResult'; * Catches errors on the observable to be handled by returning a new observable or throwing an error. * * - * + * * @example Continues with a different Observable when there's an error - * + * * Observable.of(1, 2, 3, 4, 5) - * .map(n => { + * .map(n => { * if (n == 4) { * throw 'four!'; * } - * return n; + * return n; * }) * .catch(err => Observable.of('I', 'II', 'III', 'IV', 'V')) * .subscribe(x => console.log(x)); @@ -26,25 +26,25 @@ import { subscribeToResult } from '../util/subscribeToResult'; * @example Retries the caught source Observable again in case of error, similar to retry() operator * * Observable.of(1, 2, 3, 4, 5) - * .map(n => { + * .map(n => { * if (n === 4) { - * throw 'four!'; + * throw 'four!'; * } - * return n; + * return n; * }) * .catch((err, caught) => caught) * .take(30) * .subscribe(x => console.log(x)); * // 1, 2, 3, 1, 2, 3, ... - * + * * @example Throws a new error when the source Observable throws an error - * + * * Observable.of(1, 2, 3, 4, 5) - * .map(n => { + * .map(n => { * if (n == 4) { * throw 'four!'; * } - * return n; + * return n; * }) * .catch(err => { * throw 'error in source. Details: ' + err; @@ -54,7 +54,7 @@ import { subscribeToResult } from '../util/subscribeToResult'; * err => console.log(err) * ); * // 1, 2, 3, error in source. Details: four! - * + * * @param {function} selector a function that takes as arguments `err`, which is the error, and `caught`, which * is the source observable, in case you'd like to "retry" that observable by returning it again. Whatever observable * is returned by the `selector` will be used to continue the observable chain. diff --git a/src/operator/concatMapTo.ts b/src/operator/concatMapTo.ts index 03182ea7a1..e1b468c1f2 100644 --- a/src/operator/concatMapTo.ts +++ b/src/operator/concatMapTo.ts @@ -39,7 +39,7 @@ export function concatMapTo(this: Observable, observable: Observable * // For every click on the "document" it will emit values 0 to 3 spaced * // on a 1000ms interval * // one click = 1000ms-> 0 -1000ms-> 1 -1000ms-> 2 -1000ms-> 3 - * + * * @see {@link concat} * @see {@link concatAll} * @see {@link concatMap} diff --git a/src/operator/distinct.ts b/src/operator/distinct.ts index 36f99bae07..b89ff14289 100644 --- a/src/operator/distinct.ts +++ b/src/operator/distinct.ts @@ -38,14 +38,14 @@ import { ISet, Set } from '../util/Set'; * { age: 5, name: 'Foo'}) * .distinct((p: Person) => p.name) * .subscribe(x => console.log(x)); - * + * * // displays: * // { age: 4, name: 'Foo' } * // { age: 7, name: 'Bar' } - * + * * @see {@link distinctUntilChanged} * @see {@link distinctUntilKeyChanged} - * + * * @param {function} [keySelector] optional function to select which value you want to check as distinct. * @param {Observable} [flushes] optional Observable for flushing the internal HashSet of the operator. * @return {Observable} an Observable that emits items from the source Observable with distinct values. diff --git a/src/operator/distinctUntilChanged.ts b/src/operator/distinctUntilChanged.ts index 2c9a06288c..06e73d6cb5 100644 --- a/src/operator/distinctUntilChanged.ts +++ b/src/operator/distinctUntilChanged.ts @@ -35,12 +35,12 @@ export function distinctUntilChanged(this: Observable, compare: (x: K, * { age: 6, name: 'Foo'}) * .distinctUntilChanged((p: Person, q: Person) => p.name === q.name) * .subscribe(x => console.log(x)); - * + * * // displays: * // { age: 4, name: 'Foo' } * // { age: 7, name: 'Bar' } * // { age: 5, name: 'Foo' } - * + * * @see {@link distinct} * @see {@link distinctUntilKeyChanged} * diff --git a/src/operator/distinctUntilKeyChanged.ts b/src/operator/distinctUntilKeyChanged.ts index fd6bbff8af..02ee938219 100644 --- a/src/operator/distinctUntilKeyChanged.ts +++ b/src/operator/distinctUntilKeyChanged.ts @@ -9,13 +9,13 @@ export function distinctUntilKeyChanged(this: Observable, key: string, /** * Returns an Observable that emits all items emitted by the source Observable that are distinct by comparison from the previous item, * using a property accessed by using the key provided to check if the two items are distinct. - * + * * If a comparator function is provided, then it will be called for each item to test for whether or not that value should be emitted. - * + * * If a comparator function is not provided, an equality check is used by default. * * @example An example comparing the name of persons - * + * * interface Person { * age: number, * name: string diff --git a/src/operator/every.ts b/src/operator/every.ts index 098e8056b2..963dae16dd 100644 --- a/src/operator/every.ts +++ b/src/operator/every.ts @@ -10,7 +10,7 @@ import { Subscriber } from '../Subscriber'; * Observable.of(1, 2, 3, 4, 5, 6) * .every(x => x < 5) * .subscribe(x => console.log(x)); // -> false - * + * * @param {function} predicate a function for determining if an item meets a specified condition. * @param {any} [thisArg] optional object to use for `this` in the callback * @return {Observable} an Observable of booleans that determines if all items of the source Observable meet the condition specified. diff --git a/src/operator/materialize.ts b/src/operator/materialize.ts index d302fbfb57..2ea2c4d393 100644 --- a/src/operator/materialize.ts +++ b/src/operator/materialize.ts @@ -35,7 +35,7 @@ import { Notification } from '../Notification'; * // - Notification {kind: "N", value: "A", error: undefined, hasValue: true} * // - Notification {kind: "N", value: "B", error: undefined, hasValue: true} * // - Notification {kind: "E", value: undefined, error: TypeError: - * // x.toUpperCase is not a function at MapSubscriber.letters.map.x + * // x.toUpperCase is not a function at MapSubscriber.letters.map.x * // [as project] (http://1…, hasValue: false} * * @see {@link Notification} diff --git a/src/operator/max.ts b/src/operator/max.ts index 760e8c57b3..fa9b53970b 100644 --- a/src/operator/max.ts +++ b/src/operator/max.ts @@ -11,7 +11,7 @@ import { ReduceOperator } from './reduce'; * Rx.Observable.of(5, 4, 7, 2, 8) * .max() * .subscribe(x => console.log(x)); // -> 8 - * + * * @example Use a comparer function to get the maximal item * interface Person { * age: number, @@ -23,9 +23,9 @@ import { ReduceOperator } from './reduce'; * .max((a: Person, b: Person) => a.age < b.age ? -1 : 1) * .subscribe((x: Person) => console.log(x.name)); // -> 'Beer' * } - * + * * @see {@link min} - * + * * @param {Function} optional comparer function that it will use instead of its default to compare the value of two * items. * @return {Observable} an Observable that emits item with the largest value. diff --git a/src/operator/mergeMap.ts b/src/operator/mergeMap.ts index e80ef84309..89f64936da 100644 --- a/src/operator/mergeMap.ts +++ b/src/operator/mergeMap.ts @@ -40,7 +40,7 @@ export function mergeMap(this: Observable, project: (value: T, index * // b1 * // c1 * // continues to list a,b,c with respective ascending integers - * + * * @see {@link concatMap} * @see {@link exhaustMap} * @see {@link merge} diff --git a/src/operator/min.ts b/src/operator/min.ts index 3110c02501..c0bcd9cbbb 100644 --- a/src/operator/min.ts +++ b/src/operator/min.ts @@ -11,7 +11,7 @@ import { ReduceOperator } from './reduce'; * Rx.Observable.of(5, 4, 7, 2, 8) * .min() * .subscribe(x => console.log(x)); // -> 2 - * + * * @example Use a comparer function to get the minimal item * interface Person { * age: number, @@ -23,9 +23,9 @@ import { ReduceOperator } from './reduce'; * .min( (a: Person, b: Person) => a.age < b.age ? -1 : 1) * .subscribe((x: Person) => console.log(x.name)); // -> 'Bar' * } - * + * * @see {@link max} - * + * * @param {Function} optional comparer function that it will use instead of its default to compare the value of two items. * @return {Observable} an Observable that emits item with the smallest value. * @method min diff --git a/src/operator/zip.ts b/src/operator/zip.ts index 46ec6a906c..b979956bb5 100644 --- a/src/operator/zip.ts +++ b/src/operator/zip.ts @@ -61,10 +61,10 @@ export function zipStatic(...observables: Array | ((...v /* tslint:enable:max-line-length */ /** - * Combines multiple Observables to create an Observable whose values are calculated from the values, in order, of each + * Combines multiple Observables to create an Observable whose values are calculated from the values, in order, of each * of its input Observables. * - * If the latest parameter is a function, this function is used to compute the created value from the input values. + * If the latest parameter is a function, this function is used to compute the created value from the input values. * Otherwise, an array of the input values is returned. * * @example Combine age and name from different sources @@ -80,11 +80,11 @@ export function zipStatic(...observables: Array | ((...v * (age: number, name: string, isDev: boolean) => ({ age, name, isDev })) * .subscribe(x => console.log(x)); * - * // outputs + * // outputs * // { age: 7, name: 'Foo', isDev: true } * // { age: 5, name: 'Bar', isDev: true } * // { age: 9, name: 'Beer', isDev: false } - * + * * @param observables * @return {Observable} * @static true