Skip to content

Commit

Permalink
[cli] New outdated command (#4171)
Browse files Browse the repository at this point in the history
* create base structure of outdated cli

* pull cached and installed libdefs

* format into table

* add more comments

* use a different func

* can pull definitions for comparison

* add details of next steps

* can render outdated list of libs with changes not in scopes

* stubs and scopes working

* unmock libs for testing

* clean up docs

* add docs page

* add test
  • Loading branch information
Brianzchen committed Feb 6, 2022
1 parent edaf30f commit da69682
Show file tree
Hide file tree
Showing 19 changed files with 791 additions and 99 deletions.
1 change: 1 addition & 0 deletions cli/package.json
Expand Up @@ -26,6 +26,7 @@
"prepublishOnly": "cp ../README.md .",
"test": "yarn clean && yarn build && yarn test-quick",
"test-quick": "jest && yarn lint && yarn flow",
"test:watch": "yarn clean && yarn build && yarn jest --watch",
"watch": "mkdirp dist && babel --source-maps --watch=./src --out-dir=./dist"
},
"dependencies": {
Expand Down
16 changes: 9 additions & 7 deletions cli/src/cli.js
Expand Up @@ -2,16 +2,17 @@
// @flow

import yargs from 'yargs';
import {fs, path} from './lib/node.js';
import {fs, path} from './lib/node';

import * as Install from './commands/install.js';
import * as Install from './commands/install';
import * as CreateDef from './commands/create-def';
import * as CreateStub from './commands/create-stub.js';
import * as RunTests from './commands/runTests.js';
import * as Search from './commands/search.js';
import * as Update from './commands/update.js';
import * as CreateStub from './commands/create-stub';
import * as Outdated from './commands/outdated';
import * as RunTests from './commands/runTests';
import * as Search from './commands/search';
import * as Update from './commands/update';
import * as UpdateCache from './commands/update-cache';
import * as ValidateDefs from './commands/validateDefs.js';
import * as ValidateDefs from './commands/validateDefs';

import type {Argv} from 'yargs';
import typeof Yargs from 'yargs';
Expand All @@ -30,6 +31,7 @@ export function runCLI() {
CreateDef,
CreateStub,
Install,
Outdated,
RunTests,
Search,
Update,
Expand Down
@@ -0,0 +1,3 @@
{
"compatibleCLIRange": ">=*.*.*"
}
@@ -0,0 +1,187 @@
/** @flow */
import _ from 'underscore';

/**
* _.find
*/
_.find([1, 2, 3], x => x * 1 == 3);
// $FlowExpectedError number cannot be compared to string
_.find([1, 2, 3], x => x == 'a');
// $FlowExpectedError number. This type is incompatible with function type.
_.find([1, 2, 3], 1);
// $FlowExpectedError property `y`. Property not found in object literal
_.find([{x:1}, {x:2}, {x:3}], v => v.y == 3);
_.find([{x:1}, {x:2}, {x:3}], v => v.x == 3);

/**
* _.findWhere
*/
_.findWhere([{x: 1}, {y: 2}], {x: 2});
// $FlowExpectedError number. This type is incompatible with function type.
_.findWhere([{x: 1}, {y: 2}], 1);
// XXX: It would be nice if Flow could catch this error.
// See https://github.com/facebook/flow/issues/946
_.findWhere([{x:1}, {x:2}, {x:3}], v => v.x == 3);


/**
* _.clone
*/
_.clone({a: 1}).a == 1;
// $FlowExpectedError property `b`. Property not found in object literal
_.clone({a: 1}).b == 1
// $FlowExpectedError number. This type is incompatible with function type.
_.clone({a: 1}).a == 'c';

/**
* _.isEqual
*/
_.isEqual('a', 'b');
_.isEqual({x: 1}, {y: 2});

// Flow considers these compatible with isEqual(a: any, b: any).
// Reasonable people disagree about whether these should be considered legal calls.
// See https://github.com/splodingsocks/FlowTyped/pull/1#issuecomment-149345275
// and https://github.com/facebook/flow/issues/956
_.isEqual(1);
_.isEqual(1, 2, 3);


/**
* _.range
*/
_.range(0, 10)[4] == 4
// $FlowExpectedError string. This type is incompatible with number
_.range(0, 'a');
// $FlowExpectedError string cannot be compared to number
_.range(0, 10)[4] == 'a';


/**
* _.extend
*/
_.extend({a: 1}, {b: 2}).a
_.extend({a: 1}, {b: 2}).b
// $FlowExpectedError property `c`. Property not found in object literal
_.extend({a: 1}, {b: 2}).c


/**
* _.zip
*/
_.zip(['a', 'b', 'c'], ['d', 'e', 'f'])[0].length;
_.zip(['a', 'b', 'c'], [1, 2, 3])[0].length;
_.zip(['a', 'b', 'c'], [1, 2, 3])[0][0] + 'a'
_.zip(['a', 'b', 'c'], [1, 2, 3])[0][1] * 10
// $FlowExpectedError `x` property not found in Array
_.zip([{x:1}], [{x:2,y:1}])[0].x
// $FlowExpectedError `y` property not found in object literal
_.zip([{x:1}], [{x:2,y:1}])[0][0].y
_.zip([{x:1}], [{x:2,y:1}])[0][1].y



/**
* _.any
*/
_.any([1, 2, 3], x => x == 1);
// $FlowExpectedError number cannot be compared to string.
_.any([1, 2, 3], x => x == 'a');


/**
* _.find
*/
_.find([1, 2, 3], x => x == 1);
// $FlowExpectedError number. This type is incompatible with function type.
_.find([1, 2, 3], 1);
// $FlowExpectedError Callable signature not found in object literal
_.find([1, 2, 3], {val: 1});

(_.findIndex([1, 2, 3], function(i) { return i % 2 == 0} ): number);
// $FlowExpectedError number cannot be compared to string.
(_.findIndex([1, 2, 3], function(i) { return i == '0'} ): number);

(_.indexOf(['a', 'b', 'c'], function(e) { return e == 'b'}): number);

(_.contains(['a', 'b', 'c'], 'b'): boolean);

(_.map(['hello', 'world'], function(e) { return e.length }): Array<number>);
(_.map({hello: 1, world: 2}, function(v, k) { return k.length }): Array<number>);
// $FlowExpectedError This type is incompatible with string
(_.map({hello: 1, world: 2}, function(v, k) { return k * 2 }): Array<number>);

(_.mapObject({foo: 1, bar: 2}, function (v, k) {return (k.length + v).toString()}): {[key: string]: string});
// $FlowExpectedError This type is incompatible with number
(_.mapObject({foo: 1, bar: 2}, function (v, k) {return (k.length + v).toString()}): number);

(_.pluck([{name: 'bob'}, {name: 'jane'}], 'name'): Array<string>);
(_.reduce([1, 2, 3], function(m, o) { return m + o }, 0): number);
(_.all([2, 4, 5], function(i) { return i % 2 == 0 }): boolean);
// $FlowExpectedError Property not found in Number
(_.all([2, 4, 5], function(i) { return i.length }): boolean);
(_.some([2, 4, 5], function(i) { return i % 2 == 0 }): boolean);
(_.union(['a', 'b'], ['b']): Array<string>);
(_.intersection(['a', 'b'], ['b']): Array<string>);
(_.difference(['a', 'b'], ['b']): Array<string>);
(_.first([1,2,3]): number);
(_.first([1,2,3], 2): Array<number>);
(_.last([1,2,3]): number);
(_.last([1,2,3], 2): Array<number>);
(_.sample([1,2,3]): number);
(_.sortBy(['hello', 'world'], function(e) { return e.length }): Array<string>);
(_.uniq([1,2,2]): Array<number>);
(_.compact([1, null]): Array<number>);
(_.select([1,2,3], function(e) { return e % 2 == 0 }): Array<number>);
(_.reject([1,2,3], function(e) { return e % 2 == 0 }): Array<number>);
(_.without([1,2,3], 1, 2): Array<number>);
(_.has({a: 1, b: 2}, 'b'): boolean);
(_.isArray([1, 2]): boolean);
(_.isArray(1): boolean);
(_.pick({a: 1, b: 2}, 'a'): {[key: string]: number});
(_.omit({a: 1, b: 2}, 'a'): {[key: string]: number});

_.throttle(function(a) {a.length}, 10)('hello');
_.debounce(function(a) {a.length}, 10)('hello');

_.memoize(function(){})();
_.partial(function (a, b) { return a + b }, 1)(2);
_.defer(function(){});

(

_.compose(
function (name:string):string { return name + ', hello!'; },
function (user:Object):string { return user.name; }
): (user: Object) => string

);

(_.partition([1,5,2,4], function(i: number) { return i<4 }): [Array<number>, Array<number>]);
(_.partition({x: 'foo', y: 'bar'}, function(v: string, k: string) { return k === 'bar' }): [Array<string>, Array<string>]);

(_.size([1,2]): number);
(_.size({a: 1, b: 2}): number);

_.template("a<%=b%>c")({b: "_"});
// $FlowExpectedError `foo` property not found in Function
_.template(321).foo;
// $FlowExpectedError This type is incompatible with string
_.template(321)({b: "_"});
// $FlowExpectedError This type is incompatible with string
_.template("a<%=b%>c")({b: 1});

_.isObject({});
_.isArguments(null);
_.isFunction(() => {});
_.isString('');
_.isBoolean(true);
_.isNumber(1);
_.isFinite(1);
_.isBoolean(1);
_.isDate(new Date());
_.isRegExp(/[a-z]/);
_.isError(new Error('?'));
_.isNaN(NaN);
_.isNull(null);
_.isUndefined(undefined);
@@ -0,0 +1,3 @@
declare module 'foo' {
// stuff
}
56 changes: 0 additions & 56 deletions cli/src/commands/__tests__/install-test.js
Expand Up @@ -26,7 +26,6 @@ import {testProject} from '../../lib/TEST_UTILS';
import colors from 'colors/safe';

import {
_determineFlowVersion as determineFlowVersion,
_installNpmLibDefs as installNpmLibDefs,
_installNpmLibDef as installNpmLibDef,
run,
Expand Down Expand Up @@ -55,61 +54,6 @@ const defaultRunProps = {
};

describe('install (command)', () => {
describe('determineFlowVersion', () => {
it('infers version from path if arg not passed', () => {
return testProject(async ROOT_DIR => {
const ARBITRARY_PATH = path.join(ROOT_DIR, 'some', 'arbitrary', 'path');
await Promise.all([
mkdirp(ARBITRARY_PATH),
touchFile(path.join(ROOT_DIR, '.flowconfig')),
writePkgJson(path.join(ROOT_DIR, 'package.json'), {
name: 'test',
devDependencies: {
'flow-bin': '^0.40.0',
},
}),
]);

const flowVer = await determineFlowVersion(ARBITRARY_PATH);
expect(flowVer).toEqual({
kind: 'specific',
ver: {
major: 0,
minor: 40,
patch: 0,
prerel: null,
},
});
});
});

it('uses explicitly specified version', async () => {
const explicitVer = await determineFlowVersion('/', '0.7.0');
expect(explicitVer).toEqual({
kind: 'specific',
ver: {
major: 0,
minor: 7,
patch: 0,
prerel: null,
},
});
});

it("uses 'v'-prefixed explicitly specified version", async () => {
const explicitVer = await determineFlowVersion('/', 'v0.7.0');
expect(explicitVer).toEqual({
kind: 'specific',
ver: {
major: 0,
minor: 7,
patch: 0,
prerel: null,
},
});
});
});

describe('installNpmLibDefs', () => {
const origConsoleError = console.error;

Expand Down

0 comments on commit da69682

Please sign in to comment.