From cb9aea8fb2e865a6cb497397f933f78f90e67923 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Mon, 15 Feb 2016 00:32:35 -0800 Subject: [PATCH 01/15] Export type definitions Hand-written definitions for Mori types are in mori.js.flow. In projects that use Flow for type-checking and that import Mori, Flow will load those definitions automatically. mori-spec.js is modified slightly to signal to Flow that it should type-check that file. This is to make sure that the type-checker does not infer errors in any code in the unit tests - that would indicate that there is something wrong in the type definitions. types-spec.js has been added to provide certain test cases that should pass type-checking, to make sure that those cases do pass. types-spec.js includes type annotations as specially-formatted comments. flow-bin has been added as a development dependency, and .flowconfig has been added to configure Flow type checking. Type checking can be run with: $ flow check This will check code in mori-spec.js and in types-spec.js against the definitions in mori.js.flow. --- .flowconfig | 8 + mori.js.flow | 580 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + spec/mori-spec.js | 6 + spec/types-spec.js | 118 +++++++++ 5 files changed, 713 insertions(+) create mode 100644 .flowconfig create mode 100644 mori.js.flow create mode 100644 spec/types-spec.js diff --git a/.flowconfig b/.flowconfig new file mode 100644 index 0000000..f492397 --- /dev/null +++ b/.flowconfig @@ -0,0 +1,8 @@ +[ignore] +.*/flow-bin/.* + +[include] + +[libs] + +[options] diff --git a/mori.js.flow b/mori.js.flow new file mode 100644 index 0000000..8f1af36 --- /dev/null +++ b/mori.js.flow @@ -0,0 +1,580 @@ +/* + * Type definitions for Mori, for use with Flow type checker + * + * @flow + */ + +/* Fundamentals */ + +declare function equals(x: any, y: any): boolean +declare function hash(x: any): number + +/* Collection Types */ + +/* + * Declarations for classes that do not really exist. + * We need types to describe the capabilities of different collections. + * Class declarations happen to be a convenient way to make up types that are + * unique to this module. + */ +declare export class Collection {} +declare export class Associative {} +declare export class Seq extends Collection {} +declare export class Sequential extends Collection {} +declare export class Stack extends Collection {} + +export type Indexed = Sequential | Iterable +export type Seqable = Collection | Iterable + +export type List = Collection + & Seq + & Sequential + & Stack + +export type Map = Associative + & Collection> + +export type Queue = Collection + & Seq + & Sequential + & Stack + +export type Set = Collection + +export type Vector = Associative + & Collection + & Sequential + +/* Other Types */ + +/* + * A pair is just a vector. But by pretending that there is a distinct type + * called `Pair`, we get a representation at the type level that more closely + * matches usage of pairs when operating on `Map` values. + * + * With a distinct type, `get`, `nth`, `first`, and `last` can be checked with + * the knowledge that a pair from a map: + * + * - has exactly two values + * - has a value of type `K` in position 0 + * - has a value of type `V` in position 1 + * + * Furthermore, when building a map with `conj` or `into`, the distinct `Pair` + * type allows the type checker to verify that keys and values given match the + * key and value types for the map. + */ +declare export class Pair {} + +declare export class Keyword {} +declare export class Symbol {} + +/* Collection Constructors */ + +declare function list(...args: A[]): List +declare var vector: ((...args: A[]) => Vector) + & ((k: K, v: V) => Pair) +declare function hashMap(...keysAndValues: (K | V)[]): Map +declare function sortedMap(...keysAndValues: (K | V)[]): Map +declare function sortedMapBy(cmp: (x: K, y: K) => number, ...keysAndValues: (K | V)[]): Map +declare function set(values: Seqable): Set +declare function sortedSet(values: Seqable): Set +declare function sortedSetBy(cmp: (x: A, b: A) => number, ...values: A[]): Set +declare function range(start?: number, end?: number, step?: number): Seq +declare function queue(...args: A[]): Queue + +/* Other Constructors */ + +declare function keyword(name: string): Keyword +declare function symbol(name: string): Symbol + +/* Type Predicates */ + +declare function isList(coll: any): boolean +declare function isSeq(coll: any): boolean +declare function isVector(coll: any): boolean +declare function isMap(coll: any): boolean +declare function isSet(coll: any): boolean +declare function isCollection(coll: any): boolean +declare function isSequential(coll: any): boolean +declare function isAssociative(coll: any): boolean +declare function isCounted(coll: any): boolean +declare function isIndexed(coll: any): boolean +declare function isReduceable(coll: any): boolean +declare function isSeqable(coll: any): boolean +declare function isReversible(coll: any): boolean +declare function isCollection(coll: any): boolean +declare function isKeyword(x: any): boolean +declare function isSymbol(x: any): boolean + +/* Collection Operations */ + +declare function conj>(coll: S, ...args: A[]): S +declare function into,S:Seqable>(coll: T, from: S): T +declare function assoc>(coll: S, ...keysAndValues: (K | V)[]): S +declare function dissoc>(coll: S, ...keys: K[]): S +declare function distinct>(coll: S): S +declare function empty>(coll: S): S +declare var get: ((coll: Associative, key: K, notFound?: V) => ?V) // TODO: `get` works on A[] + & ((coll: Pair, key: 0) => K) + & ((coll: Pair, key: 1) => V) +declare function getIn(coll: Associative, keys: Seqable, notFound?: V): ?V +declare function hasKey(coll: Associative | Set, key: K): boolean // TODO: `hasKey` works on A[] +declare function find(coll: Associative, key: K): ?Pair +declare var nth: ((coll: Indexed, index: number) => ?A) + & ((coll: Pair, index: 0) => K) + & ((coll: Pair, index: 1) => V) +declare var last: ((coll: Seqable) => ?A) + & ((coll: Pair) => V) +declare function assocIn>(coll: S, keys: Seqable, val: V): S +declare function updateIn>(coll: S, + keys: Seqable, + f: (_: V) => V): S +declare function count(coll: Seqable): number +declare function isEmpty(coll: Seqable): boolean +declare function peek(coll: Stack): ?A +declare function pop>(coll: S): S +declare function zipmap(xs: Seqable, ys: Seqable): Map +declare function reverse(coll: Seqable): Seq + +/* Vector Operations */ + +declare function subvec(vec: Vector, start: number, end?: number): Vector + +/* Hash Map Operations */ + +declare function keys(map: Map): Seq +declare function vals(map: Map): Seq +declare function merge(map: Map, ...maps: Map[]): Map + +/* Set Operations */ + +declare function disj(set: Set, ...toRemove: A[]): Set +declare function union(set: Set, ...sets: Set[]): Set +declare function intersection(set: Set, ...sets: Set[]): Set +declare function difference(set: Set, ...sets: Set[]): Set +declare function isSubset(seta: Set, setb: Set): boolean +declare function isSuperset(seta: Set, setb: Set): boolean + +/* Sequences */ + +declare var first: ((coll: Seqable) => ?A) + & ((coll: Pair) => K) +declare function rest(coll: Seqable): Seq +declare function seq(coll: Seqable): Seq +declare function cons(value: A, coll: Seqable): List +declare function concat(coll: Seqable, ...colls: Seqable[]): Seq +declare function flatten(coll: Seqable): Seq +declare var intoArray: ((coll: Seqable) => A[]) + & ((coll: Pair) => [K,V]) +declare function each(coll: Seqable, f: (_: A) => any): void + +declare var map: ((f: (a: A, b: B, c: C, d: D, e: E) => R, + colla: Seqable, + collb: Seqable, + collc: Seqable, + colld: Seqable, + colle: Seqable + ) => Seq) + & ((f: (a: A, b: B, c: C, d: D) => R, + colla: Seqable, + collb: Seqable, + collc: Seqable, + colld: Seqable + ) => Seq) + & ((f: (a: A, b: B, c: C) => R, + colla: Seqable, + collb: Seqable, + collc: Seqable + ) => Seq) + & ((f: (a: A, b: B) => R, + colla: Seqable, + collb: Seqable + ) => Seq) + & ((f: (a: A) => R, + colla: Seqable + ) => Seq) + + & ((f: (...values: T[]) => R, + ...colls: Seqable[] + ) => Seq) + +declare var mapcat: ((f: (a: A, b: B, c: C, d: D, e: E) => Seqable, + colla: Seqable, + collb: Seqable, + collc: Seqable, + colld: Seqable, + colle: Seqable + ) => Seq) + & ((f: (a: A, b: B, c: C, d: D) => Seqable, + colla: Seqable, + collb: Seqable, + collc: Seqable, + colld: Seqable + ) => Seq) + & ((f: (a: A, b: B, c: C) => Seqable, + colla: Seqable, + collb: Seqable, + collc: Seqable + ) => Seq) + & ((f: (a: A, b: B) => Seqable, + colla: Seqable, + collb: Seqable + ) => Seq) + & ((f: (a: A) => Seqable, + colla: Seqable + ) => Seq) + & ((f: (...values: T[]) => Seqable, + ...colls: Seqable[] + ) => Seq) + +declare function filter(pred: (value: A) => boolean, coll: Seqable): Seq +declare function remove(pred: (value: A) => boolean, coll: Seqable): Seq +declare var reduce: ((f: (accum: R, value: A) => R, + initial: R, + coll: Seqable + ) => R) + & ((f: (accum: R, value: A) => R, + coll: Seqable + ) => R) +declare function reduceKV(f: (accum: R, key: K, value: V) => R, + initial: R, + coll: Associative + ): R +declare function take(n: number, coll: Seqable): Seq +declare function takeWhile(f: (value: A) => boolean, coll: Seqable): Seq +declare function drop(n: number, coll: Seqable): Seq +declare function dropWhile(f: (value: A) => boolean, coll: Seqable): Seq +declare function some(f: (value: A) => boolean, coll: Seqable): ?A +declare function every(f: (value: A) => boolean, coll: Seqable): boolean +declare var sort: ((cmp: (x: A, y: A) => number, coll: Seqable) => Seq) + & ((coll: Seqable) => Seq) +declare var sortBy: ((keyfn: (x: A, y: A) => B, cmp: (x: B, y: B) => B, coll: Seqable) => Seq) + & ((keyfn: (x: A, y: A) => B, coll: Seqable) => Seq) +declare function interpose(x: B, coll: Seqable): Seq +declare function interleave(colla: Seqable, + collb: Seqable, + collc?: Seqable, + ...colls: Seqable[] + ): Seq +declare function iterate(f: (value: A) => A, x: A): Seq +declare var repeat: ((n: number, x: A) => Seq) + & ((x: A) => Seq) +declare var repeatedly: ((n: number, f: () => A) => Seq) + & ((f: () => A) => Seq) +declare var partition: ((n: number, step: number, pad: Seqable, coll: Seqable) => Seq>) + & ((n: number, step: number, coll: Seqable) => Seq>) + & ((n: number, coll: Seqable) => Seq>) +declare function partitionBy(f: (value: A) => K, coll: Seqable): Seq> +declare function groupBy(f: (value: A) => K, coll: Seqable): Map> +declare function lazySeq(thunk: () => Seqable): Seq + +/* Helpers */ + +declare function primSeq(seqable: Seqable, index?: number): Seq +declare function identity(x: A): A +declare function constantly(x: A): (...args: any[]) => A +declare function inc(n: number): number +declare function dec(n: number): number +declare function sum(...ns: number[]): number +declare function isEven(n: number): boolean +declare function isOdd(n: number): boolean + +declare var comp: ((f4: (_: E) => F, + f3: (_: D) => E, + f2: (_: C) => D, + f1: (_: B) => C, + f0: (_: A) => B, + ) => (_: A) => F) + & ((f3: (_: D) => E, + f2: (_: C) => D, + f1: (_: B) => C, + f0: (_: A) => B + ) => (_: A) => E) + & ((f2: (_: C) => D, + f1: (_: B) => C, + f0: (_: A) => B + ) => (_: A) => D) + & ((f1: (_: B) => C, + f0: (_: A) => B + ) => (_: A) => C) + & ((f0: (_: A) => B + ) => (_: A) => B) + & ((...fs: ((_: T) => T)[]) => (_: T) => R) + +declare var juxt: ((f0: (_: T) => A, + f1: (_: T) => B, + f2: (_: T) => C, + f3: (_: T) => D, + f4: (_: T) => E + ) => (_: T) => [A,B,C,D,E]) + & ((f0: (_: T) => A, + f1: (_: T) => B, + f2: (_: T) => C, + f3: (_: T) => D + ) => (_: T) => [A,B,C,D]) + & ((f0: (_: T) => A, + f1: (_: T) => B, + f2: (_: T) => C + ) => (_: T) => [A,B,C]) + & ((f0: (_: T) => A, + f1: (_: T) => B + ) => (_: T) => [A,B]) + & ((f0: (_: T) => A + ) => (_: T) => [A]) + & (() => (_: T) => void[]) + & ((f0: (_: T) => R, + f1: (_: T) => R, + f2: (_: T) => R, + f3: (_: T) => R, + f4: (_: T) => R, + f5: (_: T) => R, + ...fs: ((_: T) => R)[] + ) => (_: T) => R[]) + +declare var knit: ((f0: (_: T) => A, + f1: (_: T) => B, + f2: (_: T) => C, + f3: (_: T) => D, + f4: (_: T) => E + ) => (_: Seqable) => [A,B,C,D,E]) + & ((f0: (_: T) => A, + f1: (_: T) => B, + f2: (_: T) => C, + f3: (_: T) => D + ) => (_: Seqable) => [A,B,C,D]) + & ((f0: (_: T) => A, + f1: (_: T) => B, + f2: (_: T) => C + ) => (_: Seqable) => [A,B,C]) + & ((f0: (_: T) => A, + f1: (_: T) => B + ) => (_: Seqable) => [A,B]) + & ((f0: (_: T) => A + ) => (_: Seqable) => [A]) + & (() => (_: Seqable) => void[]) + & ((f0: (_: T) => R, + f1: (_: T) => R, + f2: (_: T) => R, + f3: (_: T) => R, + f4: (_: T) => R, + f5: (_: T) => R, + ...fs: ((_: T) => R)[] + ) => (_: Seqable) => R[]) + +declare var pipeline: ((x: A, + f0: (_: A) => B, + f1: (_: B) => C, + f2: (_: C) => D, + f3: (_: D) => E, + f4: (_: E) => R + ) => R) + & ((x: A, + f0: (_: A) => B, + f1: (_: B) => C, + f2: (_: C) => D, + f3: (_: D) => R, + ) => R) + & ((x: A, + f0: (_: A) => B, + f1: (_: B) => C, + f2: (_: C) => R, + ) => R) + & ((x: A, + f0: (_: A) => B, + f1: (_: B) => R, + ) => R) + & ((x: A, + f0: (_: A) => R, + ) => R) + & ((x: A) => A) + & ((x: T, + ...fs: ((_: T) => R)[] + ) => R) + +declare var partial: ((f: (...args: T[]) => R + ) => (...args: T[]) => R) + & ((f: (a: A, ...args: T[]) => R, + a: A + ) => (...args: T[]) => R) + & ((f: (a: A, b: B, ...args: T[]) => R, + a: A, + b: B, + ) => (...args: T[]) => R) + & ((f: (a: A, b: B, c: C, ...args: T[]) => R, + a: A, + b: B, + c: C, + ) => (...args: T[]) => R) + & ((f: (a: A, b: B, c: C, d: D, ...args: T[]) => R, + a: A, + b: B, + c: C, + d: D, + ) => (...args: T[]) => R) + & ((f: (a: A, b: B, c: C, d: D, e: E, ...args: T[]) => R, + a: A, + b: B, + c: C, + d: D, + e: E, + ) => (...args: T[]) => R) + +declare var curry: typeof partial + +declare var fnil: ((f: (a: ?A, ...args: T[]) => R, + a: A + ) => (a: A, ...args: T[]) => R) + & ((f: (a: ?A, b: ?B, ...args: T[]) => R, + a: A, + b: B + ) => (a: A, b: B, ...args: T[]) => R) + & ((f: (a: ?A, b: ?B, c: ?C, ...args: T[]) => R, + a: A, + b: B, + c: C + ) => (a: A, b: B, c: C, ...args: T[]) => R) + & ((f: (a: ?A, b: ?B, c: ?C, d: ?D, ...args: T[]) => R, + a: A, + b: B, + c: C, + d: D + ) => (a: A, b: B, c: C, d: D, ...args: T[]) => R) + & ((f: (a: ?A, b: ?B, c: ?C, d: ?D, e: ?E, ...args: T[]) => R, + a: A, + b: B, + c: C, + d: D, + e: E + ) => (a: A, b: B, c: C, d: D, e: E, ...args: T[]) => R) + +declare var toClj: ((x: A[]) => Vector) + & ((x: { [key: string]: A }) => Map) + +declare var toJs: ((x: Sequential | Set) => B[]) + & ((x: Map) => { [key: string]: B }) + +/* Configure */ + +declare function configure(setting: 'print-length' | 'print-level', value: ?number): void + +export { + equals, + hash, + + isList, + isSeq, + isVector, + isMap, + isSet, + isCollection, + isSequential, + isAssociative, + isCounted, + isIndexed, + isReduceable, + isSeqable, + isReversible, + isCollection, + isKeyword, + isSymbol, + + list, + vector, + hashMap, + sortedMap, + sortedMapBy, + set, + sortedSet, + sortedSetBy, + range, + queue, + + keyword, + symbol, + + conj, + into, + assoc, + dissoc, + distinct, + empty, + get, + getIn, + hasKey, + find, + nth, + last, + assocIn, + updateIn, + count, + isEmpty, + peek, + pop, + zipmap, + reverse, + + subvec, + + keys, + vals, + merge, + + disj, + union, + intersection, + difference, + isSubset, + isSuperset, + + first, + rest, + seq, + cons, + concat, + flatten, + intoArray, + each, + map, + mapcat, + filter, + remove, + reduce, + reduceKV, + take, + takeWhile, + drop, + dropWhile, + some, + every, + sort, + sortBy, + interpose, + interleave, + iterate, + repeat, + repeatedly, + partition, + partitionBy, + groupBy, + lazySeq, + + primSeq, + identity, + constantly, + inc, + dec, + sum, + isEven, + isOdd, + comp, + juxt, + knit, + pipeline, + partial, + curry, + fnil, + toClj, + toJs, + + configure, +} diff --git a/package.json b/package.json index f19dd31..9561d35 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ }, "dependencies": {}, "devDependencies": { + "flow-bin": "0.21.0", "immutable": "3.5.0", "jasmine-node": "1.7.0" }, diff --git a/spec/mori-spec.js b/spec/mori-spec.js index fa0afde..db4bfdc 100644 --- a/spec/mori-spec.js +++ b/spec/mori-spec.js @@ -1,5 +1,11 @@ +/* @flow */ + var mori = require("../mori"); +/*:: declare var describe: Function */ +/*:: declare var it: Function */ +/*:: declare var expect: Function */ + describe("Map", function () { it("demonstrates mapping a function over a vector", function () { var inc = function (n) { return n + 1; }, diff --git a/spec/types-spec.js b/spec/types-spec.js new file mode 100644 index 0000000..219975c --- /dev/null +++ b/spec/types-spec.js @@ -0,0 +1,118 @@ +/* + * Extra specs to verify that certain operations pass type-checking. + * + * @flow + */ + +var mori = require("../mori"); + +/*:: declare var describe: Function */ +/*:: declare var it: Function */ +/*:: declare var expect: Function */ + +/*:: import type { Collection, Map, Pair, Seq, Vector } from "../mori" */ + +describe("type-checking", function () { + + it("preserves collection type", function () { + var v = mori.vector(1, 2, 3); + var v_ = mori.conj(v, 4); + mori.subvec(v_, 0); // operation requires type to be a `Vector<*>` + var n/*: ?number */ = mori.first(v_); // requires `number` type parameter to be preserved + + var m = mori.hashMap('foo', 1, 'bar', 2); + var m_ = mori.into(m, mori.list(mori.vector('nao', 3))) + mori.keys(m_); // operation requires `Map<*,*>` type to be preserved + }); + + it("creates consistently-typed zipmap", function () { + var strings = mori.vector('foo', 'bar', 'nao'); + var numbers = mori.vector(1, 2, 3); + var m = mori.zipmap(strings, numbers); + const s/*: ?string */ = mori.first(mori.keys(m)); + const n/*: ?number */ = mori.first(mori.vals(m)); + }); + + it("potentially broadens type of map on `merge`", function () { + var ma/*: Map */ = mori.hashMap('foo', 'one', 'bar', 'two'); + var mb/*: Map */ = mori.hashMap(1, 1, 2, 2, 3, 3); + var m/*: Map */ = mori.merge(ma, mb); + }); + + it("tracks input types for each transformation function in `map` and `mapcat`", function () { + var strings = mori.vector('foo', 'bar', 'nao'); + var numbers = mori.vector(1, 2, 3); + + var pairs/*: Seq<[string, number]> */ = + mori.map(function(s, n) { return [s, n]; }, strings, numbers); + + var reps/*: Seq */ = + mori.mapcat(function(s, n) { return mori.repeat(n, s); }, strings, numbers); + }); + + it("potentially broadens type of collection on `partition`", function () { + var numbers = mori.vector(1, 2, 3, 4, 5); + var padded/*: Seq> */ = mori.partition(2, 2, 'xyz', numbers); + var unpadded/*: Seq> */ = mori.partition(2, numbers); + }); + + it("applies `primeSeq` to `arguments`", function () { + function asSeq() { + return mori.primSeq(arguments); + } + expect(mori.intoArray(asSeq(2,3))).toEqual([2,3]) + }); + + it("composes functions, keeping track of type changes", function () { + var f = mori.comp( + (function(x) { return mori.count(x) > 2; } /*: (_: Seq) => boolean */), + (function(x) { return mori.repeat(x, 'foo'); } /*: (_: number) => Seq */), + (function(x) { return x.toLowerCase().length; } /*: (_: string) => number */) + ); + var r1/*: boolean */ = f('foo'); + + var g = mori.comp(mori.isOdd, mori.inc); + var r2/*: boolean */ = g(3); + }); + + it("pipelines functions, keeping track of type changes", function () { + var r1/*: boolean */ = mori.pipeline('foo', + (function(x) { return x.toLowerCase().length; } /*: (_: string) => number */), + (function(x) { return mori.repeat(x, 'foo'); } /*: (_: number) => Seq */), + (function(x) { return mori.count(x) > 2; } /*: (_: Seq) => boolean */) + ); + + var r2/*: boolean */ = mori.pipeline(3, mori.inc, mori.isOdd); + }); + + it("partially applies functions", function () { + var v/*: Vector */ = mori.vector(1,2,3); + var f = mori.partial(mori.conj, v); + var v_/*: Vector */ = f(4); + // Does not type-check: + //var v_/*: Vector */ = f(4); + }); + + it("infers that a pair is guaranteed to have two elements with distinct types", function () { + var m/*: Map */ = mori.hashMap('foo', 1, 'bar', 2); + var p = mori.first(m); + if (!p) { return; } // Assures the type-checker that `p` is not `null` + + (mori.get(p, 0)/*: string */); + (mori.get(p, 1)/*: number */); + + var v = mori.vector(1,2,3); + (mori.get(v, 2)/*: ?number */); + }); + + it("transforms a Mori pair into a native Javascript pair", function () { + // Producing a native array is useful for destructuring assignment. + var m/*: Map */ = mori.hashMap('foo', 1, 'bar', 2); + var p = mori.first(m) + if (!p) { return; } // Assures the type-checker that `p` is not `null` + var a = mori.intoArray(p) + var k/*: string */ = a[0] + var v/*: number */ = a[1] + }) + +}); From 077a4046858a9b9a8ef98b18fa33670febc8a8d6 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Tue, 16 Feb 2016 14:58:38 -0800 Subject: [PATCH 02/15] Add `typecheck` script --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 9561d35..5d04940 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,8 @@ "clean": "./scripts/clean.sh", "prepublish": "npm run-script build-clean", "docs": "./scripts/docs.sh", - "test": "jasmine-node spec" + "test": "jasmine-node spec", + "typecheck": "flow check" }, "directories": { "test": "./spec" From e0533aa1147000597035665015552f34c5078cc1 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Tue, 16 Feb 2016 15:05:06 -0800 Subject: [PATCH 03/15] Export types, but keep pretend class implementations private --- mori.js.flow | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 8f1af36..bf34cd5 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -17,11 +17,20 @@ declare function hash(x: any): number * Class declarations happen to be a convenient way to make up types that are * unique to this module. */ -declare export class Collection {} -declare export class Associative {} -declare export class Seq extends Collection {} -declare export class Sequential extends Collection {} -declare export class Stack extends Collection {} +declare class _Collection {} +declare class _Associative {} +declare class _Seq extends _Collection {} +declare class _Sequential extends _Collection {} +declare class _Stack extends _Collection {} + +/* + * Export types, but do not export non-existent class implementations. + */ +export type Collection = _Collection +export type Associative = _Associative +export type Seq = _Seq +export type Sequential = _Sequential +export type Stack = _Stack export type Indexed = Sequential | Iterable export type Seqable = Collection | Iterable From 2a4ad3ae2a1107b875108d049a682c0ca9f08b8a Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Thu, 18 Feb 2016 17:39:48 -0800 Subject: [PATCH 04/15] Track key/value type alternation when constructing or assoc-ing maps Tracks type alternation for the first five pairs. After that, only checks that arguments match either the key type or the value type. Does not prevent trying to create a map with an odd number of arguments. --- mori.js.flow | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index bf34cd5..319254f 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -82,9 +82,25 @@ declare export class Symbol {} declare function list(...args: A[]): List declare var vector: ((...args: A[]) => Vector) & ((k: K, v: V) => Pair) -declare function hashMap(...keysAndValues: (K | V)[]): Map -declare function sortedMap(...keysAndValues: (K | V)[]): Map -declare function sortedMapBy(cmp: (x: K, y: K) => number, ...keysAndValues: (K | V)[]): Map +declare function hashMap( key0?: K, val0?: V + , key1?: K, val1?: V + , key2?: K, val2?: V + , key3?: K, val3?: V + , key4?: K, val4?: V + , ...keysAndValues: (K | V)[]): Map +declare function sortedMap( key0?: K, val0?: V + , key1?: K, val1?: V + , key2?: K, val2?: V + , key3?: K, val3?: V + , key4?: K, val4?: V + , ...keysAndValues: (K | V)[]): Map +declare function sortedMapBy( cmp: (x: K, y: K) => number + , key0?: K, val0?: V + , key1?: K, val1?: V + , key2?: K, val2?: V + , key3?: K, val3?: V + , key4?: K, val4?: V + , ...keysAndValues: (K | V)[]): Map declare function set(values: Seqable): Set declare function sortedSet(values: Seqable): Set declare function sortedSetBy(cmp: (x: A, b: A) => number, ...values: A[]): Set @@ -119,7 +135,13 @@ declare function isSymbol(x: any): boolean declare function conj>(coll: S, ...args: A[]): S declare function into,S:Seqable>(coll: T, from: S): T -declare function assoc>(coll: S, ...keysAndValues: (K | V)[]): S +declare function assoc>( coll: S + , key0?: K, val0?: V + , key1?: K, val1?: V + , key2?: K, val2?: V + , key3?: K, val3?: V + , key4?: K, val4?: V + , ...keysAndValues: (K | V)[]): S declare function dissoc>(coll: S, ...keys: K[]): S declare function distinct>(coll: S): S declare function empty>(coll: S): S From 0471514f3f68954c82e347d0136b9df99efa5a1e Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Thu, 18 Feb 2016 17:44:33 -0800 Subject: [PATCH 05/15] Do not use maybe type with `get` and `getIn` if `notFoundValue` is given --- mori.js.flow | 6 ++++-- spec/types-spec.js | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 319254f..ea89f60 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -145,10 +145,12 @@ declare function assoc>( coll: S declare function dissoc>(coll: S, ...keys: K[]): S declare function distinct>(coll: S): S declare function empty>(coll: S): S -declare var get: ((coll: Associative, key: K, notFound?: V) => ?V) // TODO: `get` works on A[] +declare var get: ((coll: Associative, key: K, notFound: V) => V) // TODO: `get` works on A[] + & ((coll: Associative, key: K) => ?V) & ((coll: Pair, key: 0) => K) & ((coll: Pair, key: 1) => V) -declare function getIn(coll: Associative, keys: Seqable, notFound?: V): ?V +declare var getIn: ((coll: Associative, keys: Seqable, notFound: V) => V) + & ((coll: Associative, keys: Seqable) => ?V) declare function hasKey(coll: Associative | Set, key: K): boolean // TODO: `hasKey` works on A[] declare function find(coll: Associative, key: K): ?Pair declare var nth: ((coll: Indexed, index: number) => ?A) diff --git a/spec/types-spec.js b/spec/types-spec.js index 219975c..f47094f 100644 --- a/spec/types-spec.js +++ b/spec/types-spec.js @@ -25,6 +25,12 @@ describe("type-checking", function () { mori.keys(m_); // operation requires `Map<*,*>` type to be preserved }); + it("returns default value when key is not found", function () { + var m = mori.hashMap('foo', 1, 'bar', 2); + var guaranteed/*: number */ = mori.get(m, 'nao', 3); + var not_guaranteed/*: ?number */ = mori.get(m, 'nao'); + }); + it("creates consistently-typed zipmap", function () { var strings = mori.vector('foo', 'bar', 'nao'); var numbers = mori.vector(1, 2, 3); From d2b3d802bc7547bbfe4f196f2d1971d19ceee60d Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Thu, 18 Feb 2016 18:18:25 -0800 Subject: [PATCH 06/15] Add type declarations for `second` and `next` --- mori.js.flow | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mori.js.flow b/mori.js.flow index ea89f60..6172eac 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -192,7 +192,10 @@ declare function isSuperset(seta: Set, setb: Set): boolean declare var first: ((coll: Seqable) => ?A) & ((coll: Pair) => K) +declare var second: ((coll: Seqable) => ?A) + & ((coll: Pair) => V) declare function rest(coll: Seqable): Seq +declare function next(coll: Seqable): Seq declare function seq(coll: Seqable): Seq declare function cons(value: A, coll: Seqable): List declare function concat(coll: Seqable, ...colls: Seqable[]): Seq @@ -560,7 +563,9 @@ export { isSuperset, first, + second, rest, + next, seq, cons, concat, From e27a322713b06587a0efad95a7781a330bd72572 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Mon, 22 Feb 2016 23:49:57 -0800 Subject: [PATCH 07/15] Use null-terminated argument lists to avoid ambiguity in overloaded function types --- mori.js.flow | 144 +++++++++++++++++++++++++++++++-------------------- 1 file changed, 88 insertions(+), 56 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 6172eac..42926df 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -145,11 +145,11 @@ declare function assoc>( coll: S declare function dissoc>(coll: S, ...keys: K[]): S declare function distinct>(coll: S): S declare function empty>(coll: S): S -declare var get: ((coll: Associative, key: K, notFound: V) => V) // TODO: `get` works on A[] +declare var get: ((coll: Associative, key: K, notFound: V_) => V|V_) // TODO: `get` works on A[] & ((coll: Associative, key: K) => ?V) & ((coll: Pair, key: 0) => K) & ((coll: Pair, key: 1) => V) -declare var getIn: ((coll: Associative, keys: Seqable, notFound: V) => V) +declare var getIn: ((coll: Associative, keys: Seqable, notFound: V_) => V|V_) & ((coll: Associative, keys: Seqable) => ?V) declare function hasKey(coll: Associative | Set, key: K): boolean // TODO: `hasKey` works on A[] declare function find(coll: Associative, key: K): ?Pair @@ -209,27 +209,31 @@ declare var map: ((f: (a: A, b: B, c: C, d: D, e: E) => R, collb: Seqable, collc: Seqable, colld: Seqable, - colle: Seqable + colle: Seqable, + $?: null ) => Seq) & ((f: (a: A, b: B, c: C, d: D) => R, colla: Seqable, collb: Seqable, collc: Seqable, - colld: Seqable + colld: Seqable, + $?: null ) => Seq) & ((f: (a: A, b: B, c: C) => R, colla: Seqable, collb: Seqable, - collc: Seqable + collc: Seqable, + $?: null ) => Seq) & ((f: (a: A, b: B) => R, colla: Seqable, - collb: Seqable + collb: Seqable, + $?: null ) => Seq) & ((f: (a: A) => R, - colla: Seqable + colla: Seqable, + $?: null ) => Seq) - & ((f: (...values: T[]) => R, ...colls: Seqable[] ) => Seq) @@ -239,25 +243,30 @@ declare var mapcat: ((f: (a: A, b: B, c: C, d: D, e: E) => Seqable< collb: Seqable, collc: Seqable, colld: Seqable, - colle: Seqable + colle: Seqable, + $?: null ) => Seq) & ((f: (a: A, b: B, c: C, d: D) => Seqable, colla: Seqable, collb: Seqable, collc: Seqable, - colld: Seqable + colld: Seqable, + $?: null ) => Seq) & ((f: (a: A, b: B, c: C) => Seqable, colla: Seqable, collb: Seqable, - collc: Seqable + collc: Seqable, + $?: null ) => Seq) & ((f: (a: A, b: B) => Seqable, colla: Seqable, - collb: Seqable + collb: Seqable, + $?: null ) => Seq) & ((f: (a: A) => Seqable, - colla: Seqable + colla: Seqable, + $?: null ) => Seq) & ((f: (...values: T[]) => Seqable, ...colls: Seqable[] @@ -271,7 +280,7 @@ declare var reduce: ((f: (accum: R, value: A) => R, ) => R) & ((f: (accum: R, value: A) => R, coll: Seqable - ) => R) + ) => ?R) declare function reduceKV(f: (accum: R, key: K, value: V) => R, initial: R, coll: Associative @@ -315,49 +324,51 @@ declare function sum(...ns: number[]): number declare function isEven(n: number): boolean declare function isOdd(n: number): boolean -declare var comp: ((f4: (_: E) => F, - f3: (_: D) => E, - f2: (_: C) => D, - f1: (_: B) => C, - f0: (_: A) => B, - ) => (_: A) => F) - & ((f3: (_: D) => E, - f2: (_: C) => D, - f1: (_: B) => C, - f0: (_: A) => B - ) => (_: A) => E) - & ((f2: (_: C) => D, - f1: (_: B) => C, - f0: (_: A) => B - ) => (_: A) => D) - & ((f1: (_: B) => C, - f0: (_: A) => B - ) => (_: A) => C) - & ((f0: (_: A) => B - ) => (_: A) => B) - & ((...fs: ((_: T) => T)[]) => (_: T) => R) +declare var comp: (( fn3: (d: D) => E + , fn2: (c: C) => D + , fn1: (b: B) => C + , fn0: (a: A) => B + , $?: null + ) => (a: A) => E) + & (( fn2: (c: C) => D + , fn1: (b: B) => C + , fn0: (a: A) => B + , $?: null + ) => (a: A) => D) + & (( fn1: (b: B) => C + , fn0: (a: A) => B + , $?: null + ) => (a: A) => C) + & (( fn0: (a: A) => B + , $?: null + ) => (a: A) => B) declare var juxt: ((f0: (_: T) => A, f1: (_: T) => B, f2: (_: T) => C, f3: (_: T) => D, - f4: (_: T) => E + f4: (_: T) => E, + $?: null ) => (_: T) => [A,B,C,D,E]) & ((f0: (_: T) => A, f1: (_: T) => B, f2: (_: T) => C, - f3: (_: T) => D + f3: (_: T) => D, + $?: null ) => (_: T) => [A,B,C,D]) & ((f0: (_: T) => A, f1: (_: T) => B, - f2: (_: T) => C + f2: (_: T) => C, + $?: null ) => (_: T) => [A,B,C]) & ((f0: (_: T) => A, - f1: (_: T) => B + f1: (_: T) => B, + $?: null ) => (_: T) => [A,B]) - & ((f0: (_: T) => A + & ((f0: (_: T) => A, + $?: null ) => (_: T) => [A]) - & (() => (_: T) => void[]) + & (($?: null) => (_: T) => void[]) & ((f0: (_: T) => R, f1: (_: T) => R, f2: (_: T) => R, @@ -371,23 +382,28 @@ declare var knit: ((f0: (_: T) => A, f1: (_: T) => B, f2: (_: T) => C, f3: (_: T) => D, - f4: (_: T) => E + f4: (_: T) => E, + $?: null ) => (_: Seqable) => [A,B,C,D,E]) & ((f0: (_: T) => A, f1: (_: T) => B, f2: (_: T) => C, - f3: (_: T) => D + f3: (_: T) => D, + $?: null ) => (_: Seqable) => [A,B,C,D]) & ((f0: (_: T) => A, f1: (_: T) => B, - f2: (_: T) => C + f2: (_: T) => C, + $?: null ) => (_: Seqable) => [A,B,C]) & ((f0: (_: T) => A, - f1: (_: T) => B + f1: (_: T) => B, + $?: null ) => (_: Seqable) => [A,B]) - & ((f0: (_: T) => A + & ((f0: (_: T) => A, + $?: null ) => (_: Seqable) => [A]) - & (() => (_: Seqable) => void[]) + & (($?: null) => (_: Seqable) => void[]) & ((f0: (_: T) => R, f1: (_: T) => R, f2: (_: T) => R, @@ -402,50 +418,60 @@ declare var pipeline: ((x: A, f1: (_: B) => C, f2: (_: C) => D, f3: (_: D) => E, - f4: (_: E) => R + f4: (_: E) => R, + $?: null ) => R) & ((x: A, f0: (_: A) => B, f1: (_: B) => C, f2: (_: C) => D, f3: (_: D) => R, + $?: null ) => R) & ((x: A, f0: (_: A) => B, f1: (_: B) => C, f2: (_: C) => R, + $?: null ) => R) & ((x: A, f0: (_: A) => B, f1: (_: B) => R, + $?: null ) => R) & ((x: A, f0: (_: A) => R, + $?: null ) => R) - & ((x: A) => A) + & ((x: A, $?: null) => A) & ((x: T, ...fs: ((_: T) => R)[] ) => R) -declare var partial: ((f: (...args: T[]) => R +declare var partial: ((f: (...args: T[]) => R, + $?: null ) => (...args: T[]) => R) & ((f: (a: A, ...args: T[]) => R, - a: A + a: A, + $?: null ) => (...args: T[]) => R) & ((f: (a: A, b: B, ...args: T[]) => R, a: A, b: B, + $?: null ) => (...args: T[]) => R) & ((f: (a: A, b: B, c: C, ...args: T[]) => R, a: A, b: B, c: C, + $?: null ) => (...args: T[]) => R) & ((f: (a: A, b: B, c: C, d: D, ...args: T[]) => R, a: A, b: B, c: C, d: D, + $?: null ) => (...args: T[]) => R) & ((f: (a: A, b: B, c: C, d: D, e: E, ...args: T[]) => R, a: A, @@ -453,34 +479,40 @@ declare var partial: ((f: (...args: T[]) => R c: C, d: D, e: E, + $?: null ) => (...args: T[]) => R) declare var curry: typeof partial declare var fnil: ((f: (a: ?A, ...args: T[]) => R, - a: A + a: A, + $?: null ) => (a: A, ...args: T[]) => R) & ((f: (a: ?A, b: ?B, ...args: T[]) => R, a: A, - b: B + b: B, + $?: null ) => (a: A, b: B, ...args: T[]) => R) & ((f: (a: ?A, b: ?B, c: ?C, ...args: T[]) => R, a: A, b: B, - c: C + c: C, + $?: null ) => (a: A, b: B, c: C, ...args: T[]) => R) & ((f: (a: ?A, b: ?B, c: ?C, d: ?D, ...args: T[]) => R, a: A, b: B, c: C, - d: D + d: D, + $?: null ) => (a: A, b: B, c: C, d: D, ...args: T[]) => R) & ((f: (a: ?A, b: ?B, c: ?C, d: ?D, e: ?E, ...args: T[]) => R, a: A, b: B, c: C, d: D, - e: E + e: E, + $?: null ) => (a: A, b: B, c: C, d: D, e: E, ...args: T[]) => R) declare var toClj: ((x: A[]) => Vector) From aa3757e00d8ae9a5cc3e580d0a3f0ff2eefacad0 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Tue, 23 Feb 2016 00:03:17 -0800 Subject: [PATCH 08/15] Declare proper type signature for `curry` --- mori.js.flow | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/mori.js.flow b/mori.js.flow index 42926df..48009e4 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -482,7 +482,31 @@ declare var partial: ((f: (...args: T[]) => R, $?: null ) => (...args: T[]) => R) -declare var curry: typeof partial +declare var curry: (( f: (a: A) => R + , $?: null + ) => (a: A) => R) + & (( f: (a: A, b: B) => R + , b: B + , $?: null + ) => (a: A) => R) + & (( f: (a: A, b: B, c: C) => R + , b: B + , c: C + , $?: null + ) => (a: A) => R) + & (( f: (a: A, b: B, c: C, d: D) => R + , b: B + , c: C + , d: D + , $?: null + ) => (a: A) => R) + & (( f: (a: A, b: B, c: C, d: D, e: E) => R + , b: B + , c: C + , d: D + , e: E + , $?: null + ) => (a: A) => R) declare var fnil: ((f: (a: ?A, ...args: T[]) => R, a: A, From 37103d6f1b65198544629d649dac143d680bff88 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Tue, 23 Feb 2016 17:57:34 -0800 Subject: [PATCH 09/15] Introduce `Keyed` to describe functions that work on `Associative` and `Set` values --- mori.js.flow | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 48009e4..213a3ad 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -19,6 +19,7 @@ declare function hash(x: any): number */ declare class _Collection {} declare class _Associative {} +declare class _Keyed {} declare class _Seq extends _Collection {} declare class _Sequential extends _Collection {} declare class _Stack extends _Collection {} @@ -28,6 +29,7 @@ declare class _Stack extends _Collection {} */ export type Collection = _Collection export type Associative = _Associative +export type Keyed = _Keyed export type Seq = _Seq export type Sequential = _Sequential export type Stack = _Stack @@ -42,6 +44,7 @@ export type List = Collection export type Map = Associative & Collection> + & Keyed export type Queue = Collection & Seq @@ -49,9 +52,11 @@ export type Queue = Collection & Stack export type Set = Collection + & Keyed export type Vector = Associative & Collection + & Keyed & Sequential /* Other Types */ @@ -145,13 +150,13 @@ declare function assoc>( coll: S declare function dissoc>(coll: S, ...keys: K[]): S declare function distinct>(coll: S): S declare function empty>(coll: S): S -declare var get: ((coll: Associative, key: K, notFound: V_) => V|V_) // TODO: `get` works on A[] - & ((coll: Associative, key: K) => ?V) +declare var get: ((coll: Keyed, key: K, notFound: V_) => V|V_) // TODO: `get` works on A[] + & ((coll: Keyed, key: K) => ?V) & ((coll: Pair, key: 0) => K) & ((coll: Pair, key: 1) => V) -declare var getIn: ((coll: Associative, keys: Seqable, notFound: V_) => V|V_) - & ((coll: Associative, keys: Seqable) => ?V) -declare function hasKey(coll: Associative | Set, key: K): boolean // TODO: `hasKey` works on A[] +declare var getIn: ((coll: Keyed, keys: Seqable, notFound: V_) => V|V_) + & ((coll: Keyed, keys: Seqable) => ?V) +declare function hasKey(coll: Keyed, key: K): boolean // TODO: `hasKey` works on A[] declare function find(coll: Associative, key: K): ?Pair declare var nth: ((coll: Indexed, index: number) => ?A) & ((coll: Pair, index: 0) => K) From d8ec7374f36a57577db1f4e974ab74263ded8f65 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Tue, 23 Feb 2016 23:38:02 -0800 Subject: [PATCH 10/15] Remove duplicate declaration of `isCollection` --- mori.js.flow | 2 -- 1 file changed, 2 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 213a3ad..10f5a8b 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -132,7 +132,6 @@ declare function isIndexed(coll: any): boolean declare function isReduceable(coll: any): boolean declare function isSeqable(coll: any): boolean declare function isReversible(coll: any): boolean -declare function isCollection(coll: any): boolean declare function isKeyword(x: any): boolean declare function isSymbol(x: any): boolean @@ -571,7 +570,6 @@ export { isReduceable, isSeqable, isReversible, - isCollection, isKeyword, isSymbol, From 074675df6ce6a025c66936f293e40b6dccb459bb Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Sat, 27 Feb 2016 19:59:38 -0800 Subject: [PATCH 11/15] Skip undefined result check for `first`, `second`, `last`, `peek`, `nth` --- mori.js.flow | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 10f5a8b..539491d 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -157,10 +157,10 @@ declare var getIn: ((coll: Keyed, keys: Seqable, notFoun & ((coll: Keyed, keys: Seqable) => ?V) declare function hasKey(coll: Keyed, key: K): boolean // TODO: `hasKey` works on A[] declare function find(coll: Associative, key: K): ?Pair -declare var nth: ((coll: Indexed, index: number) => ?A) +declare var nth: ((coll: Indexed, index: number) => A) & ((coll: Pair, index: 0) => K) & ((coll: Pair, index: 1) => V) -declare var last: ((coll: Seqable) => ?A) +declare var last: ((coll: Seqable) => A) & ((coll: Pair) => V) declare function assocIn>(coll: S, keys: Seqable, val: V): S declare function updateIn>(coll: S, @@ -168,7 +168,7 @@ declare function updateIn>(coll: S, f: (_: V) => V): S declare function count(coll: Seqable): number declare function isEmpty(coll: Seqable): boolean -declare function peek(coll: Stack): ?A +declare function peek(coll: Stack): A declare function pop>(coll: S): S declare function zipmap(xs: Seqable, ys: Seqable): Map declare function reverse(coll: Seqable): Seq @@ -194,9 +194,9 @@ declare function isSuperset(seta: Set, setb: Set): boolean /* Sequences */ -declare var first: ((coll: Seqable) => ?A) +declare var first: ((coll: Seqable) => A) & ((coll: Pair) => K) -declare var second: ((coll: Seqable) => ?A) +declare var second: ((coll: Seqable) => A) & ((coll: Pair) => V) declare function rest(coll: Seqable): Seq declare function next(coll: Seqable): Seq From f583b7310d83d2d14ba099c17479b4c784c6f599 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Sat, 27 Feb 2016 23:33:28 -0800 Subject: [PATCH 12/15] Accept non-boolean return values from predicate callbacks --- mori.js.flow | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index 539491d..8d2c3b7 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -82,6 +82,8 @@ declare export class Pair {} declare export class Keyword {} declare export class Symbol {} +type booleany = any + /* Collection Constructors */ declare function list(...args: A[]): List @@ -276,8 +278,8 @@ declare var mapcat: ((f: (a: A, b: B, c: C, d: D, e: E) => Seqable< ...colls: Seqable[] ) => Seq) -declare function filter(pred: (value: A) => boolean, coll: Seqable): Seq -declare function remove(pred: (value: A) => boolean, coll: Seqable): Seq +declare function filter(pred: (value: A) => booleany, coll: Seqable): Seq +declare function remove(pred: (value: A) => booleany, coll: Seqable): Seq declare var reduce: ((f: (accum: R, value: A) => R, initial: R, coll: Seqable @@ -290,11 +292,11 @@ declare function reduceKV(f: (accum: R, key: K, value: V) => R, coll: Associative ): R declare function take(n: number, coll: Seqable): Seq -declare function takeWhile(f: (value: A) => boolean, coll: Seqable): Seq +declare function takeWhile(f: (value: A) => booleany, coll: Seqable): Seq declare function drop(n: number, coll: Seqable): Seq -declare function dropWhile(f: (value: A) => boolean, coll: Seqable): Seq -declare function some(f: (value: A) => boolean, coll: Seqable): ?A -declare function every(f: (value: A) => boolean, coll: Seqable): boolean +declare function dropWhile(f: (value: A) => booleany, coll: Seqable): Seq +declare function some(f: (value: A) => booleany, coll: Seqable): ?A +declare function every(f: (value: A) => booleany, coll: Seqable): boolean declare var sort: ((cmp: (x: A, y: A) => number, coll: Seqable) => Seq) & ((coll: Seqable) => Seq) declare var sortBy: ((keyfn: (x: A, y: A) => B, cmp: (x: B, y: B) => B, coll: Seqable) => Seq) From 9c611c18f234e9e0bd63f34b2f8c11a18e6b2568 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Sat, 27 Feb 2016 23:40:50 -0800 Subject: [PATCH 13/15] Add overloads to `toJs` for `Seq` and `Pair` --- mori.js.flow | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mori.js.flow b/mori.js.flow index 8d2c3b7..c53f47d 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -548,8 +548,9 @@ declare var fnil: ((f: (a: ?A, ...args: T[]) => R, declare var toClj: ((x: A[]) => Vector) & ((x: { [key: string]: A }) => Map) -declare var toJs: ((x: Sequential | Set) => B[]) +declare var toJs: ((x: Sequential | Set | Seq) => B[]) & ((x: Map) => { [key: string]: B }) + & ((x: Pair) => [K,V]) /* Configure */ From 1af100e01e21609167c6f2b61032695e259a4ad3 Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Sat, 27 Feb 2016 23:59:16 -0800 Subject: [PATCH 14/15] Upgrade to Flow v0.22.0 --- .flowconfig | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.flowconfig b/.flowconfig index f492397..983394c 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,5 +1,6 @@ [ignore] .*/flow-bin/.* +.*[^e].json [include] diff --git a/package.json b/package.json index 5d04940..e753e63 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ }, "dependencies": {}, "devDependencies": { - "flow-bin": "0.21.0", + "flow-bin": "0.22.0", "immutable": "3.5.0", "jasmine-node": "1.7.0" }, From 34e156d86e5243e8e8487153b160ac0da8ed583a Mon Sep 17 00:00:00 2001 From: Jesse Hallett <(none)> Date: Sun, 28 Feb 2016 00:08:15 -0800 Subject: [PATCH 15/15] Reverse telescoping of `partial` type; add type-check test for `curry` On upgrading to Flow v0.22.0, the previous type definition for `partial` resulted in a type error when checking `spec/types-spec.js`. --- mori.js.flow | 52 +++++++++++++++++++++++----------------------- spec/types-spec.js | 8 +++++++ 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/mori.js.flow b/mori.js.flow index c53f47d..c07a4ac 100644 --- a/mori.js.flow +++ b/mori.js.flow @@ -454,32 +454,7 @@ declare var pipeline: ((x: A, ...fs: ((_: T) => R)[] ) => R) -declare var partial: ((f: (...args: T[]) => R, - $?: null - ) => (...args: T[]) => R) - & ((f: (a: A, ...args: T[]) => R, - a: A, - $?: null - ) => (...args: T[]) => R) - & ((f: (a: A, b: B, ...args: T[]) => R, - a: A, - b: B, - $?: null - ) => (...args: T[]) => R) - & ((f: (a: A, b: B, c: C, ...args: T[]) => R, - a: A, - b: B, - c: C, - $?: null - ) => (...args: T[]) => R) - & ((f: (a: A, b: B, c: C, d: D, ...args: T[]) => R, - a: A, - b: B, - c: C, - d: D, - $?: null - ) => (...args: T[]) => R) - & ((f: (a: A, b: B, c: C, d: D, e: E, ...args: T[]) => R, +declare var partial: ((f: (a: A, b: B, c: C, d: D, e: E, ...args: T[]) => R, a: A, b: B, c: C, @@ -487,6 +462,31 @@ declare var partial: ((f: (...args: T[]) => R, e: E, $?: null ) => (...args: T[]) => R) + & ((f: (a: A, b: B, c: C, d: D, ...args: T[]) => R, + a: A, + b: B, + c: C, + d: D, + $?: null + & ((f: (a: A, b: B, c: C, ...args: T[]) => R, + a: A, + b: B, + c: C, + $?: null + ) => (...args: T[]) => R) + & ((f: (a: A, b: B, ...args: T[]) => R, + a: A, + b: B, + $?: null + ) => (...args: T[]) => R) + ) => (...args: T[]) => R) + & ((f: (a: A, ...args: T[]) => R, + a: A, + $?: null + ) => (...args: T[]) => R) + & ((f: (...args: T[]) => R, + $?: null + ) => (...args: T[]) => R) declare var curry: (( f: (a: A) => R , $?: null diff --git a/spec/types-spec.js b/spec/types-spec.js index f47094f..7cc12c5 100644 --- a/spec/types-spec.js +++ b/spec/types-spec.js @@ -99,6 +99,14 @@ describe("type-checking", function () { //var v_/*: Vector */ = f(4); }); + it("'curries' functions", function () { + var v/*: Vector */ = mori.vector(1,2,3); + var f = mori.curry(mori.conj, 4); + var v_/*: Vector */ = f(v); + // Does not type-check: + //var v_/*: Vector */ = f(v); + }); + it("infers that a pair is guaranteed to have two elements with distinct types", function () { var m/*: Map */ = mori.hashMap('foo', 1, 'bar', 2); var p = mori.first(m);