├── .npmignore ├── lib ├── types.js ├── inferers.js ├── type-checks.js └── index.js ├── test ├── fixtures │ ├── missing-return.js │ ├── any-return-value.js │ ├── missing-return-with-mixed.js │ ├── return-regexp.js │ ├── bad-return-value.js │ ├── int8.js │ ├── missing-return-with-nullable.js │ ├── mixed-return-value.js │ ├── binary-return-value.js │ ├── int16.js │ ├── int32.js │ ├── uint16.js │ ├── uint32.js │ ├── uint8.js │ ├── float32.js │ ├── float64.js │ ├── generic-function.js │ ├── callexpr-return-value.js │ ├── numeric-literal-annotations.js │ ├── array-type-annotation.js │ ├── async-function.js │ ├── bad-async-function.js │ ├── bad-tuples.js │ ├── boolean-literal-annotations.js │ ├── bug-108-default-value.js │ ├── string-arguments.js │ ├── string-literal-annotations.js │ ├── bad-default-arguments.js │ ├── bad-string-literal-annotations.js │ ├── const-tracking.js │ ├── infer-member-expression.js │ ├── bad-array-return-value.js │ ├── bad-const-tracking.js │ ├── logical-expression.js │ ├── object-pattern.js │ ├── tuples.js │ ├── bad-function-return-value.js │ ├── logical-or-expression.js │ ├── arrow-function-2.js │ ├── multiple-arguments.js │ ├── optional-arguments.js │ ├── bug-96-iterate-array.js │ ├── class-annotation.js │ ├── default-arguments.js │ ├── enum.js │ ├── poly-args.js │ ├── bad-conditional-expression.js │ ├── bug-xxx-export.js │ ├── interface.js │ ├── pragma-ignore-file.js │ ├── return-object-types.js │ ├── async-function-return-promise.js │ ├── complex-object-types.js │ ├── conditional-expression.js │ ├── optional-properties.js │ ├── bug-107-type-alias.js │ ├── bug-48-export-star.js │ ├── qualified-types.js │ ├── const-tracking-with-new.js │ ├── fancy-generic-function.js │ ├── pragma-opt-in.js │ ├── var-declarations.js │ ├── arrow-function.js │ ├── import-type.js │ ├── bug-8-class-support.js │ ├── import-multiple-types.js │ ├── object-pattern-complex.js │ ├── tuples-assignment-expression.js │ ├── bad-rest-params.js │ ├── infer-member-expression-from-typealias.js │ ├── set-entries.js │ ├── bad-iterable.js │ ├── symbols.js │ ├── bug-30-conditional-return.js │ ├── iterable.js │ ├── bad-rest-params-2.js │ ├── bad-iterable-type.js │ ├── const-tracking-with-new-extended.js │ ├── class-method.js │ ├── export-typed-var.js │ ├── export-class.js │ ├── typeof.js │ ├── bug-7-class-support.js │ ├── interface-extends.js │ ├── map-keys.js │ ├── nested-object-types.js │ ├── map-values.js │ ├── bad-map-values.js │ ├── map-contents.js │ ├── bug-87-bad-check.js │ ├── bug-62-default-params.js │ ├── indexers.js │ ├── intersection.js │ ├── bug-xxx-method-params.js │ ├── infer-member-expression-from-object.js │ ├── new.js │ ├── bug-59-type-annotation-in-loop-again.js │ ├── var-declarations-2.js │ ├── bad-binary-return-value.js │ ├── object-indexer-basic.js │ ├── interface-multi-extends.js │ ├── bad-infer-nested-member-expression-from-typealias.js │ ├── bad-generators-return.js │ ├── bad-generators.js │ ├── bug-68-return-string-literal.js │ ├── bad-class-getter.js │ ├── export-type.js │ ├── infer-nested-member-expression-from-typealias.js │ ├── object-properties.js │ ├── react-proptypes.js │ ├── bug-xxx-assignment-expression.js │ ├── class-implements.js │ ├── generators.js │ ├── rest-params.js │ ├── bad-object-properties.js │ ├── bug-xxx-literal-return.js │ ├── react-parameterized.js │ ├── rest-params-array.js │ ├── bad-class-setter.js │ ├── object-indexer-mixed.js │ ├── bad-conditional-return-value.js │ ├── bug-83-spread-object.js │ ├── class-getter.js │ ├── async-method.js │ ├── class-type-params.js │ ├── bad-object-method.js │ ├── bug-78-not-type-checked-array.js │ ├── bug-98-false-positive-destructuring-expression.js │ ├── bug-98-false-positive-destructuring.js │ ├── object-properties-function.js │ ├── typeof-class.js │ ├── conditional-return-value.js │ ├── bug-76-cannot-read-property-name-of-undefined.js │ ├── class-properties.js │ ├── react-decorator.js │ ├── generators-with-next.js │ ├── bug-59-type-annotation-in-loop.js │ ├── assignment-expression.js │ ├── bug-71-cannot-iterate-void.js │ ├── class-setter.js │ ├── pragma-ignore-statement.js │ ├── type-aliases.js │ ├── bad-object-method-arrow.js │ ├── object-method.js │ ├── bug-82-too-much-inference.js │ └── class-properties-complex.js ├── mocha.opts └── index.js ├── .gitignore ├── .babelrc ├── .travis.yml ├── test-polyfill.js ├── LICENSE.md ├── package.json └── README.md /.npmignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/types.js: -------------------------------------------------------------------------------- 1 | "use strict"; -------------------------------------------------------------------------------- /test/fixtures/missing-return.js: -------------------------------------------------------------------------------- 1 | export default function demo () : Object { 2 | 3 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .settings 2 | node_modules 3 | lib-checked 4 | *.transformed 5 | npm-debug.log 6 | -------------------------------------------------------------------------------- /test/fixtures/any-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): any { 2 | return false; 3 | } -------------------------------------------------------------------------------- /test/fixtures/missing-return-with-mixed.js: -------------------------------------------------------------------------------- 1 | export default function demo () : mixed { 2 | 3 | } -------------------------------------------------------------------------------- /test/fixtures/return-regexp.js: -------------------------------------------------------------------------------- 1 | export default function demo (): RegExp { 2 | return /foo/; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): Object { 2 | return null; 3 | } -------------------------------------------------------------------------------- /test/fixtures/int8.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: int8): int8 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/missing-return-with-nullable.js: -------------------------------------------------------------------------------- 1 | export default function demo () : ?Object { 2 | 3 | } -------------------------------------------------------------------------------- /test/fixtures/mixed-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): mixed { 2 | return false; 3 | } -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "stage-0", 4 | "es2015" 5 | ], 6 | "plugins": [ 7 | ] 8 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | 4 | node_js: 5 | - "0.12" 6 | - "iojs" 7 | - "4.2.1" -------------------------------------------------------------------------------- /test/fixtures/binary-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): boolean { 2 | return 1 > 2; 3 | } -------------------------------------------------------------------------------- /test/fixtures/int16.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: int16): int16 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/int32.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: int32): int32 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/uint16.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: uint16): uint16 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/uint32.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: uint32): uint32 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/uint8.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: uint8): uint8 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/float32.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: float32): float32 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/float64.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: float64): float64 { 2 | return input + 1; 3 | } -------------------------------------------------------------------------------- /test/fixtures/generic-function.js: -------------------------------------------------------------------------------- 1 | export default function demo (value: T): T { 2 | return value; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/callexpr-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): string { 2 | return "test".toString(); 3 | } -------------------------------------------------------------------------------- /test/fixtures/numeric-literal-annotations.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: 1|2): 3 { 2 | return 1 + 2; 3 | } -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter=spec 2 | --require should 3 | --require babel-polyfill 4 | --require ./test-polyfill.js 5 | -------------------------------------------------------------------------------- /test/fixtures/array-type-annotation.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string[]): string { 2 | return input[0]; 3 | } -------------------------------------------------------------------------------- /test/fixtures/async-function.js: -------------------------------------------------------------------------------- 1 | export default async function demo (input: string[]): string { 2 | return input[0]; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-async-function.js: -------------------------------------------------------------------------------- 1 | export default async function demo (input: number[]): string { 2 | return input; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-tuples.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: [number, string]): [string, number] { 2 | return input; 3 | } -------------------------------------------------------------------------------- /test/fixtures/boolean-literal-annotations.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: true|false): true { 2 | return true; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bug-108-default-value.js: -------------------------------------------------------------------------------- 1 | export default function demo ({y = '123'}: {y: string;}): string { 2 | return y; 3 | } -------------------------------------------------------------------------------- /test/fixtures/string-arguments.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string): boolean { 2 | return input.length > 0; 3 | } -------------------------------------------------------------------------------- /test/fixtures/string-literal-annotations.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: "foo"|"bar"): "bar" { 2 | return "bar"; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-default-arguments.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string = 123): string { 2 | return input + input; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-string-literal-annotations.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: "foo"|"bar"): "foo" { 2 | return "bar"; 3 | } -------------------------------------------------------------------------------- /test/fixtures/const-tracking.js: -------------------------------------------------------------------------------- 1 | export default function demo (): boolean { 2 | const result = false; 3 | 4 | return result; 5 | } -------------------------------------------------------------------------------- /test/fixtures/infer-member-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: {name: string}): string { 2 | return input.name; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-array-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): Array { 2 | let foo; 3 | foo = 123; 4 | return foo; 5 | } -------------------------------------------------------------------------------- /test/fixtures/bad-const-tracking.js: -------------------------------------------------------------------------------- 1 | export default function demo (): string { 2 | const result = false; 3 | 4 | return result; 5 | } -------------------------------------------------------------------------------- /test/fixtures/logical-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string): string|number { 2 | return input && input.length; 3 | } -------------------------------------------------------------------------------- /test/fixtures/object-pattern.js: -------------------------------------------------------------------------------- 1 | 2 | export default function demo ({a, b}: {a: string, b: number}): string { 3 | return a; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/tuples.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: [number, string]): [string, number] { 2 | return [input[1], input[0]]; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-function-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): Function { 2 | let foo; 3 | foo = 123; 4 | return foo; 5 | } -------------------------------------------------------------------------------- /test/fixtures/logical-or-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string): string|number { 2 | return input || input.length; 3 | } -------------------------------------------------------------------------------- /test/fixtures/arrow-function-2.js: -------------------------------------------------------------------------------- 1 | export default function demo (input) { 2 | let func = (arg : number) => arg 3 | return func(input) 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/multiple-arguments.js: -------------------------------------------------------------------------------- 1 | export default function demo (foo: string, bar: number): boolean { 2 | return foo.length > 0 && bar > 0; 3 | } -------------------------------------------------------------------------------- /test/fixtures/optional-arguments.js: -------------------------------------------------------------------------------- 1 | export default function demo (foo: string, bar?: number): boolean { 2 | return foo.length > 0 && bar > 0; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bug-96-iterate-array.js: -------------------------------------------------------------------------------- 1 | export default function demo () { 2 | const strategies = []; 3 | for (const strategy of strategies) {} 4 | } -------------------------------------------------------------------------------- /test/fixtures/class-annotation.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Class): Class { 2 | input.prototype.foo = () => 'bar'; 3 | return input; 4 | } -------------------------------------------------------------------------------- /test/fixtures/default-arguments.js: -------------------------------------------------------------------------------- 1 | export default function demo (foo: string, bar: number = 1): boolean { 2 | return foo.length > 0 && bar > 0; 3 | } -------------------------------------------------------------------------------- /test/fixtures/enum.js: -------------------------------------------------------------------------------- 1 | type status = "active" | "inactive"; 2 | 3 | export default function demo (input: status): status { 4 | return "active"; 5 | } -------------------------------------------------------------------------------- /test/fixtures/poly-args.js: -------------------------------------------------------------------------------- 1 | export default function demo (arg: string|Array, fn: Function|RegExp): boolean { 2 | return arg.length > 234; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bad-conditional-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string): string|number { 2 | return input.length > 3 ? input : false; 3 | } -------------------------------------------------------------------------------- /test/fixtures/bug-xxx-export.js: -------------------------------------------------------------------------------- 1 | import {User} from './export-class'; 2 | 3 | export default function demo () { 4 | let user; 5 | user = new User(); 6 | }; -------------------------------------------------------------------------------- /test/fixtures/interface.js: -------------------------------------------------------------------------------- 1 | interface User { 2 | name: string 3 | }; 4 | 5 | export default function demo (input: User): User { 6 | return input; 7 | } -------------------------------------------------------------------------------- /test/fixtures/pragma-ignore-file.js: -------------------------------------------------------------------------------- 1 | // typecheck: ignore file 2 | 3 | export default function demo (input: string = false): number { 4 | return false; 5 | } -------------------------------------------------------------------------------- /test/fixtures/return-object-types.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: any): { 2 | greeting: string; 3 | id: number; 4 | } { 5 | return input; 6 | } -------------------------------------------------------------------------------- /test/fixtures/async-function-return-promise.js: -------------------------------------------------------------------------------- 1 | export default async function demo (input: string[]): Promise { 2 | return Promise.resolve(input[0]); 3 | } -------------------------------------------------------------------------------- /test/fixtures/complex-object-types.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: { 2 | greeting: string; 3 | id: number; 4 | }): boolean { 5 | return false; 6 | } -------------------------------------------------------------------------------- /test/fixtures/conditional-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: string): string|number { 2 | return input.length > 3 ? input : input.length; 3 | } -------------------------------------------------------------------------------- /test/fixtures/optional-properties.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: { 2 | greeting: string; 3 | id?: number; 4 | }): boolean { 5 | return false; 6 | } -------------------------------------------------------------------------------- /test/fixtures/bug-107-type-alias.js: -------------------------------------------------------------------------------- 1 | 2 | type BasicSeq = {captureTime: number}; 3 | 4 | export default function test () { 5 | var k:BasicSeq = {x:1}; 6 | return k; 7 | } -------------------------------------------------------------------------------- /test/fixtures/bug-48-export-star.js: -------------------------------------------------------------------------------- 1 | export * as example from "./export-type"; 2 | 3 | export default function demo (input: string): number { 4 | return input.length; 5 | } -------------------------------------------------------------------------------- /test/fixtures/qualified-types.js: -------------------------------------------------------------------------------- 1 | let T = { 2 | Object, 3 | Array, 4 | } 5 | 6 | export default function demo (foo: T.Object|T.Array): boolean { 7 | return true 8 | } -------------------------------------------------------------------------------- /test/fixtures/const-tracking-with-new.js: -------------------------------------------------------------------------------- 1 | class User { 2 | 3 | } 4 | 5 | export default function demo (): User { 6 | const result = new User; 7 | 8 | return result; 9 | } -------------------------------------------------------------------------------- /test/fixtures/fancy-generic-function.js: -------------------------------------------------------------------------------- 1 | export default function demo (buffer: Buffer, callback: (value: T) => number): number { 2 | return callback(buffer[0]); 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/pragma-opt-in.js: -------------------------------------------------------------------------------- 1 | /* @typecheck: some, production, demo */ 2 | 3 | function bar() {} 4 | 5 | // some some 6 | export default function demo(args: string) {} 7 | -------------------------------------------------------------------------------- /test/fixtures/var-declarations.js: -------------------------------------------------------------------------------- 1 | export default function demo (input) { 2 | let a : Array = input 3 | for(let b : string of a) { 4 | let c : string = b 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/arrow-function.js: -------------------------------------------------------------------------------- 1 | export default function demo (input) { 2 | let func = (arg : number) => { 3 | let x : number = arg 4 | } 5 | return func(input) 6 | } 7 | -------------------------------------------------------------------------------- /test/fixtures/import-type.js: -------------------------------------------------------------------------------- 1 | import type {User} from "./export-type"; 2 | 3 | export default function demo (user: User): User { 4 | const saved = user; 5 | return saved; 6 | } -------------------------------------------------------------------------------- /test-polyfill.js: -------------------------------------------------------------------------------- 1 | require("babel-core/register")({ 2 | "presets": ["stage-1", "es2015"], 3 | "plugins": [ 4 | //"syntax-flow", 5 | "transform-flow-strip-types" 6 | ] 7 | }); 8 | -------------------------------------------------------------------------------- /test/fixtures/bug-8-class-support.js: -------------------------------------------------------------------------------- 1 | class Foo { 2 | bar(v : string) { 3 | } 4 | } 5 | 6 | export default function test () { 7 | const x = new Foo(); 8 | x.bar("hello world"); 9 | } -------------------------------------------------------------------------------- /test/fixtures/import-multiple-types.js: -------------------------------------------------------------------------------- 1 | import type {User, UserCollection} from "./export-type"; 2 | 3 | export default function demo (users: UserCollection): User { 4 | return users[0]; 5 | } -------------------------------------------------------------------------------- /test/fixtures/object-pattern-complex.js: -------------------------------------------------------------------------------- 1 | 2 | export default function demo ({a, b: c, d: {e: f, g: h}}: {a: string; b: number; d: {e: string; g: number}}): string { 3 | return f; 4 | } 5 | -------------------------------------------------------------------------------- /test/fixtures/tuples-assignment-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: [number, string]): [string, number] { 2 | const foo: [string, number] = ["bar", 123]; 3 | return foo; 4 | } -------------------------------------------------------------------------------- /test/fixtures/bad-rest-params.js: -------------------------------------------------------------------------------- 1 | function countArgs(...args: number): number 2 | { 3 | return args.length; 4 | } 5 | 6 | export default function test(): number 7 | { 8 | return countArgs(); 9 | } -------------------------------------------------------------------------------- /test/fixtures/infer-member-expression-from-typealias.js: -------------------------------------------------------------------------------- 1 | export type User = { 2 | name: string; 3 | }; 4 | 5 | export default function demo (input: User): string { 6 | return input.name; 7 | } -------------------------------------------------------------------------------- /test/fixtures/set-entries.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Set): number { 2 | let total = 0; 3 | for (let item of input) { 4 | total += item; 5 | } 6 | return total; 7 | } -------------------------------------------------------------------------------- /test/fixtures/bad-iterable.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: number): number { 2 | let total = 0; 3 | for (let item: string of input) { 4 | total += item; 5 | } 6 | return total; 7 | } -------------------------------------------------------------------------------- /test/fixtures/symbols.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Symbol): Symbol { 2 | return createSymbol('wat'); 3 | } 4 | 5 | 6 | function createSymbol (label) { 7 | return Symbol(label); 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/bug-30-conditional-return.js: -------------------------------------------------------------------------------- 1 | function zero(): number 2 | { 3 | if (true) 4 | return [].length; 5 | } 6 | 7 | export default function test(): number 8 | { 9 | return zero(); 10 | } -------------------------------------------------------------------------------- /test/fixtures/iterable.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Iterable): number { 2 | let total = 0; 3 | for (let item: number of input) { 4 | total += item; 5 | } 6 | return total; 7 | } -------------------------------------------------------------------------------- /test/fixtures/bad-rest-params-2.js: -------------------------------------------------------------------------------- 1 | function countArgs(...args: Array|number): number 2 | { 3 | return args.length; 4 | } 5 | 6 | export default function test(): number 7 | { 8 | return countArgs(); 9 | } -------------------------------------------------------------------------------- /test/fixtures/bad-iterable-type.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Iterable): number { 2 | let total = 0; 3 | for (let item: string of input) { 4 | total += item; 5 | } 6 | return total; 7 | } -------------------------------------------------------------------------------- /test/fixtures/const-tracking-with-new-extended.js: -------------------------------------------------------------------------------- 1 | class Person {} 2 | 3 | class User extends Person {} 4 | 5 | export default function demo (): Person { 6 | const result = new User; 7 | 8 | return result; 9 | } -------------------------------------------------------------------------------- /test/fixtures/class-method.js: -------------------------------------------------------------------------------- 1 | class Foo { 2 | method (): Foo { 3 | return this; 4 | } 5 | } 6 | 7 | export default function wat (): Foo { 8 | const foo = new Foo(); 9 | 10 | return foo.method(); 11 | } -------------------------------------------------------------------------------- /test/fixtures/export-typed-var.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name: string; 3 | } 4 | 5 | export const user: User = {name: 'foo'}; 6 | 7 | export default function demo (input: string): number { 8 | return input.length; 9 | } -------------------------------------------------------------------------------- /test/fixtures/export-class.js: -------------------------------------------------------------------------------- 1 | export class User {} 2 | 3 | export type UserCollection = User[]; 4 | 5 | export default function demo (input: User): UserCollection { 6 | const saved = input; 7 | return [saved]; 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/typeof.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name: string; 3 | }; 4 | 5 | const user: User = { 6 | name: 'bob' 7 | }; 8 | 9 | export default function demo (input: typeof user): string { 10 | return input.name; 11 | } -------------------------------------------------------------------------------- /test/fixtures/bug-7-class-support.js: -------------------------------------------------------------------------------- 1 | class X { 2 | add (x: number, y: number): number { 3 | return x + y; 4 | } 5 | } 6 | 7 | export default function test () { 8 | const x = new X(); 9 | return x.add(12, 23); 10 | } -------------------------------------------------------------------------------- /test/fixtures/interface-extends.js: -------------------------------------------------------------------------------- 1 | interface Thing { 2 | name: string; 3 | }; 4 | 5 | interface User extends Thing { 6 | age: number; 7 | } 8 | 9 | export default function demo (input: User): User { 10 | return input; 11 | } -------------------------------------------------------------------------------- /test/fixtures/map-keys.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Map<*, number>): Map { 2 | const converted = new Map(); 3 | for (let [key, value] of input) { 4 | converted.set(value, key); 5 | } 6 | return converted; 7 | } -------------------------------------------------------------------------------- /test/fixtures/nested-object-types.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: { 2 | greeting: string; 3 | id: number; 4 | nested: { 5 | left: number; 6 | right: number; 7 | } 8 | }): boolean { 9 | return false; 10 | } -------------------------------------------------------------------------------- /test/fixtures/map-values.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Map): Map<*, number> { 2 | const converted = new Map(); 3 | for (let [key, value] of input) { 4 | converted.set(key, value); 5 | } 6 | return converted; 7 | } -------------------------------------------------------------------------------- /test/fixtures/bad-map-values.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Map): Map<*, number> { 2 | const converted = new Map(); 3 | for (let [key, value] of input) { 4 | converted.set(value, key); 5 | } 6 | return converted; 7 | } -------------------------------------------------------------------------------- /test/fixtures/map-contents.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Map): Map { 2 | const converted = new Map(); 3 | for (let [key, value] of input) { 4 | converted.set(value, key); 5 | } 6 | return converted; 7 | } -------------------------------------------------------------------------------- /test/fixtures/bug-87-bad-check.js: -------------------------------------------------------------------------------- 1 | export default function demo (input) { 2 | let foo; 3 | 4 | if (input.yes) { 5 | foo = true; 6 | } 7 | else { 8 | foo = false; 9 | } 10 | 11 | input.result = foo; 12 | 13 | return input; 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/bug-62-default-params.js: -------------------------------------------------------------------------------- 1 | export default function demo (options?: { 2 | option1?: string, 3 | option2?: boolean, 4 | option3?: number 5 | } = { 6 | option3: undefined 7 | }) 8 | { 9 | return options; 10 | } -------------------------------------------------------------------------------- /test/fixtures/indexers.js: -------------------------------------------------------------------------------- 1 | type Visitors = { 2 | [key: string]: Visitor 3 | } 4 | 5 | type Visitor = (path: NodePath) => void; 6 | 7 | 8 | export default function demo (visitor: Visitor): Visitors { 9 | return { 10 | foo: visitor 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/intersection.js: -------------------------------------------------------------------------------- 1 | type Nameable = { 2 | name: string; 3 | }; 4 | 5 | type Locatable = { 6 | address: string; 7 | }; 8 | 9 | export default function demo (input: Nameable & Locatable): string { 10 | return `${input.name} ${input.address}`; 11 | } -------------------------------------------------------------------------------- /test/fixtures/bug-xxx-method-params.js: -------------------------------------------------------------------------------- 1 | export class Thing { 2 | 3 | parent: ?Thing; 4 | 5 | something (): Thing { 6 | return this; 7 | } 8 | 9 | 10 | ['foo'] () { 11 | 12 | } 13 | 14 | } 15 | 16 | 17 | 18 | export default function demo () { 19 | 20 | }; -------------------------------------------------------------------------------- /test/fixtures/infer-member-expression-from-object.js: -------------------------------------------------------------------------------- 1 | export type User = { 2 | name: string; 3 | }; 4 | 5 | export default function demo (input: User): string { 6 | let output = { 7 | name: "test", 8 | address: "123 Fake Street" 9 | }; 10 | return output.name; 11 | } -------------------------------------------------------------------------------- /test/fixtures/new.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor (name: string) { 3 | this.name = name; 4 | } 5 | } 6 | 7 | export default function demo (name: string): any { 8 | let user: ?User; 9 | (() => { 10 | user = new User(name); 11 | })(); 12 | return user; 13 | } 14 | -------------------------------------------------------------------------------- /test/fixtures/bug-59-type-annotation-in-loop-again.js: -------------------------------------------------------------------------------- 1 | type Type = number; 2 | 3 | export default function demo (): number { 4 | let foo: Array = ['foo', 123, 'bar', 456]; 5 | 6 | for (let bar: string|Type of foo) { 7 | // ... 8 | } 9 | 10 | return 123; 11 | } -------------------------------------------------------------------------------- /test/fixtures/var-declarations-2.js: -------------------------------------------------------------------------------- 1 | export default function demo (input): number { 2 | let a : Array = input 3 | for(let b : string of a) { 4 | let c : string = b 5 | if(c == '1') 6 | var x : number = parseFloat(c) 7 | } 8 | if(x != null) 9 | return x 10 | } 11 | -------------------------------------------------------------------------------- /test/fixtures/bad-binary-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (): string { 2 | if (Math.random() >= 0.5) { 3 | return "yes"; 4 | } 5 | else if (Math.random() >= 0.5) { 6 | const str = "yes"; 7 | return str; 8 | } 9 | else { 10 | return 1 > 2; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/object-indexer-basic.js: -------------------------------------------------------------------------------- 1 | type Thing = { 2 | [key: string]: string|number 3 | }; 4 | 5 | export default function demo (key, value): Thing { 6 | const thing: Thing = { 7 | string: "hello world", 8 | number: 123 9 | }; 10 | thing[key] = value; 11 | return thing; 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/interface-multi-extends.js: -------------------------------------------------------------------------------- 1 | interface Thing { 2 | name: string; 3 | }; 4 | interface Person { 5 | age: number; 6 | }; 7 | 8 | interface User extends Thing, Person { 9 | isActive: boolean; 10 | } 11 | 12 | export default function demo (input: User): User { 13 | return input; 14 | } 15 | -------------------------------------------------------------------------------- /test/fixtures/bad-infer-nested-member-expression-from-typealias.js: -------------------------------------------------------------------------------- 1 | export type User = { 2 | name: string; 3 | location: Location; 4 | }; 5 | 6 | export type Location = { 7 | address: string; 8 | } 9 | 10 | export default function demo (input: User): number { 11 | return input.location.address; 12 | } -------------------------------------------------------------------------------- /test/fixtures/bad-generators-return.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: T): T[] { 2 | const items = []; 3 | for (let item of gen(input)) { 4 | items.push(item); 5 | } 6 | return items; 7 | } 8 | 9 | 10 | function* gen (item): Generator { 11 | yield 1; 12 | yield 2; 13 | return 34; 14 | } -------------------------------------------------------------------------------- /test/fixtures/bad-generators.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: T): T[] { 2 | const items = []; 3 | for (let item of gen(input)) { 4 | items.push(item); 5 | } 6 | return items; 7 | } 8 | 9 | 10 | function* gen (item): Generator { 11 | yield 1; 12 | yield false; 13 | return true; 14 | } -------------------------------------------------------------------------------- /test/fixtures/bug-68-return-string-literal.js: -------------------------------------------------------------------------------- 1 | export default function demo (): string { 2 | return foo(); 3 | } 4 | 5 | function foo (): string { 6 | return 'foo'; 7 | } 8 | 9 | class Foo { 10 | constructor() { 11 | this.ret = ''; 12 | } 13 | 14 | MyFunction(): string { 15 | return this.ret; 16 | } 17 | } -------------------------------------------------------------------------------- /test/fixtures/bad-class-getter.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor (name) { 3 | this.name = name; 4 | } 5 | 6 | get length (): number { 7 | return this.name.length; 8 | } 9 | } 10 | 11 | export default function demo (name: string): string { 12 | const user = new User(name); 13 | return user.length; 14 | } 15 | 16 | -------------------------------------------------------------------------------- /test/fixtures/export-type.js: -------------------------------------------------------------------------------- 1 | export type User = { 2 | name: string, 3 | age: number 4 | }; 5 | 6 | export type UserCollection = User[]; 7 | 8 | export const wat = 123; 9 | 10 | export default function demo (input: User): User { 11 | const saved = input; 12 | return saved; 13 | } 14 | 15 | const wat2 = 321; 16 | export {wat2}; 17 | -------------------------------------------------------------------------------- /test/fixtures/infer-nested-member-expression-from-typealias.js: -------------------------------------------------------------------------------- 1 | export type User = { 2 | name: string; 3 | location: Location; 4 | }; 5 | 6 | export type Location = { 7 | address: string; 8 | } 9 | 10 | //export type address = string; 11 | 12 | export default function demo (input: User): string { 13 | return input.location.address; 14 | } -------------------------------------------------------------------------------- /test/fixtures/object-properties.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name?: string; 3 | email?: string; 4 | } 5 | 6 | 7 | 8 | export default function demo (name, email): User { 9 | const user = createUser(); 10 | user.name = name; 11 | user.email = email; 12 | return user; 13 | } 14 | 15 | function createUser (): User { 16 | return {}; 17 | } -------------------------------------------------------------------------------- /test/fixtures/react-proptypes.js: -------------------------------------------------------------------------------- 1 | const React = Object; 2 | 3 | class Foo extends React { 4 | 5 | props: { 6 | bar: string; 7 | }; 8 | 9 | render() { 10 | 11 | } 12 | 13 | } 14 | 15 | export default function demo (props) { 16 | const error = Foo.propTypes.bar(props, 'bar', 'Foo'); 17 | if (error) { 18 | throw error; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/bug-xxx-assignment-expression.js: -------------------------------------------------------------------------------- 1 | const HEADER_OFFSET = 1; 2 | const NEXT_OFFSET = 2; 3 | const FIRST_BLOCK = 3; 4 | 5 | function writeInitialHeader (int32Array: Int32Array) { 6 | const header = HEADER_OFFSET; 7 | const block = FIRST_BLOCK; 8 | int32Array[header + NEXT_OFFSET] = block; 9 | } 10 | 11 | export default function demo () { 12 | 13 | } -------------------------------------------------------------------------------- /test/fixtures/class-implements.js: -------------------------------------------------------------------------------- 1 | interface Thing { 2 | name: string; 3 | }; 4 | interface Person { 5 | age: number; 6 | }; 7 | 8 | 9 | class User implements Thing, Person { 10 | constructor (input: Object) { 11 | this.input = input; 12 | } 13 | } 14 | 15 | export default function demo (input: Object): User { 16 | return new User(input); 17 | } 18 | -------------------------------------------------------------------------------- /test/fixtures/generators.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: T): T[] { 2 | const items = []; 3 | for (let item of gen(input)) { 4 | items.push(item); 5 | } 6 | return items; 7 | } 8 | 9 | 10 | function* gen (item): Generator { 11 | yield 1; 12 | yield 2; 13 | yield 3; 14 | yield item; 15 | return true; 16 | } -------------------------------------------------------------------------------- /test/fixtures/rest-params.js: -------------------------------------------------------------------------------- 1 | export default function countArgs(...args: number[]): number { 2 | return args.length; 3 | } 4 | 5 | export default function countArgs2(...args2: number[]|string[]): number { 6 | return args2.length; 7 | } 8 | 9 | function noAnnotation(...unannotated) { 10 | countArgs2(...unannotated); 11 | return countArgs(...unannotated); 12 | } -------------------------------------------------------------------------------- /test/fixtures/bad-object-properties.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name?: string; 3 | email?: string; 4 | } 5 | 6 | 7 | 8 | export default function demo (name, email): User { 9 | const user = createUser(); 10 | user.name = 234134; 11 | user.name = name; 12 | user.email = email; 13 | return user; 14 | } 15 | 16 | function createUser (): User { 17 | return {}; 18 | } -------------------------------------------------------------------------------- /test/fixtures/bug-xxx-literal-return.js: -------------------------------------------------------------------------------- 1 | export function demoBoolean (): { property: true } { 2 | return { property: true }; 3 | } 4 | 5 | export function demoString (): { property: "string" } { 6 | return { property: "string" }; 7 | } 8 | 9 | export function demoNumber (): { property: 2 } { 10 | return { property: 2 }; 11 | } 12 | 13 | export default demoBoolean 14 | -------------------------------------------------------------------------------- /test/fixtures/react-parameterized.js: -------------------------------------------------------------------------------- 1 | const React = Object; 2 | 3 | type Props = { 4 | bar: string; 5 | } 6 | 7 | class Foo extends React { 8 | 9 | render() { 10 | 11 | } 12 | 13 | } 14 | 15 | export default function demo (props) { 16 | const error = Foo.propTypes.bar(props, 'bar', 'Foo'); 17 | if (error) { 18 | throw error; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/rest-params-array.js: -------------------------------------------------------------------------------- 1 | export default function countArgs(...args: Array): number { 2 | return args.length; 3 | } 4 | 5 | export default function countArgs2(...args2: Array|Array): number { 6 | return args2.length; 7 | } 8 | 9 | function noAnnotation(...unannotated) { 10 | countArgs2(...unannotated); 11 | return countArgs(...unannotated); 12 | } -------------------------------------------------------------------------------- /test/fixtures/bad-class-setter.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor (name) { 3 | this._name = name; 4 | this._called = false; 5 | } 6 | 7 | set name (name: string) { 8 | this._name = name; 9 | } 10 | 11 | } 12 | 13 | export default function demo (name): string { 14 | const user = new User('anonymous'); 15 | user.name = null; 16 | return user.name; 17 | } 18 | 19 | -------------------------------------------------------------------------------- /test/fixtures/object-indexer-mixed.js: -------------------------------------------------------------------------------- 1 | type Thing = { 2 | bool: boolean; 3 | bools: boolean[]; 4 | [key: string]: string|number 5 | }; 6 | 7 | export default function demo (key, value): Thing { 8 | const thing: Thing = { 9 | bool: true, 10 | bools: [true, false], 11 | string: "hello world", 12 | number: 123 13 | }; 14 | thing[key] = value; 15 | return thing; 16 | } 17 | -------------------------------------------------------------------------------- /test/fixtures/bad-conditional-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (opt: ?Object): number|string { 2 | if (opt) { 3 | return opt; 4 | } 5 | else if (Math.random() > 0.3) { 6 | return stringGen(); 7 | } 8 | else { 9 | return numberGen(); 10 | } 11 | } 12 | 13 | function stringGen () { 14 | return "test"; 15 | } 16 | 17 | function numberGen () { 18 | return 123; 19 | } -------------------------------------------------------------------------------- /test/fixtures/bug-83-spread-object.js: -------------------------------------------------------------------------------- 1 | export default function demo (headers) { 2 | const isid = true; 3 | const foo: {a: string;} = {a: "123"}; 4 | const container = { 5 | headers: {}, 6 | something: "else", 7 | 8 | method (): string { 9 | return this.something; 10 | } 11 | } 12 | container.headers = { 'x-user-isid': isid, ...foo, ...headers }; 13 | return container; 14 | } -------------------------------------------------------------------------------- /test/fixtures/class-getter.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor (name) { 3 | this.name = name; 4 | } 5 | 6 | get length (): number { 7 | return this.name.length; 8 | } 9 | 10 | get minusLength (): number { 11 | return -this.length; 12 | } 13 | } 14 | 15 | export default function demo (name: string): number { 16 | const user = new User(name); 17 | return user.length; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /test/fixtures/async-method.js: -------------------------------------------------------------------------------- 1 | export class Thing { 2 | constructor (name: string) { 3 | this.name = name; 4 | } 5 | 6 | async go (age: number): [string, number] { 7 | return [this.name, age]; 8 | } 9 | } 10 | 11 | export default async function demo (input: string[]): [string, number] { 12 | const thing = new Thing(input[0]); 13 | const result = await thing.go(88); 14 | return result; 15 | } 16 | -------------------------------------------------------------------------------- /test/fixtures/class-type-params.js: -------------------------------------------------------------------------------- 1 | export class Thing { 2 | constructor (input: T) { 3 | this.input = input; 4 | } 5 | 6 | get (): T { 7 | return this.input; 8 | } 9 | 10 | foo (): string { 11 | return "123"; 12 | } 13 | } 14 | 15 | 16 | export default function demo (input: Z): [Z, string] { 17 | const instance = new Thing(input); 18 | return [instance.get(), instance.foo()]; 19 | } -------------------------------------------------------------------------------- /test/fixtures/bad-object-method.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name?: string; 3 | email?: string; 4 | } 5 | 6 | 7 | 8 | export default function demo (name, email): User { 9 | const user: User = { 10 | name: ("foo": string), 11 | email: ("bar@example.com": string), 12 | 13 | something (): User { 14 | this.name = 123; 15 | return this; 16 | } 17 | }; 18 | 19 | return user.something(); 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/bug-78-not-type-checked-array.js: -------------------------------------------------------------------------------- 1 | function findBlocks(el: HTMLElement): Array { 2 | let blocks = []; 3 | 4 | if (el.hasAttribute('rt-is') || getComponentSubclass(el.tagName.toLowerCase())) { 5 | blocks.push(el); 6 | } 7 | 8 | blocks.push.apply(blocks, el.querySelectorAll(getComponentSelector())); 9 | 10 | return blocks; 11 | } 12 | 13 | 14 | export default function demo () { 15 | 16 | } -------------------------------------------------------------------------------- /test/fixtures/bug-98-false-positive-destructuring-expression.js: -------------------------------------------------------------------------------- 1 | type TypeDateTime = { 2 | date: string, 3 | time: string 4 | }; 5 | 6 | type TypeAction = { 7 | data: Object, 8 | name: string 9 | }; 10 | 11 | const demo = ({date, time}: TypeDateTime) : TypeAction => ({ 12 | data: { 13 | date, 14 | time 15 | }, 16 | name: 'DATE_TIME' 17 | }); 18 | 19 | 20 | export default demo; 21 | -------------------------------------------------------------------------------- /test/fixtures/bug-98-false-positive-destructuring.js: -------------------------------------------------------------------------------- 1 | type TypeDateTime = { 2 | date: string, 3 | time: string 4 | }; 5 | 6 | type TypeAction = { 7 | data: Object, 8 | name: string 9 | }; 10 | 11 | const demo = ({date, time}: TypeDateTime) : TypeAction => { 12 | return { 13 | data: { 14 | date, 15 | time 16 | }, 17 | name: 'DATE_TIME' 18 | }; 19 | }; 20 | 21 | export default demo; 22 | -------------------------------------------------------------------------------- /test/fixtures/object-properties-function.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name?: string; 3 | email?: string; 4 | } 5 | 6 | 7 | 8 | export default function demo (name, email): User { 9 | const user = createUser(); 10 | user.name = name; 11 | user.email = email; 12 | return user; 13 | } 14 | 15 | function createUser (): User { 16 | return { 17 | activate: activate 18 | }; 19 | } 20 | 21 | 22 | function activate () { 23 | this.active = true; 24 | } -------------------------------------------------------------------------------- /test/fixtures/typeof-class.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor (name: string) { 3 | this.name = name; 4 | } 5 | } 6 | 7 | const user: User = new User('bob'); 8 | 9 | export default function demo (input: string|boolean): typeof user { 10 | return typeof input === 'string' ? create(input) : nope("nope"); 11 | } 12 | 13 | 14 | function create (name: string) { 15 | return new User(name); 16 | } 17 | 18 | function nope (name: string) { 19 | return name; 20 | } -------------------------------------------------------------------------------- /test/fixtures/conditional-return-value.js: -------------------------------------------------------------------------------- 1 | export default function demo (opt: ?Object): number|string { 2 | if (opt) { 3 | return identity(opt); 4 | } 5 | else if (Math.random() > 0.3) { 6 | return stringGen(); 7 | } 8 | else { 9 | return numberGen(); 10 | } 11 | } 12 | 13 | function stringGen () { 14 | return "test"; 15 | } 16 | 17 | function numberGen () { 18 | return 123; 19 | } 20 | 21 | function identity (input) { 22 | return input; 23 | } -------------------------------------------------------------------------------- /test/fixtures/bug-76-cannot-read-property-name-of-undefined.js: -------------------------------------------------------------------------------- 1 | class Bar { 2 | 3 | } 4 | 5 | class Foo { 6 | _bar: Bar; 7 | 8 | constructor() { 9 | this._bar = new Bar(); 10 | } 11 | 12 | setBar(): void { 13 | let bar: ?Bar = null; 14 | 15 | if (bar != null) { 16 | this._bar = bar; 17 | } 18 | } 19 | } 20 | 21 | 22 | 23 | export default function demo (): Bar { 24 | const foo = new Foo(); 25 | foo.setBar(); 26 | return foo._bar; 27 | } -------------------------------------------------------------------------------- /test/fixtures/class-properties.js: -------------------------------------------------------------------------------- 1 | class User { 2 | name: string; 3 | email: string; 4 | age: number; 5 | 6 | constructor (name, email, age = 123) { 7 | this.name = name; 8 | this.email = email; 9 | this.age = age; 10 | } 11 | method (input: string|boolean, extra: false): User { 12 | return this; 13 | } 14 | } 15 | 16 | export default function demo (name, email): User { 17 | const user = new User(name, email); 18 | return user.method('str', false); 19 | } -------------------------------------------------------------------------------- /test/fixtures/react-decorator.js: -------------------------------------------------------------------------------- 1 | const Component = Object; 2 | let _tmp; 3 | 4 | function decorator(Component) { 5 | _tmp = Component; 6 | return true; 7 | } 8 | 9 | @decorator 10 | class Foo extends Component { 11 | 12 | props: { 13 | bar: string; 14 | }; 15 | 16 | render() { 17 | } 18 | 19 | } 20 | 21 | export default function demo (props) { 22 | const error = _tmp.propTypes.bar(props, 'bar', 'Foo'); 23 | if (error) { 24 | throw error; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/fixtures/generators-with-next.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: T): T[] { 2 | const items = []; 3 | const it = gen(); 4 | let next; 5 | while (!(next = it.next(input)).done) { 6 | let yieldedValue = next.value; 7 | items.push(yieldedValue); 8 | } 9 | return items; 10 | } 11 | 12 | 13 | function* gen (): Generator { 14 | let last: number = 0; 15 | last = yield 1; 16 | last = yield 2 + last; 17 | last = yield 3 + last; 18 | return true; 19 | } -------------------------------------------------------------------------------- /test/fixtures/bug-59-type-annotation-in-loop.js: -------------------------------------------------------------------------------- 1 | export default function demo (): number { 2 | let foo: Array = []; 3 | let total = 0; 4 | for (let bar: string of foo) { 5 | total += foo.length; 6 | } 7 | for (let bar: string of foo) 8 | total += foo.length; 9 | 10 | for (let i: number = 0, blah: string = ["a", "b", "c"].join(); i < foo.length; i++) { 11 | total += foo.length; 12 | } 13 | 14 | for (let prop: string in demo) { 15 | total += prop.length; 16 | } 17 | return total; 18 | } -------------------------------------------------------------------------------- /test/fixtures/assignment-expression.js: -------------------------------------------------------------------------------- 1 | export default function demo (input: Array): string { 2 | let items: Array = input; 3 | items = [1, 2, 3]; 4 | items = [4, 5, 6]; 5 | items = makeArray(); 6 | ((items = 456): number); 7 | items = 123; 8 | (items: string); 9 | items = "wat"; 10 | items = makeString(); 11 | 12 | items = "foo"; 13 | 14 | return items; 15 | } 16 | 17 | 18 | function makeArray (): Array { 19 | return [7, 8, 9]; 20 | } 21 | 22 | function makeString (): string { 23 | return "foo bar"; 24 | } -------------------------------------------------------------------------------- /test/fixtures/bug-71-cannot-iterate-void.js: -------------------------------------------------------------------------------- 1 | const got = []; 2 | 3 | class Foo { 4 | constructor() { 5 | this.foo = ["a", "b", "c"]; 6 | } 7 | 8 | myFunction(): void { 9 | for (let f: string of this.foo) { 10 | got.push(f); 11 | } 12 | } 13 | 14 | myFunction2(): void { 15 | for (f of this.foo) { 16 | got.push(f); 17 | } 18 | var f; 19 | } 20 | } 21 | 22 | export default function demo (): string[] { 23 | const foo = new Foo (); 24 | foo.myFunction(); 25 | foo.myFunction2(); 26 | return got; 27 | } -------------------------------------------------------------------------------- /test/fixtures/class-setter.js: -------------------------------------------------------------------------------- 1 | class User { 2 | constructor (name) { 3 | this._name = name; 4 | this._called = false; 5 | } 6 | 7 | get name (): string { 8 | return this._name; 9 | } 10 | 11 | set name (name: string) { 12 | this._name = name; 13 | } 14 | 15 | set setterOnly (value: boolean) { 16 | this._called = value; 17 | } 18 | } 19 | 20 | export default function demo (name): string { 21 | const user = new User('anonymous'); 22 | user.name = name; 23 | user.setterOnly = true; 24 | return user.name; 25 | } 26 | 27 | -------------------------------------------------------------------------------- /test/fixtures/pragma-ignore-statement.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Do something 3 | */ 4 | export default function demo (input: string): number { 5 | 6 | /* typecheck: ignore statement */ 7 | let foo: string = 123; 8 | 9 | /* typecheck: ignore statement */ 10 | foo = 123; 11 | 12 | return input.length * 2; 13 | } 14 | 15 | // typecheck: ignore statement 16 | function badFnLine (input: string = 123): boolean { 17 | return input; 18 | } 19 | 20 | /* typecheck: ignore statement */ 21 | function badFnBlock (input: string = 123): boolean { 22 | return input; 23 | } 24 | -------------------------------------------------------------------------------- /test/fixtures/type-aliases.js: -------------------------------------------------------------------------------- 1 | type Blob = Buffer; 2 | type integer = number; 3 | type str = string; 4 | type strOrNumber = string|number; 5 | type arr = Array; 6 | type strings = Array; 7 | type obj = { 8 | name: string, 9 | age: number, 10 | location: { 11 | city: arr, 12 | wat: mixed, 13 | qux: any, 14 | blub: Function 15 | } 16 | }; 17 | export default function demo (value: T, extra: string, wat: {foo: string, bar: number|Array}): T|string { 18 | const someValue: string = "123"; 19 | return value + someValue; 20 | } 21 | -------------------------------------------------------------------------------- /test/fixtures/bad-object-method-arrow.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name?: string; 3 | email?: string; 4 | } 5 | 6 | 7 | 8 | export default function demo (name, email): string { 9 | const user: User = { 10 | name: ("foo": string), 11 | email: ("bar@example.com": string), 12 | 13 | something (): User { 14 | this.name = name; 15 | return this; 16 | }, 17 | 18 | other: function (): string { 19 | const foo = () => { 20 | this.email = {}; 21 | return 'foo'; 22 | }; 23 | return foo(); 24 | } 25 | }; 26 | 27 | return user.something().other(); 28 | } 29 | -------------------------------------------------------------------------------- /test/fixtures/object-method.js: -------------------------------------------------------------------------------- 1 | type User = { 2 | name?: string; 3 | email?: string; 4 | } 5 | 6 | 7 | 8 | export default function demo (name, email): string { 9 | const user: User = { 10 | name: ("foo": string), 11 | email: ("bar@example.com": string), 12 | 13 | something (): User { 14 | this.name = name; 15 | return this; 16 | }, 17 | 18 | other: function (): string { 19 | const foo = () => { 20 | this.email = 'test@example.com'; 21 | return 'foo'; 22 | }; 23 | return foo(); 24 | } 25 | }; 26 | 27 | return user.something().other(); 28 | } 29 | -------------------------------------------------------------------------------- /test/fixtures/bug-82-too-much-inference.js: -------------------------------------------------------------------------------- 1 | const KEY_COMPONENT = Symbol('foo'); 2 | 3 | export default function demo () { 4 | let Component = createClass({ 5 | constructor(block, options) { 6 | if (options.init) { 7 | this.init = options.init; 8 | } 9 | if (options.dispose) { 10 | this.dispose = options.dispose; 11 | } 12 | 13 | block[KEY_COMPONENT] = this; 14 | }, 15 | 16 | init: null, 17 | dispose: null 18 | }); 19 | 20 | return Component.constructor({}, {init: 123, dispose: 456}); 21 | } 22 | 23 | function createClass (input) { 24 | return input; 25 | } -------------------------------------------------------------------------------- /test/fixtures/class-properties-complex.js: -------------------------------------------------------------------------------- 1 | type Location = { 2 | address: string; 3 | country: CountryCode; 4 | pos: GeoPoint; 5 | }; 6 | 7 | type CountryCode = "GB" | "US" | "FR" | "CA"; // Sorry everyone else! 8 | 9 | type GeoPoint = { 10 | lat: number; 11 | lon: number; 12 | } 13 | class Thing { 14 | name: string; 15 | go (age: number): [string, number] { 16 | return [this.name, age]; 17 | } 18 | } 19 | 20 | class User { 21 | name: string; 22 | email: string; 23 | age: number; 24 | location: Location; 25 | 26 | constructor (name, email, age = 123) { 27 | this.name = name; 28 | this.email = email; 29 | this.age = age; 30 | } 31 | method (input: string|boolean, extra: false): User { 32 | return this; 33 | } 34 | setLocation (input): User { 35 | this.location = input; 36 | return this; 37 | } 38 | } 39 | 40 | export default function demo (name: string, email: string, location: Object, country): User { 41 | const user = new User(name, email); 42 | user.setLocation(location); 43 | user.location.country = country; 44 | user.nope = 123; 45 | return user.method('str', false); 46 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2015 codemix.com 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "babel-plugin-typecheck", 3 | "version": "3.9.0", 4 | "description": "Transforms flow type annotations into runtime type checks.", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "build": "babel --plugins syntax-flow,transform-flow-strip-types -d ./lib ./src", 8 | "build-typed": "npm run build && babel --plugins ../lib,syntax-flow,transform-flow-strip-types -d ./lib-checked ./src", 9 | "prepublish": "npm run test-checked", 10 | "pretest": "npm run build", 11 | "test": "mocha ./test/index.js", 12 | "test-checked": "npm run build-typed && TYPECHECK_USE_LIBCHECKED=1 mocha ./test/index.js", 13 | "watch": "NODE_WATCH=1 mocha --watch" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/codemix/babel-plugin-typecheck" 18 | }, 19 | "keywords": [ 20 | "babel", 21 | "babel-plugin", 22 | "types", 23 | "typing", 24 | "typecheck", 25 | "type check", 26 | "flow" 27 | ], 28 | "author": "Charles Pick ", 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/codemix/babel-plugin-typecheck/issues" 32 | }, 33 | "homepage": "https://github.com/codemix/babel-plugin-typecheck", 34 | "dependencies": { 35 | "babel-generator": "^6.7.7" 36 | }, 37 | "devDependencies": { 38 | "babel-cli": "^6.7.7", 39 | "babel-core": "^6.1.0", 40 | "babel-plugin-syntax-class-properties": "^6.1.18", 41 | "babel-plugin-syntax-flow": "^6.0.14", 42 | "babel-plugin-transform-decorators-legacy": "^1.0.0", 43 | "babel-plugin-transform-es2015-modules-commonjs": "^6.1.3", 44 | "babel-plugin-transform-flow-strip-types": "^6.0.14", 45 | "babel-polyfill": "^6.0.16", 46 | "babel-preset-es2015": "^6.6.0", 47 | "babel-preset-react": "^6.5.0", 48 | "babel-preset-stage-0": "^6.5.0", 49 | "babel-preset-stage-1": "^6.5.0", 50 | "mocha": "~2.2.4", 51 | "should": "^6.0.1" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /lib/inferers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | 7 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 8 | 9 | exports.default = make; 10 | /** 11 | * Register the builtin type inferers and return a function which can infer the type of 12 | * a given node path. 13 | */ 14 | function make(_ref) { 15 | var t = _ref.types; 16 | var template = _ref.template; 17 | 18 | var INFERENCE_TYPES = {}; 19 | 20 | /** 21 | * Register a new type inference for the given node type. 22 | */ 23 | function register(type, fn) { 24 | INFERENCE_TYPES[type] = fn; 25 | } 26 | 27 | /** 28 | * Infer the type of the given node path and return an annotation. 29 | */ 30 | function inferType(path) { 31 | var inferer = INFERENCE_TYPES[path.type]; 32 | if (inferer) { 33 | return inferer(path); 34 | } else { 35 | console.log('Unsupported Type: ' + path.type); 36 | return path.getTypeAnnotation() || t.anyTypeAnnotation(); 37 | } 38 | } 39 | 40 | function lookupGlobalIdentifier(name) { 41 | switch (name) { 42 | case 'Symbol': 43 | return t.functionTypeAnnotation(null, [], null, t.anyTypeAnnotation()); 44 | return t.functionTypeAnnotation(null, [t.functionTypeParam(t.identifier('key'), t.stringTypeAnnotation())], null, t.anyTypeAnnotation() //t.genericTypeAnnotation(t.identifier('Symbol')) 45 | ); 46 | default: 47 | return t.anyTypeAnnotation(); 48 | } 49 | } 50 | 51 | register('ObjectExpression', function (path) { 52 | var _path$get$reduce = path.get('properties').reduce(function (_ref2, prop) { 53 | var _ref3 = _slicedToArray(_ref2, 2); 54 | 55 | var properties = _ref3[0]; 56 | var indexers = _ref3[1]; 57 | 58 | if (prop.node.computed) { 59 | var keyType = inferType(prop.get('key')); 60 | if (keyType.type === 'AnyTypeAnnotation') { 61 | keyType = t.stringTypeAnnotation(); 62 | } 63 | indexers.push(t.objectTypeIndexer(t.identifier('key'), keyType, inferType(prop.get('value')))); 64 | } else { 65 | properties.push(t.objectTypeProperty(prop.node.key, inferType(prop.get('value')))); 66 | } 67 | return [properties, indexers]; 68 | }, [[], []]); 69 | 70 | var _path$get$reduce2 = _slicedToArray(_path$get$reduce, 2); 71 | 72 | var properties = _path$get$reduce2[0]; 73 | var indexers = _path$get$reduce2[1]; 74 | 75 | 76 | return t.objectTypeAnnotation(properties, indexers); 77 | }); 78 | 79 | register('CallExpression', function (path) { 80 | var callee = path.get('callee'); 81 | var annotation = inferType(callee); 82 | dump(annotation); 83 | return t.anyTypeAnnotation(); 84 | }); 85 | 86 | register('Identifier', function (path) { 87 | var binding = path.scope.getBinding(path.node.name); 88 | if (!binding) { 89 | return lookupGlobalIdentifier(path.node.name); 90 | } else { 91 | console.log(binding); 92 | } 93 | }); 94 | 95 | return inferType; 96 | } -------------------------------------------------------------------------------- /lib/type-checks.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | Object.defineProperty(exports, "__esModule", { 4 | value: true 5 | }); 6 | exports.default = make; 7 | var INVALID = exports.INVALID = 0; 8 | var NEEDS_CHECK = exports.NEEDS_CHECK = 1; 9 | var STATICALLY_VERIFIED = exports.STATICALLY_VERIFIED = 3; 10 | 11 | function make(_ref) { 12 | var t = _ref.types; 13 | 14 | var ANNOTATION_TYPES = {}; 15 | 16 | registerAnnotationType('VoidTypeAnnotation', { 17 | compatible: ['VoidTypeAnnotation', 'NullableTypeAnnotation'], 18 | checkAnnotation: function checkAnnotation(expected, candidate) { 19 | if (candidate.type === 'VoidTypeAnnotation') { 20 | return STATICALLY_VERIFIED; 21 | } else { 22 | return NEEDS_CHECK; 23 | } 24 | }, 25 | checkValue: function checkValue(expected, candidate) { 26 | if (t.isIdentifier(candidate) && candidate.node.name === 'undefined') { 27 | return STATICALLY_VERIFIED; 28 | } else { 29 | switch (candidate.type) { 30 | case 'NullLiteral': 31 | case 'ThisExpression': 32 | case 'NewExpression': 33 | case 'ObjectExpression': 34 | case 'ArrayExpression': 35 | case 'FunctionExpression': 36 | case 'ArrowFunctionExpression': 37 | case 'BooleanLiteral': 38 | case 'NumericLiteral': 39 | case 'StringLiteral': 40 | case 'RegExpLiteral': 41 | return INVALID; 42 | case 'Identifier': 43 | return candidate.node.name === 'undefined' ? INVALID : NEEDS_CHECK; 44 | default: 45 | return NEEDS_CHECK; 46 | } 47 | } 48 | }, 49 | runtime: function runtime(expected, id) { 50 | return id + ' === undefined'; 51 | } 52 | }); 53 | 54 | registerAnnotationType('NullLiteralTypeAnnotation', { 55 | compatible: ['NullLiteralTypeAnnotation', 'NullableTypeAnnotation'], 56 | checkAnnotation: function checkAnnotation(expected, candidate) { 57 | if (candidate.type === 'NullLiteralTypeAnnotation') { 58 | return STATICALLY_VERIFIED; 59 | } else { 60 | return NEEDS_CHECK; 61 | } 62 | }, 63 | checkValue: function checkValue(expected, candidate) { 64 | if (candidate.type === 'Identifier' && candidate.node.name === 'undefined') { 65 | return INVALID; 66 | } else if (candidate.type === 'NullLiteral') { 67 | return STATICALLY_VERIFIED; 68 | } else { 69 | switch (candidate.type) { 70 | case 'ThisExpression': 71 | case 'NewExpression': 72 | case 'ObjectExpression': 73 | case 'ArrayExpression': 74 | case 'FunctionExpression': 75 | case 'ArrowFunctionExpression': 76 | case 'BooleanLiteral': 77 | case 'NumericLiteral': 78 | case 'StringLiteral': 79 | case 'RegExpLiteral': 80 | return INVALID; 81 | default: 82 | return NEEDS_CHECK; 83 | } 84 | } 85 | }, 86 | runtime: function runtime(expected, id) { 87 | return id + ' === null'; 88 | } 89 | }); 90 | 91 | registerLiteralAnnotationType('Boolean'); 92 | registerLiteralAnnotationType('Numeric'); 93 | registerLiteralAnnotationType('String'); 94 | 95 | registerAnnotationType('NullableTypeAnnotation', { 96 | compatible: ['NullableTypeAnnotation', 'NullLiteralTypeAnnotation', 'VoidTypeAnnotation'] 97 | 98 | }); 99 | 100 | /** 101 | * Register an annotation type with the given name / config. 102 | */ 103 | function registerAnnotationType(name, config) { 104 | ANNOTATION_TYPES[name] = config; 105 | } 106 | 107 | /** 108 | * Register a literal annotation type. 109 | */ 110 | function registerLiteralAnnotationType(shortName) { 111 | 112 | var typeName = shortName + 'Literal'; 113 | var annotationName = shortName + 'TypeAnnotation'; 114 | var literalAnnotationName = typeName + 'TypeAnnotation'; 115 | 116 | registerAnnotationType(literalAnnotationName, { 117 | compatible: [literalAnnotationName, annotationName], 118 | checkAnnotation: function checkAnnotation(expected, candidate) { 119 | if (candidate.type === literalAnnotationName) { 120 | if (candidate.value === expected.value) { 121 | return STATICALLY_VERIFIED; 122 | } else { 123 | return INVALID; 124 | } 125 | } else { 126 | return NEEDS_CHECK; 127 | } 128 | }, 129 | checkValue: function checkValue(expected, candidate) { 130 | if (candidate.type === typeName) { 131 | if (candidate.value === expected.value) { 132 | return STATICALLY_VERIFIED; 133 | } else { 134 | return INVALID; 135 | } 136 | } else { 137 | switch (candidate.type) { 138 | case 'NullLiteral': 139 | case 'ThisExpression': 140 | case 'NewExpression': 141 | case 'ObjectExpression': 142 | case 'ArrayExpression': 143 | case 'FunctionExpression': 144 | case 'ArrowFunctionExpression': 145 | case 'BooleanLiteral': 146 | case 'NumericLiteral': 147 | case 'StringLiteral': 148 | case 'RegExpLiteral': 149 | return INVALID; 150 | case 'Identifier': 151 | return candidate.node.name === 'undefined' ? INVALID : NEEDS_CHECK; 152 | default: 153 | return NEEDS_CHECK; 154 | } 155 | } 156 | }, 157 | runtime: function runtime(expected, id) { 158 | return [id + ' === value', { value: expected.value }]; 159 | } 160 | }); 161 | 162 | registerAnnotationType(annotationName, { 163 | compatible: [annotationName, literalAnnotationName], 164 | checkAnnotation: function checkAnnotation(expected, candidate) { 165 | if (candidate.type === literalAnnotationName) { 166 | return STATICALLY_VERIFIED; 167 | } else { 168 | return NEEDS_CHECK; 169 | } 170 | }, 171 | checkValue: function checkValue(expected, candidate) { 172 | if (candidate.type === typeName) { 173 | return STATICALLY_VERIFIED; 174 | } else { 175 | switch (candidate.type) { 176 | case 'NullLiteral': 177 | case 'ThisExpression': 178 | case 'NewExpression': 179 | case 'ObjectExpression': 180 | case 'ArrayExpression': 181 | case 'FunctionExpression': 182 | case 'ArrowFunctionExpression': 183 | case 'BooleanLiteral': 184 | case 'NumericLiteral': 185 | case 'StringLiteral': 186 | case 'RegExpLiteral': 187 | return INVALID; 188 | case 'Identifier': 189 | return candidate.node.name === 'undefined' ? INVALID : NEEDS_CHECK; 190 | default: 191 | return NEEDS_CHECK; 192 | } 193 | } 194 | }, 195 | runtime: function runtime(expected, id) { 196 | switch (shortName) { 197 | case 'String': 198 | return 'typeof ' + id + ' === \'string\''; 199 | case 'Numeric': 200 | return 'typeof ' + id + ' === \'number\''; 201 | case 'Boolean': 202 | return 'typeof ' + id + ' === \'boolean\''; 203 | } 204 | } 205 | }); 206 | } 207 | 208 | function checkStatic(path) {} 209 | 210 | function checkRuntime(path) {} 211 | 212 | return { checkStatic: checkStatic, checkRuntime: checkRuntime }; 213 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Babel Typecheck 2 | 3 | This is a [Babel](https://babeljs.io/) plugin for static and runtime type checking using [flow type](http://flowtype.org/) annotations. 4 | 5 | [![Build Status](https://travis-ci.org/codemix/babel-plugin-typecheck.svg)](https://travis-ci.org/codemix/babel-plugin-typecheck) 6 | 7 | > Note: Now requires babel 6.1, babel 5 users [see the 2.x branch](https://github.com/codemix/babel-plugin-typecheck/tree/2.x). 8 | 9 | # What? 10 | 11 | Turns code like this: 12 | ```js 13 | function sendMessage (to: User, message: string): boolean { 14 | return socket.send(to, message); 15 | } 16 | ``` 17 | into code like this: 18 | ```js 19 | function sendMessage(to, message) { 20 | var _socket$send; 21 | 22 | if (!(to instanceof User)) throw new TypeError("Value of argument 'to' violates contract."); 23 | if (typeof message !== "string") throw new TypeError("Value of argument 'message' violates contract."); 24 | _socket$send = socket.send(to, message); 25 | if (typeof _socket$send !== "boolean") throw new TypeError("Function 'sendMessage' return value violates contract."); 26 | return _socket$send; 27 | } 28 | ``` 29 | 30 | And guards against some silly mistakes, for example the following code will fail to compile with a `SyntaxError`, because the function can return the wrong type. 31 | 32 | ```js 33 | function foo (): boolean { 34 | if (Math.random() > 0.5) { 35 | return "yes"; // <-- SyntaxError - string is not boolean 36 | } 37 | else { 38 | return false; 39 | } 40 | } 41 | 42 | function bar (input: string = 123): string { // <-- SyntaxError: default value is not string 43 | return input + "456"; 44 | } 45 | ``` 46 | 47 | # Installation 48 | 49 | First, install via [npm](https://npmjs.org/package/babel-plugin-typecheck). 50 | ```sh 51 | npm install --save-dev babel-plugin-typecheck 52 | ``` 53 | Then, in your babel configuration (usually in your `.babelrc` file), add `"typecheck"` to your list of plugins: 54 | ```json 55 | { 56 | "plugins": [ 57 | ["typecheck", { 58 | "disable": { 59 | "production": true 60 | } 61 | }] 62 | ] 63 | } 64 | ``` 65 | 66 | The example configuration will disable typecheck when `NODE_ENV=production` which is usually preferable for performance reasons. 67 | 68 | **Important**: This plugin has a dependency on `babel-plugin-syntax-flow` and `babel-plugin-transform-flow-strip-types`. 69 | Without `syntax-flow`, babel will be unable to parse the flow annotation syntax. 70 | Without `transform-flow-strip-types`, the type annotations will be included in the output which will make it unparsable by JS engines. 71 | 72 | If you are not already using the `babel-preset-react` plugin, you **must** install those plugins and include them in your babel configuration (usually `.babelrc`). Put them *after* `typecheck` in the list, e.g. 73 | ```json 74 | { 75 | "plugins": ["typecheck", "syntax-flow", "transform-flow-strip-types"] 76 | } 77 | ``` 78 | If you *are* using `babel-preset-react` you can ignore this warning. 79 | 80 | > **Note** Depending on your babel configuration you may encounter issues where typecheck interferes with other transformations. This can almost always be fixed by adjusting your preset order and setting `"passPerPreset": true` in your `.babelrc`. 81 | 82 | # Examples 83 | 84 | The basic format is similar to [Flow Type Annotations](http://flowtype.org/docs/type-annotations.html). 85 | 86 | Here are a few examples of annotations this plugin supports: 87 | 88 | ```js 89 | function foo( 90 | aNum: number, 91 | anOptionalString: ?string, // will allow null/undefined 92 | anObject: Object, 93 | aDate: Date, 94 | anError: Error, 95 | aUnionType: Object|string, 96 | aClass: User, 97 | aShape: {foo: number, bar: ?string}, 98 | anArray: Array, 99 | arrayOf: string[] | Array, 100 | {x, y}: {x: string, y: number}, // destructuring works 101 | es6Defaults: number = 42 102 | ) : number { 103 | return aNum; 104 | } 105 | ``` 106 | 107 | # Importing and Exporting types. 108 | 109 | You can reuse types across modules using an extension of the ES6 module syntax: 110 | 111 | ***places.js***: 112 | ```js 113 | export type CsvDataType = Array>; 114 | export type LocationType = { 115 | country: string, 116 | sourceNid: string, 117 | locationNid: string, 118 | name: string, 119 | url: string, 120 | alternativeUrl: ?string, 121 | street1: ?string 122 | }; 123 | ``` 124 | ***widget.js***: 125 | ```js 126 | import type { 127 | CsvDataType, 128 | LocationType 129 | } from './places'; 130 | 131 | // You can now use CsvDataType and LocationType just like any other type. 132 | ``` 133 | 134 | Note that in contrast to flow, an imported type **must** be an actual type and cannot be a class or other concrete value. 135 | 136 | # Optimization 137 | 138 | In cases where typecheck can statically verify that the return value is of the correct type, no type checks will be inserted, for instance: 139 | ```js 140 | function bar (): string|Object { 141 | if (Math.random() > 0.5) { 142 | return "yes"; 143 | } 144 | else { 145 | return { 146 | message: "no" 147 | }; 148 | } 149 | } 150 | ``` 151 | will produce no type checks at all, because we can trivially tell that the function can only return one of the two permitted types. 152 | This is also true for simple cases like: 153 | ```js 154 | function createUser (): User { 155 | return new User(); // <-- no typecheck required 156 | } 157 | ``` 158 | This is currently quite limited though, as the plugin can only statically infer the types of literals and very simple expressions, it can't (yet) statically verify e.g. the result of a function call. In those cases a runtime type check is required: 159 | ```js 160 | function createUser (): User { 161 | return User.create(); // <-- produces runtime typecheck 162 | } 163 | ``` 164 | 165 | ## Changes in 3.5.0 166 | 167 | Supports various number types: 168 | 169 | * int8 170 | * uint8 171 | * int16 172 | * uint16 173 | * int32 174 | * uint32 175 | * float32 176 | * float16 177 | 178 | 179 | **Example:** 180 | 181 | ```js 182 | function demo (input: uint8): uint16 { 183 | return input * input; 184 | } 185 | 186 | demo(1); // ok 187 | demo(128); // ok 188 | demo(255); // ok 189 | demo(-1); // TypeError 190 | demo(12.34); // TypeError 191 | demo(1024); // TypeError 192 | demo('nope'); // TypeError 193 | 194 | ``` 195 | 196 | ## Changes in 3.0.0 197 | 198 | ### Supports type aliases: 199 | ```js 200 | type Foo = string|number; 201 | 202 | function demo (input: Foo): string { 203 | return input + ' world'; 204 | } 205 | 206 | demo('hello'); // ok 207 | demo(123); // ok 208 | demo(["not", "a", "Foo"]); // fails 209 | ``` 210 | 211 | ### Better static type inference 212 | ```js 213 | function demo (input: string): string[] { 214 | return makeArray(input); // no return type check required, knows that makeArray is compatible 215 | } 216 | 217 | function makeArray (input: string): string[] { 218 | return [input]; 219 | } 220 | ``` 221 | 222 | ### Type propagation 223 | ```js 224 | function demo (input: string): User { 225 | const user = new User({name: input}); 226 | return user; // No check required, knows that user is the correct type 227 | } 228 | ``` 229 | 230 | ### Assignment tracking 231 | ```js 232 | let name: string = "bob"; 233 | 234 | name = "Bob"; // ok 235 | name = makeString(); // ok 236 | name = 123; // SyntaxError, expected string not number 237 | 238 | function makeString (): string { 239 | return "Sally"; 240 | } 241 | ``` 242 | 243 | ### Type casting 244 | ```js 245 | let name: string = "bob"; 246 | 247 | name = "Bob"; 248 | ((name: number) = 123); 249 | name = 456; 250 | name = "fish"; // SyntaxError, expected number; 251 | ``` 252 | 253 | ### Array type parameters 254 | ```js 255 | function demo (input: string[]): number { 256 | return input.length; 257 | } 258 | 259 | demo(["a", "b", "c"]); // ok 260 | demo([1, 2, 3]); // TypeError 261 | ``` 262 | 263 | ### Shape tracking 264 | ```js 265 | type User = { 266 | name: string; 267 | email: string; 268 | }; 269 | 270 | function demo (input: User): string { 271 | return input.name; 272 | } 273 | 274 | demo({}); // TypeError 275 | demo({name: 123, email: "test@test.com"}); // TypeError 276 | demo({name: "test", email: "test@test.com"}); // ok 277 | ``` 278 | 279 | 280 | ## Pragmas 281 | 282 | Sometimes you might need to disable type checking for a particular file or section of code. 283 | To ignore an entire file, add a comment at the top level scope of the file: 284 | ```js 285 | // typecheck: ignore file 286 | export function wrong (input: string = 123): boolean { 287 | return input + ' nope'; 288 | } 289 | ``` 290 | 291 | To ignore a particular statement: 292 | ```js 293 | let foo: string = "hello world"; 294 | // typecheck: ignore statement 295 | foo = 123; 296 | ``` 297 | 298 | > Note: Because of how typecheck works, it's not possible to ignore individual lines, only entire statements or files. 299 | > So if you ignore e.g. an if statement, the entire body of that statement will be ignored. 300 | 301 | You can also control the disabling and enabling of type checking using the [plugin options](http://babeljs.io/docs/plugins/) and the `@typecheck` pragma. Type checking will be enabled only for files where any of the configured `only` values are found in the `@typecheck` pragma. With babel configuration: 302 | 303 | ``` 304 | "plugins": [ 305 | ["typecheck", { only: ["production", "test"] }], 306 | ... 307 | ] 308 | ``` 309 | 310 | This file would have typechecks enabled 311 | 312 | ``` 313 | // @typecheck: production, some 314 | ``` 315 | 316 | Whereas this file would not: 317 | 318 | ``` 319 | // @typecheck: any, some 320 | ``` 321 | 322 | 323 | 324 | # License 325 | 326 | Published by [codemix](http://codemix.com/) under a permissive MIT License, see [LICENSE.md](./LICENSE.md). 327 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import {parse, transform, traverse} from 'babel-core'; 3 | 4 | if (process.env.NODE_WATCH) { 5 | var typecheck = require('../src').default; 6 | } 7 | else if (process.env.TYPECHECK_USE_LIBCHECKED) { 8 | var typecheck = require('../lib-checked').default; 9 | } 10 | else { 11 | var typecheck = require('../lib').default; 12 | } 13 | 14 | describe('Typecheck', function () { 15 | 16 | ok('react-decorator', {bar: 'bar'}); 17 | ok('react-parameterized', {bar: 'bar'}); 18 | failWith(` 19 | Invalid prop \`bar\` supplied to \`Foo\`. 20 | 21 | Expected: 22 | string 23 | 24 | Got: 25 | number 26 | `, 'react-parameterized', {bar: 3}); 27 | 28 | ok('react-proptypes', {bar: 'bar'}); 29 | failWith(` 30 | Invalid prop \`bar\` supplied to \`Foo\`. 31 | 32 | Expected: 33 | string 34 | 35 | Got: 36 | number 37 | `, 'react-proptypes', {bar: 3}); 38 | ok('bug-108-default-value', {y: ''}); 39 | failWith(` 40 | Value of argument 0 violates contract. 41 | 42 | Expected: 43 | { y: string 44 | } 45 | 46 | Got: 47 | { 48 | y: boolean; 49 | } 50 | `, 'bug-108-default-value', {y: false}); 51 | failWith(` 52 | Value of variable "k" violates contract. 53 | 54 | Expected: 55 | BasicSeq 56 | 57 | Got: 58 | { x: number; 59 | } 60 | `, 'bug-107-type-alias', 123); 61 | okWithOptions('pragma-opt-in', { only: ['test'] }, 1); 62 | failWithOptions('pragma-opt-in', { only: ['production'] }, 1); 63 | okWithOptions('pragma-opt-in', { only: ['production'] }, 'a'); 64 | failWithOptions('pragma-opt-in', { only: ['test', 'production'] }, 1); 65 | okWithOptions('pragma-opt-in', { only: ['test', 'production'] }, 'a'); 66 | ok('pragma-opt-in', 'a'); 67 | 68 | ok('bug-98-false-positive-destructuring', {date: 'string', time: 'string'}); 69 | ok('bug-98-false-positive-destructuring-expression', {date: 'string', time: 'string'}); 70 | ok('bug-96-iterate-array'); 71 | 72 | ok('object-indexer-basic', 'foo', 'bar'); 73 | failWith(` 74 | Function "demo" return value violates contract. 75 | 76 | Expected: 77 | Thing 78 | 79 | Got: 80 | { 81 | string: string; 82 | number: number; 83 | foo: boolean; 84 | } 85 | `, 'object-indexer-basic', 'foo', false); 86 | 87 | ok('object-indexer-mixed', 'foo', 'bar'); 88 | ok('object-indexer-mixed', 'foo', 123); 89 | failWith(` 90 | Function "demo" return value violates contract. 91 | 92 | Expected: 93 | Thing 94 | 95 | Got: 96 | { 97 | bool: boolean; 98 | bools: boolean[]; 99 | string: string; 100 | number: number; 101 | foo: boolean; 102 | }`, 'object-indexer-mixed', 'foo', false); 103 | 104 | ok('int8', 0); 105 | ok('int8', 1); 106 | ok('int8', 12); 107 | ok('int8', 126); 108 | ok('int8', -127); 109 | failWith(` 110 | Value of argument "input" violates contract. 111 | 112 | Expected: 113 | int8 114 | 115 | Got: 116 | number`,'int8', 128); 117 | failWith(` 118 | Value of argument "input" violates contract. 119 | 120 | Expected: 121 | int8 122 | 123 | Got: 124 | number`,'int8', -129); 125 | failWith(` 126 | Value of argument "input" violates contract. 127 | 128 | Expected: 129 | int8 130 | 131 | Got: 132 | number`,'int8', 123.45); 133 | failWith(` 134 | Value of argument "input" violates contract. 135 | 136 | Expected: 137 | int8 138 | 139 | Got: 140 | string`, 'int8', 'nope'); 141 | 142 | ok('uint8', 0); 143 | ok('uint8', 1); 144 | ok('uint8', 2); 145 | ok('uint8', 25); 146 | ok('uint8', 254); 147 | failWith(` 148 | Value of argument "input" violates contract. 149 | 150 | Expected: 151 | uint8 152 | 153 | Got: 154 | number`,'uint8', 256); 155 | failWith(` 156 | Value of argument "input" violates contract. 157 | 158 | Expected: 159 | uint8 160 | 161 | Got: 162 | number`,'uint8', -1); 163 | failWith(` 164 | Value of argument "input" violates contract. 165 | 166 | Expected: 167 | uint8 168 | 169 | Got: 170 | number`,'uint8', 123.45); 171 | failWith(` 172 | Value of argument "input" violates contract. 173 | 174 | Expected: 175 | uint8 176 | 177 | Got: 178 | string`, 'uint8', 'nope'); 179 | 180 | ok('int16', 0); 181 | ok('int16', 3); 182 | ok('int16', 32); 183 | ok('int16', 327); 184 | ok('int16', 32766) 185 | failWith(` 186 | Value of argument "input" violates contract. 187 | 188 | Expected: 189 | int16 190 | 191 | Got: 192 | number`,'int16', 32768); 193 | ok('int16', -32768); 194 | failWith(` 195 | Value of argument "input" violates contract. 196 | 197 | Expected: 198 | int16 199 | 200 | Got: 201 | number`,'int16', -32769); 202 | failWith(` 203 | Value of argument "input" violates contract. 204 | 205 | Expected: 206 | int16 207 | 208 | Got: 209 | number`,'int16', 123.45); 210 | failWith(` 211 | Value of argument "input" violates contract. 212 | 213 | Expected: 214 | int16 215 | 216 | Got: 217 | string`, 'int16', 'nope'); 218 | 219 | ok('uint16', 0); 220 | ok('uint16', 6); 221 | ok('uint16', 65); 222 | ok('uint16', 655); 223 | ok('uint16', 65534); 224 | failWith(` 225 | Value of argument "input" violates contract. 226 | 227 | Expected: 228 | uint16 229 | 230 | Got: 231 | number`,'uint16', 65536); 232 | failWith(` 233 | Value of argument "input" violates contract. 234 | 235 | Expected: 236 | uint16 237 | 238 | Got: 239 | number`,'uint16', -1); 240 | failWith(` 241 | Value of argument "input" violates contract. 242 | 243 | Expected: 244 | uint16 245 | 246 | Got: 247 | number`,'uint16', 123.45); 248 | failWith(` 249 | Value of argument "input" violates contract. 250 | 251 | Expected: 252 | uint16 253 | 254 | Got: 255 | string`, 'uint16', 'nope'); 256 | 257 | ok('int32', 0); 258 | ok('int32', 3); 259 | ok('int32', 32); 260 | ok('int32', 327); 261 | ok('int32', 2147483646) 262 | failWith(` 263 | Value of argument "input" violates contract. 264 | 265 | Expected: 266 | int32 267 | 268 | Got: 269 | number`,'int32', 2147483648); 270 | ok('int32', -2147483648); 271 | failWith(` 272 | Value of argument "input" violates contract. 273 | 274 | Expected: 275 | int32 276 | 277 | Got: 278 | number`,'int32', -2147483649); 279 | failWith(` 280 | Value of argument "input" violates contract. 281 | 282 | Expected: 283 | int32 284 | 285 | Got: 286 | number`,'int32', 123.45); 287 | failWith(` 288 | Value of argument "input" violates contract. 289 | 290 | Expected: 291 | int32 292 | 293 | Got: 294 | string`, 'int32', 'nope'); 295 | 296 | ok('uint32', 0); 297 | ok('uint32', 6); 298 | ok('uint32', 65); 299 | ok('uint32', 655); 300 | ok('uint32', 4294967294); 301 | failWith(` 302 | Value of argument "input" violates contract. 303 | 304 | Expected: 305 | uint32 306 | 307 | Got: 308 | number`,'uint32', 4294967296); 309 | failWith(` 310 | Value of argument "input" violates contract. 311 | 312 | Expected: 313 | uint32 314 | 315 | Got: 316 | number`,'uint32', -1); 317 | failWith(` 318 | Value of argument "input" violates contract. 319 | 320 | Expected: 321 | uint32 322 | 323 | Got: 324 | number`,'uint32', 123.45); 325 | failWith(` 326 | Value of argument "input" violates contract. 327 | 328 | Expected: 329 | uint32 330 | 331 | Got: 332 | string`, 'uint32', 'nope'); 333 | 334 | ok('float32', 1.999); 335 | ok('float32', -1.999); 336 | ok('float32', 1e5); 337 | failWith(` 338 | Value of argument "input" violates contract. 339 | 340 | Expected: 341 | float32 342 | 343 | Got: 344 | number`, 'float32', -3.40282348e+38); 345 | failWith(` 346 | Value of argument "input" violates contract. 347 | 348 | Expected: 349 | float32 350 | 351 | Got: 352 | number`, 'float32', 3.40282348e+38); 353 | failWith(` 354 | Value of argument "input" violates contract. 355 | 356 | Expected: 357 | float32 358 | 359 | Got: 360 | number`, 'float32', 1e48); 361 | failWith(` 362 | Value of argument "input" violates contract. 363 | 364 | Expected: 365 | float32 366 | 367 | Got: 368 | string`, 'float32', 'nope'); 369 | 370 | ok('float64', 123); 371 | ok('float64', -123); 372 | ok('float64', Math.pow(2, 32)); 373 | ok('float64', Math.pow(2, 48)); 374 | ok('float64', Math.pow(2, 53)); 375 | failWith(` 376 | Value of argument "input" violates contract. 377 | 378 | Expected: 379 | float64 380 | 381 | Got: 382 | string`, 'float64', 'nope'); 383 | 384 | 385 | ok('bug-87-bad-check', {}); 386 | ok('class-annotation', class Thing {}); 387 | failWith(` 388 | Value of argument "input" violates contract. 389 | 390 | Expected: 391 | Class 392 | 393 | Got: 394 | boolean`, 'class-annotation', false); 395 | 396 | if (!(() => true).prototype) { 397 | failWith(` 398 | Value of argument "input" violates contract. 399 | 400 | Expected: 401 | Class 402 | 403 | Got: 404 | function`, 'class-annotation', () => true); 405 | } 406 | else { 407 | // environment does not support spec compliant arrow functions. 408 | it.skip(` 409 | Value of argument "input" violates contract. 410 | 411 | Expected: 412 | Class 413 | 414 | Got: 415 | function`); 416 | } 417 | 418 | ok('bug-83-spread-object', {a: 1, b: 2, c: 3}); 419 | ok('bug-82-too-much-inference'); 420 | ok('bug-xxx-assignment-expression'); 421 | ok('bug-xxx-literal-return'); 422 | ok('bug-78-not-type-checked-array'); 423 | ok('bug-76-cannot-read-property-name-of-undefined'); 424 | ok('bug-71-cannot-iterate-void'); 425 | ok('iterable', [1, 2, 3]); 426 | failWith(` 427 | Value of variable "item" violates contract. 428 | 429 | Expected: 430 | number 431 | 432 | Got: 433 | string`, 'iterable', ['a', 'b', 'c']); 434 | failStatic('bad-iterable', [1, 2, 3]); 435 | failStatic('bad-iterable-type', 123); 436 | 437 | ok('bug-68-return-string-literal'); 438 | ok('indexers', foo => null); 439 | ok('object-pattern', {a: 'foo', b: 34}); 440 | failWith(` 441 | Value of argument 0 violates contract. 442 | 443 | Expected: 444 | { a: string; 445 | b: number; 446 | } 447 | 448 | Got: 449 | { a: string; 450 | } 451 | `, 'object-pattern', {a: 'foo'}); 452 | ok('object-pattern-complex', {a: 'foo', b: 34, d: {e: 'bar', g: 123, a: 123}}); 453 | failWith(` 454 | Value of argument 0 violates contract. 455 | 456 | Expected: 457 | { a: string; 458 | b: number; 459 | d: { e: string; 460 | g: number; 461 | }; 462 | } 463 | 464 | Got: 465 | { a: string; 466 | b: number; 467 | d: { e: string; 468 | g: boolean; 469 | a: number; 470 | }; 471 | } 472 | `, 'object-pattern-complex', {a: 'foo', b: 34, d: {e: 'bar', g: false, a: 123}}); 473 | ok('generators', 'foo'); 474 | failWith(` 475 | Function "gen" yielded an invalid value. 476 | 477 | Expected: 478 | number | string 479 | 480 | Got: 481 | boolean`, 'generators', false); 482 | ok('generators-with-next', 12); 483 | failWith(` 484 | Generator "gen" received an invalid next value. 485 | 486 | Expected: 487 | number 488 | 489 | Got: 490 | string`, 'generators-with-next', 'foo'); 491 | failWith(` 492 | Generator "gen" received an invalid next value. 493 | 494 | Expected: 495 | number 496 | 497 | Got: 498 | boolean`, 'generators-with-next', false); 499 | failStatic('bad-generators', 'foo'); 500 | failStatic('bad-generators-return', 'foo'); 501 | ok('object-properties-function', 'bob', 'bob@example.com'); 502 | ok('bug-62-default-params'); 503 | ok('bug-62-default-params', {option1: 'foo'}); 504 | ok('bug-62-default-params', {option1: 'foo', option2: false}); 505 | ok('bug-62-default-params', {option1: 'foo', option2: true, option3: 123}); 506 | failWith(` 507 | Value of optional argument "options" violates contract. 508 | 509 | Expected: 510 | { option1?: string; 511 | option2?: bool; 512 | option3?: number; 513 | } 514 | 515 | Got: 516 | { 517 | option1: boolean; 518 | }`, 'bug-62-default-params', {option1: true}); 519 | failWith(` 520 | Value of optional argument "options" violates contract. 521 | 522 | Expected: 523 | { option1?: string; 524 | option2?: bool; 525 | option3?: number; 526 | } 527 | 528 | Got: 529 | { 530 | option1: string; 531 | option2: string; 532 | }`, 'bug-62-default-params', {option1: 'foo', option2: 'nope'}); 533 | failWith(` 534 | Value of optional argument "options" violates contract. 535 | 536 | Expected: 537 | { option1?: string; 538 | option2?: bool; 539 | option3?: number; 540 | } 541 | 542 | Got: 543 | { 544 | option1: string; 545 | option2: boolean; 546 | option3: string; 547 | }`, 'bug-62-default-params', {option1: 'foo', option2: true, option3: 'nope'}); 548 | ok('bug-xxx-method-params'); 549 | ok('bug-59-type-annotation-in-loop', 'foo'); 550 | ok('bug-59-type-annotation-in-loop-again', 'foo'); 551 | ok('object-method', 'bob', 'bob@example.com'); 552 | failStatic('bad-object-method', 'bob', 'bob@example.com'); 553 | failStatic('bad-object-method-arrow', 'bob', 'bob@example.com'); 554 | failWith(` 555 | Value of "this.name" violates contract. 556 | 557 | Expected: 558 | string 559 | 560 | Got: 561 | boolean`, 'object-method', false, 'bob@example.com'); 562 | ok('object-properties', 'bob', 'bob@example.com'); 563 | failStatic('bad-object-properties', 'bob', 'bob@example.com'); 564 | failWith(` 565 | Value of "user.name" violates contract. 566 | 567 | Expected: 568 | string 569 | 570 | Got: 571 | boolean`, 'object-properties', false, 'bob@example.com'); 572 | failWith(` 573 | Value of "user.email" violates contract. 574 | 575 | Expected: 576 | string 577 | 578 | Got: 579 | boolean`, 'object-properties', 'bob', false); 580 | ok('class-getter', 'alice'); 581 | failStatic('bad-class-getter', 'alice'); 582 | ok('class-setter', 'alice'); 583 | failStatic('bad-class-setter', 'alice'); 584 | failWith(` 585 | Value of argument "name" violates contract. 586 | 587 | Expected: 588 | string 589 | 590 | Got: 591 | number`, 'class-setter', 123); 592 | ok('class-properties-complex', 'sally', 'bob@example.com', { 593 | address: '123 Fake Street', 594 | country: 'FR', 595 | pos: { 596 | lat: 12.34, 597 | lon: 45.67 598 | } 599 | }, 'FR'); 600 | 601 | failWith(` 602 | Value of "user.location.country" violates contract. 603 | 604 | Expected: 605 | CountryCode 606 | 607 | Got: 608 | string`, 'class-properties-complex', 'sally', 'bob@example.com', { 609 | address: '123 Fake Street', 610 | country: 'FR', 611 | pos: { 612 | lat: 12.34, 613 | lon: 45.67 614 | } 615 | }, 'Invalid'); 616 | 617 | failWith(` 618 | Value of "user.location.country" violates contract. 619 | 620 | Expected: 621 | CountryCode 622 | 623 | Got: 624 | boolean`, 'class-properties-complex', 'sally', 'bob@example.com', { 625 | address: '123 Fake Street', 626 | country: 'FR', 627 | pos: { 628 | lat: 12.34, 629 | lon: 45.67 630 | } 631 | }, false); 632 | ok('class-properties', 'bob', 'bob@example.com'); 633 | failWith(` 634 | Value of "this.email" violates contract. 635 | 636 | Expected: 637 | string 638 | 639 | Got: 640 | null`, 'class-properties', 'bob', null); 641 | failWith(` 642 | Value of "this.name" violates contract. 643 | 644 | Expected: 645 | string 646 | 647 | Got: 648 | boolean`, 'class-properties', false, 'bob@example.com'); 649 | ok('string-literal-annotations', 'foo'); 650 | ok('string-literal-annotations', 'bar'); 651 | failWith(` 652 | Value of argument "input" violates contract. 653 | 654 | Expected: 655 | "foo" | "bar" 656 | 657 | Got: 658 | string`, 'string-literal-annotations', 'wat'); 659 | failStatic('bad-string-literal-annotations', 'foo'); 660 | 661 | ok('boolean-literal-annotations', true); 662 | ok('boolean-literal-annotations', false); 663 | failWith(` 664 | Value of argument "input" violates contract. 665 | 666 | Expected: 667 | true | false 668 | 669 | Got: 670 | string`, 'boolean-literal-annotations', 'wat'); 671 | 672 | ok('numeric-literal-annotations', 1); 673 | ok('numeric-literal-annotations', 2); 674 | failWith(` 675 | Value of argument "input" violates contract. 676 | 677 | Expected: 678 | 1 | 2 679 | 680 | Got: 681 | number`, 'numeric-literal-annotations', 3); 682 | 683 | ok('enum', 'active'); 684 | ok('enum', 'inactive'); 685 | failWith(` 686 | Value of argument "input" violates contract. 687 | 688 | Expected: 689 | status 690 | 691 | Got: 692 | string`, 'enum', 'pending'); 693 | 694 | ok('pragma-ignore-statement', 'some string'); 695 | ok('pragma-ignore-file', 'some string'); 696 | 697 | ok('async-method', ['hello world']); 698 | ok('async-function', ['hello world']); 699 | failWith(` 700 | Value of argument "input" violates contract. 701 | 702 | Expected: 703 | string[] 704 | 705 | Got: 706 | number[]`, 'async-function', [123]); 707 | ok('async-function-return-promise', ['a', 'b', 'c']); 708 | failStatic('bad-async-function', 'hello world'); 709 | ok('class-getter', 'alice'); 710 | ok("bug-xxx-export"); 711 | ok('new', 'bob'); 712 | ok('symbols', Symbol('foo')); 713 | failWith(` 714 | Value of argument "input" violates contract. 715 | 716 | Expected: 717 | Symbol 718 | 719 | Got: 720 | string`, 'symbols', 'wat'); 721 | ok('export-typed-var', 'foo'); 722 | ok('bug-48-export-star', 'wat'); 723 | ok('typeof', {name: 'bob'}); 724 | failWith(` 725 | Value of argument "input" violates contract. 726 | 727 | Expected: 728 | typeof user 729 | 730 | Got: 731 | { 732 | name: boolean; 733 | }`, 'typeof', {name: false}); 734 | ok('typeof-class', 'bob'); 735 | failWith(` 736 | Function "demo" return value violates contract. 737 | 738 | Expected: 739 | typeof user 740 | 741 | Got: 742 | string`, 'typeof-class', false); 743 | 744 | ok('intersection', {name: 'bob', address: '123 Fake Street'}); 745 | failWith(` 746 | Value of argument "input" violates contract. 747 | 748 | Expected: 749 | Nameable & Locatable 750 | 751 | Got: 752 | { 753 | name: string; 754 | address: boolean; 755 | }`, 'intersection', {name: 'bob', address: false}); 756 | 757 | ok('set-entries', new Set([1, 2, 3])); 758 | failWith(` 759 | Value of argument "input" violates contract. 760 | 761 | Expected: 762 | Set 763 | 764 | Got: 765 | Set`, 'set-entries', new Set([1, 'b', 3])); 766 | 767 | ok('map-keys', new Map([['a', 1], ['b', 2], ['c', 3]])); 768 | ok('map-values', new Map([['a', 1], ['b', 2], ['c', 3]])); 769 | failWith(` 770 | Function "demo" return value violates contract. 771 | 772 | Expected: 773 | Map<*, number> 774 | 775 | Got: 776 | Map`, 'bad-map-values', new Map([['a', 1], ['b', 2], ['c', 3]])); 777 | 778 | ok('map-contents', new Map([['a', 1], ['b', 2], ['c', 3]])); 779 | failWith(` 780 | Value of argument "input" violates contract. 781 | 782 | Expected: 783 | Map 784 | 785 | Got: 786 | Map`, 'map-contents', new Map([['a', 1], ['b', 2], ['c', 'nope']])); 787 | ok('interface', {name: 'hello world'}); 788 | ok('interface-extends', {name: 'hello world', age: 123}); 789 | ok('interface-multi-extends', {name: 'hello world', age: 123, isActive: true}); 790 | ok('class-implements', {name: 'hello world', age: 123, isActive: true}); 791 | ok('class-type-params', 'hello world'); 792 | ok('class-type-params', ['hello world']); 793 | 794 | ok('array-type-annotation', ['foo', 'bar']); 795 | failWith(` 796 | Value of argument "input" violates contract. 797 | 798 | Expected: 799 | string[] 800 | 801 | Got: 802 | [string, number]`, 'array-type-annotation', ['foo', 123]); 803 | 804 | ok('infer-member-expression-from-object', {name: "bob"}); 805 | ok('logical-expression', 'foo'); 806 | ok('logical-or-expression', 'foo'); 807 | ok('infer-member-expression', {name: "bob"}); 808 | 809 | ok('infer-member-expression-from-typealias', {name: "bob"}); 810 | 811 | ok('infer-nested-member-expression-from-typealias', {name: "bob", location: {address: "123 Fake Street"}}); 812 | failStatic("bad-infer-nested-member-expression-from-typealias", {name: "bob", location: {address: "123 Fake Street"}}); 813 | 814 | failStatic("bad-binary-return-value"); 815 | ok("var-declarations", ["abc", "123"]) 816 | 817 | 818 | ok("tuples", [123, "foobar"]); 819 | ok("tuples-assignment-expression", [123, "foobar"]); 820 | 821 | failStatic("bad-tuples", [123, "foobar"]); 822 | ok("return-regexp"); 823 | 824 | ok("conditional-return-value"); 825 | 826 | failStatic("bad-conditional-return-value"); 827 | 828 | failWith(` 829 | Function "demo" return value violates contract. 830 | 831 | Expected: 832 | number | string 833 | 834 | Got: 835 | { 836 | a: number; 837 | }`, "conditional-return-value", {a: 123}); 838 | 839 | 840 | ok("assignment-expression", [1, 2, 3]); 841 | failStatic("bad-array-return-value"); 842 | 843 | failStatic("bad-function-return-value"); 844 | 845 | ok("type-aliases", "foo", "bar", {foo: "foo", bar: 123}); 846 | ok("generic-function", 123); 847 | ok("fancy-generic-function", Buffer(123), (value) => value); 848 | ok("return-object-types", {greeting: "hello world", id: 123}); 849 | failWith(` 850 | Function "demo" return value violates contract. 851 | 852 | Expected: 853 | { greeting: string; 854 | id: number; 855 | } 856 | 857 | Got: 858 | { 859 | foo: string; 860 | }`, "return-object-types", {foo: "bar"}); 861 | 862 | ok("nested-object-types", {greeting: "hello world", id: 123, nested: {left: 10, right: 20}}); 863 | failWith(` 864 | Value of argument "input" violates contract. 865 | 866 | Expected: 867 | { greeting: string; 868 | id: number; 869 | nested: { left: number; 870 | right: number; 871 | }; 872 | } 873 | 874 | Got: 875 | { 876 | foo: string; 877 | }`, "nested-object-types", {foo: "bar"}); 878 | failWith(` 879 | Value of argument "input" violates contract. 880 | 881 | Expected: 882 | { greeting: string; 883 | id: number; 884 | nested: { left: number; 885 | right: number; 886 | }; 887 | } 888 | 889 | Got: 890 | { 891 | greeting: string; 892 | id: number; 893 | nested: { 894 | left: boolean; 895 | right: boolean; 896 | }; 897 | }`, "nested-object-types", {greeting: "hello world", id: 123, nested: {left: true, right: false}}); 898 | failWith(` 899 | Value of argument "input" violates contract. 900 | 901 | Expected: 902 | { greeting: string; 903 | id: number; 904 | nested: { left: number; 905 | right: number; 906 | }; 907 | } 908 | 909 | Got: 910 | { 911 | greeting: string; 912 | id: number; 913 | nested: { 914 | left: number; 915 | }; 916 | }`, "nested-object-types", {greeting: "hello world", id: 123, nested: {left: 10}}); 917 | failWith(` 918 | Value of argument "input" violates contract. 919 | 920 | Expected: 921 | { greeting: string; 922 | id: number; 923 | nested: { left: number; 924 | right: number; 925 | }; 926 | } 927 | 928 | Got: 929 | { 930 | greeting: string; 931 | id: string; 932 | nested: { 933 | left: number; 934 | right: number; 935 | }; 936 | } 937 | `, "nested-object-types", {greeting: "hello world", id: "123", nested: {left: 10, right: 20}}); 938 | 939 | ok("complex-object-types", {greeting: "hello world", id: 123}); 940 | failWith(` 941 | Value of argument "input" violates contract. 942 | 943 | Expected: 944 | { greeting: string; 945 | id: number; 946 | } 947 | 948 | Got: 949 | { 950 | foo: string; 951 | }`, "complex-object-types", {foo: "bar"}); 952 | failWith(` 953 | Value of argument "input" violates contract. 954 | 955 | Expected: 956 | { greeting: string; 957 | id: number; 958 | } 959 | 960 | Got: 961 | string`, "complex-object-types", "foo"); 962 | 963 | ok("any-return-value"); 964 | ok("callexpr-return-value"); 965 | ok("binary-return-value"); 966 | ok("mixed-return-value"); 967 | ok("string-arguments", "hello world"); 968 | ok("multiple-arguments", "hello world", 123); 969 | ok("const-tracking"); 970 | ok("const-tracking-with-new"); 971 | ok("const-tracking-with-new-extended"); 972 | 973 | failWith(` 974 | Value of argument "input" violates contract. 975 | 976 | Expected: 977 | string 978 | 979 | Got: 980 | void`, 981 | "string-arguments"); 982 | 983 | failWith(` 984 | Value of argument "input" violates contract. 985 | 986 | Expected: 987 | string 988 | 989 | Got: 990 | number`, 991 | "string-arguments", 992 | 123); 993 | 994 | failStatic("bad-const-tracking"); 995 | failStatic("bad-return-value"); 996 | failStatic("bad-default-arguments"); 997 | failStatic("missing-return"); 998 | ok("missing-return-with-nullable"); 999 | ok("missing-return-with-mixed"); 1000 | 1001 | 1002 | ok("class-method"); 1003 | 1004 | 1005 | ok("poly-args", "hello world", /a/); 1006 | ok("poly-args", ["hello world"], /b/); 1007 | failWith(` 1008 | Value of argument \"arg\" violates contract. 1009 | 1010 | Expected: 1011 | string | Array 1012 | 1013 | Got: 1014 | number`, "poly-args", 123); 1015 | failWith(` 1016 | Value of argument \"fn\" violates contract. 1017 | 1018 | Expected: 1019 | Function | RegExp 1020 | 1021 | Got: 1022 | number`, "poly-args", "hello", 123); 1023 | 1024 | ok("bug-7-class-support"); 1025 | ok("bug-8-class-support"); 1026 | 1027 | 1028 | ok("optional-properties", {greeting: "hello world", id: 123}); 1029 | ok("optional-properties", {greeting: "hello world"}); 1030 | failWith(` 1031 | Value of argument "input" violates contract. 1032 | 1033 | Expected: 1034 | { greeting: string; 1035 | id?: number; 1036 | } 1037 | 1038 | Got: 1039 | { 1040 | greeting: string; 1041 | id: string; 1042 | }`, "optional-properties", {greeting: "hello world", id: "123"}); 1043 | failWith(` 1044 | Value of argument "input" violates contract. 1045 | 1046 | Expected: 1047 | { greeting: string; 1048 | id?: number; 1049 | } 1050 | 1051 | Got: 1052 | { 1053 | greeting: string; 1054 | id: null; 1055 | }`, "optional-properties", {greeting: "hello world", id: null}); 1056 | failWith(` 1057 | Value of argument "input" violates contract. 1058 | 1059 | Expected: 1060 | { greeting: string; 1061 | id?: number; 1062 | } 1063 | 1064 | Got: 1065 | { 1066 | id: number; 1067 | }`, "optional-properties", {id: 123}); 1068 | failWith(` 1069 | Value of argument "input" violates contract. 1070 | 1071 | Expected: 1072 | { greeting: string; 1073 | id?: number; 1074 | } 1075 | 1076 | Got: 1077 | { 1078 | foo: string; 1079 | }`, "optional-properties", {foo: "bar"}); 1080 | failWith(` 1081 | Value of argument "input" violates contract. 1082 | 1083 | Expected: 1084 | { greeting: string; 1085 | id?: number; 1086 | } 1087 | 1088 | Got: 1089 | string`, "optional-properties", "foo"); 1090 | 1091 | ok("optional-arguments", "hello world"); 1092 | ok("optional-arguments", "hello world", 123); 1093 | failWith(` 1094 | Value of optional argument "bar" violates contract. 1095 | 1096 | Expected: 1097 | number 1098 | 1099 | Got: 1100 | string`, "optional-arguments", "hello world", "123"); 1101 | failWith(` 1102 | Value of optional argument "bar" violates contract. 1103 | 1104 | Expected: 1105 | number 1106 | 1107 | Got: 1108 | null`, "optional-arguments", "hello world", null); 1109 | 1110 | ok("default-arguments", "hello world"); 1111 | ok("default-arguments", "hello world", 123); 1112 | failWith(` 1113 | Value of argument "bar" violates contract. 1114 | 1115 | Expected: 1116 | number 1117 | 1118 | Got: 1119 | string`, "default-arguments", "hello world", "123"); 1120 | failWith(` 1121 | Value of argument "bar" violates contract. 1122 | 1123 | Expected: 1124 | number 1125 | 1126 | Got: 1127 | null`, "default-arguments", "hello world", null); 1128 | 1129 | ok("qualified-types", {}) 1130 | failWith(` 1131 | Value of argument "foo" violates contract. 1132 | 1133 | Expected: 1134 | T.Object | T.Array 1135 | 1136 | Got: 1137 | string`, "qualified-types", "hello") 1138 | 1139 | ok("var-declarations", ["abc", "123"]) 1140 | failWith(` 1141 | Value of variable "a" violates contract. 1142 | 1143 | Expected: 1144 | Array 1145 | 1146 | Got: 1147 | string`, "var-declarations", "abc") 1148 | failWith(` 1149 | Value of variable "b" violates contract. 1150 | 1151 | Expected: 1152 | string 1153 | 1154 | Got: 1155 | number`, "var-declarations", ["abc", 123]) 1156 | 1157 | ok("var-declarations-2", ["abc", "123"]) 1158 | ok("var-declarations-2", ["abc", "1"]) 1159 | failWith(` 1160 | Value of variable "a" violates contract. 1161 | 1162 | Expected: 1163 | Array 1164 | 1165 | Got: 1166 | string`, "var-declarations-2", "abc") 1167 | failWith(` 1168 | Value of variable "b" violates contract. 1169 | 1170 | Expected: 1171 | string 1172 | 1173 | Got: 1174 | number`, "var-declarations-2", ["abc", 123]) 1175 | 1176 | ok("arrow-function", 123); 1177 | ok("arrow-function-2", 123); 1178 | 1179 | failWith(` 1180 | Value of argument "arg" violates contract. 1181 | 1182 | Expected: 1183 | number 1184 | 1185 | Got: 1186 | string`, "arrow-function", "abc") 1187 | failWith(` 1188 | Value of argument "arg" violates contract. 1189 | 1190 | Expected: 1191 | number 1192 | 1193 | Got: 1194 | string`, "arrow-function-2", "abc") 1195 | 1196 | ok("bug-30-conditional-return"); 1197 | 1198 | ok("rest-params"); 1199 | ok("rest-params", 1); 1200 | ok("rest-params", 10, 20); 1201 | ok("rest-params-array"); 1202 | ok("rest-params-array", 1); 1203 | ok("rest-params-array", 10, 20); 1204 | failStatic("bad-rest-params"); 1205 | failStatic("bad-rest-params-2"); 1206 | 1207 | ok("export-type", {name: "Bob", age: 45}); 1208 | ok("import-type", {name: "Bob", age: 45}); 1209 | ok("import-multiple-types", [{name: "Bob", age: 45}]); 1210 | ok('conditional-expression', 'foo'); 1211 | 1212 | it(`should load itself`, function () { 1213 | this.timeout(60000); // @fixme We are currently unacceptably slow. 1214 | load('/../../src/index'); 1215 | }); 1216 | }); 1217 | 1218 | function load (basename, opts) { 1219 | return loadInternal(basename, opts).exports.default; 1220 | } 1221 | 1222 | function loadInternal (basename, opts) { 1223 | const filename = `${__dirname}/fixtures/${basename}.js`; 1224 | const source = fs.readFileSync(filename, 'utf8'); 1225 | const transformed = transform(source, { 1226 | filename: filename, 1227 | presets: [ 1228 | "es2015", 1229 | "stage-0", 1230 | ], 1231 | plugins: [ 1232 | opts ? [typecheck, opts] : typecheck, 1233 | 'transform-flow-strip-types', 1234 | 'transform-decorators-legacy', 1235 | 'syntax-class-properties' 1236 | ] 1237 | }); 1238 | const context = { 1239 | exports: {} 1240 | }; 1241 | if (process.env.TYPECHECK_SAVE_TRANSFORMED) { 1242 | fs.writeFileSync(`${__dirname}/fixtures/${basename}.js.transformed`, transformed.code, 'utf8'); 1243 | } 1244 | const loaded = new Function('module', 'exports', 'require', transformed.code); 1245 | loaded(context, context.exports, (path) => { 1246 | if (/^\.\//.test(path)) { 1247 | const module = loadInternal(path.slice(2)); 1248 | return module.exports; 1249 | } 1250 | else { 1251 | return require(path); 1252 | } 1253 | }); 1254 | return context; 1255 | } 1256 | 1257 | function isThenable (thing: mixed): boolean { 1258 | return thing && typeof thing.then === 'function'; 1259 | } 1260 | 1261 | function okWithOptions (basename, opts, ...args) { 1262 | it(`should load '${basename}' with options '${JSON.stringify(opts)}'`, async function () { 1263 | const result = load(basename, opts)(...args); 1264 | if (isThenable(result)) { 1265 | await result; 1266 | } 1267 | }); 1268 | } 1269 | 1270 | function failWithOptions (basename, opts, ...args) { 1271 | it(`should not load '${basename}' with options '${JSON.stringify(opts)}'`, async function () { 1272 | let failed = false; 1273 | try { 1274 | const result = load(basename, opts)(...args); 1275 | if (isThenable(result)) { 1276 | await result; 1277 | } 1278 | } 1279 | catch (e) { 1280 | failed = true; 1281 | } 1282 | if (!failed) { 1283 | throw new Error(`Test '${basename}' should have failed but did not.`); 1284 | } 1285 | }); 1286 | } 1287 | 1288 | function ok (basename, ...args) { 1289 | it(`should load '${basename}'`, async function () { 1290 | const result = load(basename)(...args); 1291 | if (isThenable(result)) { 1292 | await result; 1293 | } 1294 | }); 1295 | } 1296 | 1297 | function fail (basename, ...args) { 1298 | it(`should not load '${basename}'`, async function () { 1299 | let failed = false; 1300 | try { 1301 | const result = load(basename)(...args); 1302 | if (isThenable(result)) { 1303 | await result; 1304 | } 1305 | } 1306 | catch (e) { 1307 | failed = true; 1308 | } 1309 | if (!failed) { 1310 | throw new Error(`Test '${basename}' should have failed but did not.`); 1311 | } 1312 | }); 1313 | } 1314 | 1315 | function failWith (errorMessage, basename, ...args) { 1316 | it(`should not load '${basename}'`, async function () { 1317 | let failed = false; 1318 | let message; 1319 | try { 1320 | const result = load(basename)(...args); 1321 | if (isThenable(result)) { 1322 | await result; 1323 | } 1324 | } 1325 | catch (e) { 1326 | failed = true; 1327 | message = e.message; 1328 | } 1329 | if (!failed) { 1330 | throw new Error(`Test '${basename}' should have failed but did not.`); 1331 | } 1332 | // ignore differences in whitespace in comparison. 1333 | if (message.replace(/\s+/g, '') !== errorMessage.replace(/\s+/g, '')) { 1334 | throw new Error(`Test '${basename}' failed with ${message} instead of ${errorMessage}.`); 1335 | } 1336 | }); 1337 | } 1338 | 1339 | 1340 | function failStatic (basename, ...args) { 1341 | it(`should refuse to load '${basename}'`, function () { 1342 | let failed = false; 1343 | try { 1344 | load(basename)(...args); 1345 | } 1346 | catch (e) { 1347 | if (e instanceof SyntaxError) { 1348 | failed = true; 1349 | //console.log(e.toString()); 1350 | } 1351 | else { 1352 | throw e; 1353 | } 1354 | } 1355 | if (!failed) { 1356 | throw new Error(`Test '${basename}' should have failed static verification but did not.`); 1357 | } 1358 | }); 1359 | } 1360 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _slicedToArray=function(){function sliceIterator(arr,i){var _arr=[];var _n=true;var _d=false;var _e=undefined;try{for(var _i=arr[Symbol.iterator](),_s;!(_n=(_s=_i.next()).done);_n=true){_arr.push(_s.value);if(i&&_arr.length===i)break;}}catch(err){_d=true;_e=err;}finally {try{if(!_n&&_i["return"])_i["return"]();}finally {if(_d)throw _e;}}return _arr;}return function(arr,i){if(Array.isArray(arr)){return arr;}else if(Symbol.iterator in Object(arr)){return sliceIterator(arr,i);}else {throw new TypeError("Invalid attempt to destructure non-iterable instance");}};}(); /** 2 | * # Typecheck Transformer 3 | */exports.default=function(_ref){var t=_ref.types;var template=_ref.template; /** 4 | * Binary Operators that can only produce boolean results. 5 | */var BOOLEAN_BINARY_OPERATORS=['==','===','>=','<=','>','<','instanceof'];var checks=createChecks();var staticChecks=createStaticChecks();var checkIsArray=expression('Array.isArray(input)');var checkIsMap=expression('input instanceof Map');var checkIsSet=expression('input instanceof Set');var checkIsClass=expression('typeof input === \'function\' && input.prototype && input.prototype.constructor === input');var checkIsGenerator=expression('typeof input === \'function\' && input.generator');var checkIsIterable=expression('input && (typeof input[Symbol.iterator] === \'function\' || Array.isArray(input))');var checkIsObject=expression('input != null && typeof input === \'object\'');var checkNotNull=expression('input != null');var checkEquals=expression('input === expected');var declareTypeChecker=template('\n const id = (function () {\n function id (input) {\n return check;\n };\n Object.defineProperty(id, Symbol.hasInstance, {\n value: function (input) {\n return id(input);\n }\n });\n return id;\n })();\n ');var guard=template('\n if (!check) {\n throw new TypeError(message);\n }\n ');var thrower=template('\n if (check) {\n ret;\n }\n else {\n throw new TypeError(message);\n }\n ');var guardInline=expression('\n (id => {\n if (!check) {\n throw new TypeError(message);\n }\n return id;\n })(input)\n ');var guardFn=expression('\n function name (id) {\n if (!check) {\n throw new TypeError(message);\n }\n return id;\n }\n ');var readableName=expression('\n inspect(input)\n ');var checkMapKeys=expression('\n input instanceof Map && Array.from(input.keys()).every(key => keyCheck)\n ');var checkMapValues=expression('\n input instanceof Map && Array.from(input.values()).every(value => valueCheck)\n ');var checkMapEntries=expression('\n input instanceof Map && Array.from(input).every(([key, value]) => keyCheck && valueCheck)\n ');var checkSetEntries=expression('\n input instanceof Set && Array.from(input).every(value => valueCheck)\n ');var checkObjectIndexers=expression('\n Object.keys(input).every(key => {\n const value = input[key];\n if (~fixedKeys.indexOf(key)) {\n return true;\n }\n else {\n return check;\n }\n });\n ');var checkObjectIndexersNoFixed=expression('\n Object.keys(input).every(key => {\n const value = input[key];\n return check;\n });\n ');var propType=expression('\n (function(props, name, component) {\n var prop = props[name];\n if(!check) {\n return new Error(\n "Invalid prop `" + name + "` supplied to `" + component\n + "`.\\n\\nExpected:\\n" + expected + "\\n\\nGot:\\n" + got + "\\n\\n"\n );\n }\n })\n ');var PRAGMA_IGNORE_STATEMENT=/typecheck:\s*ignore\s+statement/i;var PRAGMA_IGNORE_FILE=/typecheck:\s*ignore\s+file/i;function skipEnvironment(comments,opts){if(!opts.only){return false;}var envs=pragmaEnvironments(comments);return !opts.only.some(function(env){return envs[env];});}function pragmaEnvironments(comments){var pragma=/@typecheck:\s*(.+)/;var environments={};comments.forEach(function(comment){var m=comment.value.match(pragma);if(m){m[1].split(',').forEach(function(env){return environments[env.trim()]=true;});}});return environments;}var visitors={Statement:function Statement(path){maybeSkip(path);},TypeAlias:function TypeAlias(path){if(maybeSkip(path)){return;}path.replaceWith(createTypeAliasChecks(path));},InterfaceDeclaration:function InterfaceDeclaration(path){if(maybeSkip(path)){return;}path.replaceWith(createInterfaceChecks(path));},ExportNamedDeclaration:function ExportNamedDeclaration(path){if(maybeSkip(path)){return;}var node=path.node;var scope=path.scope;if(node.declaration&&node.declaration.type==='TypeAlias'){var declaration=path.get('declaration');declaration.replaceWith(createTypeAliasChecks(declaration));node.exportKind='value';}},ImportDeclaration:function ImportDeclaration(path){if(maybeSkip(path)){return;}if(path.node.importKind!=='type'){return;}var _path$get$map$reduce=path.get('specifiers').map(function(specifier){var local=specifier.get('local');var tmpId=path.scope.generateUidIdentifierBasedOnNode(local.node);var replacement=t.importSpecifier(tmpId,specifier.node.imported);var id=t.identifier(local.node.name);id.isTypeChecker=true;var declarator=t.variableDeclarator(id,tmpId);declarator.isTypeChecker=true;return [declarator,replacement];}).reduce(function(_ref2,_ref3){var _ref5=_slicedToArray(_ref2,2);var declarators=_ref5[0];var specifiers=_ref5[1];var _ref4=_slicedToArray(_ref3,2);var declarator=_ref4[0];var specifier=_ref4[1];declarators.push(declarator);specifiers.push(specifier);return [declarators,specifiers];},[[],[]]);var _path$get$map$reduce2=_slicedToArray(_path$get$map$reduce,2);var declarators=_path$get$map$reduce2[0];var specifiers=_path$get$map$reduce2[1];var declaration=t.variableDeclaration('var',declarators);declaration.isTypeChecker=true;path.replaceWithMultiple([t.importDeclaration(specifiers,path.node.source),declaration]);},ArrowFunctionExpression:function ArrowFunctionExpression(path){ // Look for destructuring args with annotations. 6 | var params=path.get('params');var _iteratorNormalCompletion=true;var _didIteratorError=false;var _iteratorError=undefined;try{for(var _iterator=params[Symbol.iterator](),_step;!(_iteratorNormalCompletion=(_step=_iterator.next()).done);_iteratorNormalCompletion=true){var param=_step.value;if(param.isObjectPattern()&¶m.node.typeAnnotation){var _path$get=path.get('body');var _scope=_path$get.scope;var _id=_scope.generateUidIdentifier('arg'+param.key);var pattern=param.node;param.replaceWith(_id);if(path.node.expression){var block=t.blockStatement([t.variableDeclaration('var',[t.variableDeclarator(pattern,_id)]),t.returnStatement(path.get('body').node)]);path.node.body=block;path.node.expression=false;}else {path.get('body.body')[0].insertBefore(t.variableDeclaration('var',[t.variableDeclarator(pattern,_id)]));}}}}catch(err){_didIteratorError=true;_iteratorError=err;}finally {try{if(!_iteratorNormalCompletion&&_iterator.return){_iterator.return();}}finally {if(_didIteratorError){throw _iteratorError;}}}},Function:{enter:function enter(path,context){var _node$body$body;if(maybeSkip(path)){return;}var node=path.node;var scope=path.scope;var paramChecks=collectParamChecks(path,context);if(node.type==="ArrowFunctionExpression"&&node.expression){node.expression=false;node.body=t.blockStatement([t.returnStatement(node.body)]);}if(node.returnType){createFunctionReturnGuard(path,context);createFunctionYieldGuards(path,context);}(_node$body$body=node.body.body).unshift.apply(_node$body$body,_toConsumableArray(paramChecks));node.savedTypeAnnotation=node.returnType;node.returnCount=0;node.yieldCount=0;},exit:function exit(path){var node=path.node;var scope=path.scope;var isVoid=node.savedTypeAnnotation?maybeNullableAnnotation(node.savedTypeAnnotation):null;if(!node.returnCount&&isVoid===false){var annotation=node.savedTypeAnnotation;if(annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(node.generator&&isGeneratorAnnotation(annotation)&&annotation.typeParameters&&annotation.typeParameters.params.length>1){annotation=annotation.typeParameters.params[1];}throw path.buildCodeFrameError(buildErrorMessage('Function '+(node.id?'"'+node.id.name+'" ':'')+'did not return a value.',annotation));}if(node.nextGuardCount){path.get('body').get('body')[0].insertBefore(node.nextGuard);}if(node.yieldGuardCount){path.get('body').get('body')[0].insertBefore(node.yieldGuard);}if(node.returnGuardCount){path.get('body').get('body')[0].insertBefore(node.returnGuard);}}},YieldExpression:function YieldExpression(path,context){var fn=path.getFunctionParent();if(!fn){return;}fn.node.yieldCount++;if(!isGeneratorAnnotation(fn.node.returnType)||maybeSkip(path)){return;}var node=path.node;var parent=path.parent;var scope=path.scope;var annotation=fn.node.returnType;if(annotation.type==='NullableTypeAnnotation'||annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(!annotation.typeParameters||annotation.typeParameters.params.length===0){return;}var yieldType=annotation.typeParameters.params[0];var nextType=annotation.typeParameters.params[2];var ok=staticCheckAnnotation(path.get("argument"),yieldType);if(ok===true&&!nextType){return;}else if(ok===false){throw path.buildCodeFrameError(buildErrorMessage('Function '+(fn.node.id?'"'+fn.node.id.name+'" ':'')+'yielded an invalid type.',yieldType,getAnnotation(path.get('argument'))));}fn.node.yieldGuardCount++;if(fn.node.yieldGuard){var _yielder=t.yieldExpression(t.callExpression(fn.node.yieldGuardName,[node.argument||t.identifier('undefined')]));_yielder.hasBeenTypeChecked=true;if(fn.node.nextGuard){fn.node.nextGuardCount++;path.replaceWith(t.callExpression(fn.node.nextGuardName,[_yielder]));}else {path.replaceWith(_yielder);}}else if(fn.node.nextGuard){fn.node.nextGuardCount++;path.replaceWith(t.callExpression(fn.node.nextGuardName,[yielder]));}},ReturnStatement:function ReturnStatement(path,context){var fn=path.getFunctionParent();if(!fn){return;}fn.node.returnCount++;if(maybeSkip(path)){return;}var node=path.node;var parent=path.parent;var scope=path.scope;var _fn$node=fn.node;var returnType=_fn$node.returnType;var returnGuardName=_fn$node.returnGuardName;if(!returnType||!returnGuardName){return;}if(!node.argument){if(maybeNullableAnnotation(returnType)===false){throw path.buildCodeFrameError(buildErrorMessage('Function '+(fn.node.id?'"'+fn.node.id.name+'" ':'')+'did not return a value.',returnType));}return;}var annotation=returnType;if(annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(isGeneratorAnnotation(annotation)){annotation=annotation.typeParameters&&annotation.typeParameters.params.length>1?annotation.typeParameters.params[1]:t.anyTypeAnnotation();}else if(node.async&&annotation.type==='GenericTypeAnnotation'&&annotation.id.name==='Promise'){annotation=annotation.typeParameters&&annotation.typeParameters[0]||t.anyTypeAnnotation();}var ok=staticCheckAnnotation(path.get("argument"),annotation);if(ok===true){return;}else if(ok===false){throw path.buildCodeFrameError(buildErrorMessage('Function '+(fn.node.id?'"'+fn.node.id.name+'" ':'')+'returned an invalid type.',annotation,getAnnotation(path.get('argument'))));}fn.node.returnGuardCount++;var returner=t.returnStatement(t.callExpression(fn.node.returnGuardName,[node.argument]));returner.hasBeenTypeChecked=true;path.replaceWith(returner);},VariableDeclaration:function VariableDeclaration(path,context){if(maybeSkip(path)){return;}var node=path.node;var scope=path.scope;var collected=[];var declarations=path.get("declarations");for(var i=0;i0){var _check=collected.reduce(function(check,branch){branch.alternate=check;return branch;});if(path.parent.type==='Program'||path.parent.type==='BlockStatement'){path.insertAfter(_check);}else if(path.parentPath.isForXStatement()||path.parentPath.isForStatement()||path.parentPath.isForInStatement()){var body=path.parentPath.get('body');if(body.type!=='BlockStatement'){var block=t.blockStatement([body.node]);body.replaceWith(block);body=path.parentPath.get('body');}var children=body.get('body');if(children.length===0){body.replaceWith(_check);}else {children[0].insertBefore(_check);}}else if(path.parent.type==='ExportNamedDeclaration'||path.parent.type==='ExportDefaultDeclaration'||path.parent.type==='ExportAllDeclaration'){path.parentPath.insertAfter(_check);}else {path.replaceWith(t.blockStatement([node,_check]));}}},AssignmentExpression:function AssignmentExpression(path,context){if(maybeSkip(path)){return;}var node=path.node;var scope=path.scope;var left=path.get('left');var annotation=void 0;if(node.hasBeenTypeChecked||node.left.hasBeenTypeChecked){return;}else if(left.isMemberExpression()){annotation=getAnnotation(left);}else if(t.isIdentifier(node.left)){var binding=scope.getBinding(node.left.name);if(!binding){return;}else if(binding.path.type!=='VariableDeclarator'){return;}annotation=left.getTypeAnnotation();if(annotation.type==='AnyTypeAnnotation'){var item=binding.path.get('id');annotation=item.node.savedTypeAnnotation||item.getTypeAnnotation();}}else {return;}node.hasBeenTypeChecked=true;node.left.hasBeenTypeChecked=true;var id=node.left;var right=path.get('right');if(annotation.type==='AnyTypeAnnotation'){return;}var ok=staticCheckAnnotation(right,annotation);if(ok===true){return;}else if(ok===false){throw path.buildCodeFrameError(buildErrorMessage('Invalid assignment value for "'+humanReadableType(id)+'".',annotation,getAnnotation(right)));}var check=checkAnnotation(id,annotation,scope);if(!id.typeAnnotation){id.typeAnnotation=annotation;}id.hasBeenTypeChecked=true;if(check){var parent=path.getStatementParent();parent.insertAfter(guard({check:check,message:varTypeErrorMessage(id,context)}));}},TypeCastExpression:function TypeCastExpression(path){var node=path.node;var target=void 0;switch(node.expression.type){case 'Identifier':target=node.expression;break;case 'AssignmentExpression':target=node.expression.left;break;default: // unsupported. 7 | return;}var id=path.scope.getBindingIdentifier(target.name);if(!id){return;}id.savedTypeAnnotation=path.getTypeAnnotation();},ForOfStatement:function ForOfStatement(path,context){if(maybeSkip(path)){return;}var left=path.get('left');var right=path.get('right');var rightAnnotation=getAnnotation(right);var leftAnnotation=left.isVariableDeclaration()?getAnnotation(left.get('declarations')[0].get('id')):getAnnotation(left);if(rightAnnotation.type!=='VoidTypeAnnotation'&&rightAnnotation.type!=='NullLiteralTypeAnnotation'){var ok=maybeIterableAnnotation(rightAnnotation);if(ok===false){throw path.buildCodeFrameError('Cannot iterate '+humanReadableType(rightAnnotation)+'.');}}var id=void 0;if(right.isIdentifier()){id=right.node;}else {id=path.scope.generateUidIdentifierBasedOnNode(right.node);path.scope.push({id:id});var replacement=t.expressionStatement(t.assignmentExpression('=',id,right.node));path.insertBefore(replacement);right.replaceWith(id);}path.insertBefore(guard({check:checks.iterable({input:id}),message:t.binaryExpression('+',t.stringLiteral('Expected '+humanReadableType(right.node)+' to be iterable, got '),readableName({inspect:context.inspect,input:id}))}));if(rightAnnotation.type!=='GenericTypeAnnotation'||rightAnnotation.id.name!=='Iterable'||!rightAnnotation.typeParameters||!rightAnnotation.typeParameters.params.length){return;}var annotation=rightAnnotation.typeParameters.params[0];if(compareAnnotations(annotation,leftAnnotation)===false){throw path.buildCodeFrameError(buildErrorMessage('Invalid iterator type.',annotation,leftAnnotation));}},ClassDeclaration:function ClassDeclaration(path,context){ // Convert React props to propTypes 8 | if(!path.node.superClass){return;}var props=void 0;var hasRenderMethod=false;var _iteratorNormalCompletion2=true;var _didIteratorError2=false;var _iteratorError2=undefined;try{for(var _iterator2=path.get('body.body')[Symbol.iterator](),_step2;!(_iteratorNormalCompletion2=(_step2=_iterator2.next()).done);_iteratorNormalCompletion2=true){var memberPath=_step2.value;var classMember=memberPath.node;if(t.isClassProperty(classMember)){if(classMember.key.name==='propTypes'&&classMember.static){return;}else if(classMember.key.name==='props'&&!classMember.static){props=memberPath;}}if(t.isClassMethod(classMember)&&classMember.key.name==='render'){hasRenderMethod=true;}}}catch(err){_didIteratorError2=true;_iteratorError2=err;}finally {try{if(!_iteratorNormalCompletion2&&_iterator2.return){_iterator2.return();}}finally {if(_didIteratorError2){throw _iteratorError2;}}}var type=void 0;if(path.node.superTypeParameters){if(path.node.superTypeParameters.params.length!==3){return;}type=path.node.superTypeParameters.params[1];}if(props){type=props.node.typeAnnotation.typeAnnotation;}if(!type||!hasRenderMethod){return;}if(t.isGenericTypeAnnotation(type)){var binding=path.scope.getBinding(type.id.name);type=getAnnotation(binding.path);}if(!t.isObjectTypeAnnotation(type)){return;} // Now we have a class that has a superclass, an instance method called 'render' 9 | // and some property type annotations. We can be reasonably sure it's a React component. 10 | var propTypes=t.objectExpression(type.properties.map(function(prop){return t.objectProperty(t.identifier(prop.key.name),generatePropType(prop.value,path.scope,context));}));if(path.node.decorators){var property=t.classProperty(t.identifier('propTypes'),propTypes);property.static=true;props.insertAfter(property);}else {var root=path.parentPath.isExportDeclaration()?path.parentPath:path;root.insertAfter(t.expressionStatement(t.assignmentExpression("=",t.memberExpression(path.node.id,t.identifier("propTypes")),propTypes)));}}}; /** 11 | * Collect all the type declarations in the given path and add references to them for retreival later. 12 | */function collectTypes(path){path.traverse({InterfaceDeclaration:function InterfaceDeclaration(path){path.scope.setData('typechecker:'+path.node.id.name,path);},TypeAlias:function TypeAlias(path){path.scope.setData('typechecker:'+path.node.id.name,path);},ImportDeclaration:function ImportDeclaration(path){if(path.node.importKind!=='type'){return;}path.get('specifiers').forEach(function(specifier){var local=specifier.get('local');if(local.isIdentifier()){path.scope.setData('typechecker:'+local.node.name,specifier);}else {path.scope.setData('typechecker:'+local.node.id.name,specifier);}});},"Function|Class":function FunctionClass(path){var node=path.node;if(node.typeParameters&&node.typeParameters.params){path.get('typeParameters').get('params').forEach(function(typeParam){path.get('body').scope.setData('typeparam:'+typeParam.node.name,typeParam);});}}});}return {visitor:{Program:function Program(path,_ref6){var opts=_ref6.opts;if(opts&&opts.disable&&opts.disable[process.env.NODE_ENV]){return;}var checkFile=false;var _iteratorNormalCompletion3=true;var _didIteratorError3=false;var _iteratorError3=undefined;try{for(var _iterator3=path.get('body')[Symbol.iterator](),_step3;!(_iteratorNormalCompletion3=(_step3=_iterator3.next()).done);_iteratorNormalCompletion3=true){var _child=_step3.value;if(mustCheckFile(_child,opts)){checkFile=true;break;}}}catch(err){_didIteratorError3=true;_iteratorError3=err;}finally {try{if(!_iteratorNormalCompletion3&&_iterator3.return){_iterator3.return();}}finally {if(_didIteratorError3){throw _iteratorError3;}}}if(!checkFile){var _iteratorNormalCompletion4=true;var _didIteratorError4=false;var _iteratorError4=undefined;try{for(var _iterator4=path.get('body')[Symbol.iterator](),_step4;!(_iteratorNormalCompletion4=(_step4=_iterator4.next()).done);_iteratorNormalCompletion4=true){var child=_step4.value;if(maybeSkipFile(child,opts)){return;}}}catch(err){_didIteratorError4=true;_iteratorError4=err;}finally {try{if(!_iteratorNormalCompletion4&&_iterator4.return){_iterator4.return();}}finally {if(_didIteratorError4){throw _iteratorError4;}}}}collectTypes(path);var inspect=path.scope.generateUidIdentifier('inspect');var requiresHelpers={inspect:false};var context={get inspect(){requiresHelpers.inspect=true;return inspect;}};path.traverse(visitors,context);if(requiresHelpers.inspect){var body=path.get('body');body[body.length-1].insertAfter(template('\n function id (input, depth) {\n const maxDepth = 4;\n const maxKeys = 15;\n if (depth === undefined) {\n depth = 0;\n }\n depth += 1;\n if (input === null) {\n return \'null\';\n }\n else if (input === undefined) {\n return \'void\';\n }\n else if (typeof input === \'string\' || typeof input === \'number\' || typeof input === \'boolean\') {\n return typeof input;\n }\n else if (Array.isArray(input)) {\n if (input.length > 0) {\n if (depth > maxDepth) return \'[...]\';\n const first = id(input[0], depth);\n if (input.every(item => id(item, depth) === first)) {\n return first.trim() + \'[]\';\n }\n else {\n return \'[\' + input.slice(0, maxKeys).map(item => id(item, depth)).join(\', \') + (input.length >= maxKeys ? \', ...\' : \'\') + \']\';\n }\n }\n else {\n return \'Array\';\n }\n }\n else {\n const keys = Object.keys(input);\n if (!keys.length) {\n if (input.constructor && input.constructor.name && input.constructor.name !== \'Object\') {\n return input.constructor.name;\n }\n else {\n return \'Object\';\n }\n }\n if (depth > maxDepth) return \'{...}\';\n const indent = \' \'.repeat(depth - 1);\n let entries = keys.slice(0, maxKeys).map(key => {\n return (/^([A-Z_$][A-Z0-9_$]*)$/i.test(key) ? key : JSON.stringify(key)) + \': \' + id(input[key], depth) + \';\';\n }).join(\'\\n \' + indent);\n if (keys.length >= maxKeys) {\n entries += \'\\n \' + indent + \'...\';\n }\n if (input.constructor && input.constructor.name && input.constructor.name !== \'Object\') {\n return input.constructor.name + \' {\\n \' + indent + entries + \'\\n\' + indent + \'}\';\n }\n else {\n return \'{\\n \' + indent + entries + \'\\n\' + indent + \'}\';\n }\n }\n }\n ')({id:inspect}));}}}}; /** 13 | * Create a function which can verify the return type for a function. 14 | */function createFunctionReturnGuard(path,context){var node=path.node;var scope=path.scope;var annotation=node.returnType;if(annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(isGeneratorAnnotation(annotation)){annotation=annotation.typeParameters&&annotation.typeParameters.params.length>1?annotation.typeParameters.params[1]:t.anyTypeAnnotation();}else if(node.async&&annotation.type==='GenericTypeAnnotation'&&annotation.id.name==='Promise'){annotation=annotation.typeParameters&&annotation.typeParameters[0]||t.anyTypeAnnotation();}var name=scope.generateUidIdentifierBasedOnNode(node);var id=scope.generateUidIdentifier('id');var check=checkAnnotation(id,annotation,scope);if(check){node.returnGuard=guardFn({id:id,name:name,check:check,message:returnTypeErrorMessage(path,path.node,id,context)});node.returnGuard.hasBeenTypeChecked=true;node.returnGuardName=name;node.returnGuardCount=0;}}function createFunctionYieldGuards(path,context){var node=path.node;var scope=path.scope;var annotation=node.returnType;if(annotation.type==='NullableTypeAnnotation'||annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(!annotation.typeParameters||annotation.typeParameters.params.length===0){return;}if(annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(!isGeneratorAnnotation(annotation)){return;}var yieldType=annotation.typeParameters.params[0];var nextType=annotation.typeParameters.params[2];if(yieldType){var _name=scope.generateUidIdentifier('check'+(node.id?node.id.name.slice(0,1).toUpperCase()+node.id.name.slice(1):'')+'Yield');var _id3=scope.generateUidIdentifier('id');var check=checkAnnotation(_id3,yieldType,scope);if(check){node.yieldGuard=guardFn({id:_id3,name:_name,check:check,message:yieldTypeErrorMessage(node,yieldType,_id3,context)});node.yieldGuardName=_name;node.yieldGuardCount=0;}}if(nextType){var _name2=scope.generateUidIdentifier('check'+(node.id?node.id.name.slice(0,1).toUpperCase()+node.id.name.slice(1):'')+'Next');var _id4=scope.generateUidIdentifier('id');var _check2=checkAnnotation(_id4,nextType,scope);if(_check2){node.nextGuard=guardFn({id:_id4,name:_name2,check:_check2,message:yieldNextTypeErrorMessage(node,nextType,_id4,context)});node.nextGuardName=_name2;node.nextGuardCount=0;}}}function isThisMemberExpression(path){var node=path.node;if(node.type==='ThisExpression'){return true;}else if(node.type==='MemberExpression'){return isThisMemberExpression(path.get('object'));}else {return false;}}function isGeneratorAnnotation(annotation){if(!annotation){return false;}if(annotation.type==='TypeAnnotation'||annotation.type==='NullableTypeAnnotation'){annotation=annotation.typeAnnotation;}return annotation.type==='GenericTypeAnnotation'&&annotation.id.name==='Generator';}function buildErrorMessage(message,expected,got){if(got){return message+'\n\nExpected:\n'+humanReadableType(expected)+'\n\nGot:\n'+humanReadableType(got);}else {return message+'\n\nExpected:\n'+humanReadableType(expected);}}function createChecks(){return {number:expression('typeof input === \'number\''),numericLiteral:checkNumericLiteral,boolean:expression('typeof input === \'boolean\''),booleanLiteral:checkBooleanLiteral,class:checkClass,function:expression('typeof input === \'function\''),string:expression('typeof input === \'string\''),stringLiteral:checkStringLiteral,symbol:expression('typeof input === \'symbol\''),undefined:expression('input === undefined'),null:expression('input === null'),void:expression('input == null'),instanceof:expression('input instanceof type'),type:expression('type(input)'),mixed:function mixed(){return null;},any:function any(){return null;},union:checkUnion,intersection:checkIntersection,array:checkArray,map:checkMap,set:checkSet,generator:checkGenerator,iterable:checkIterable,tuple:checkTuple,object:checkObject,nullable:checkNullable,typeof:checkTypeof,int8:expression('typeof input === \'number\' && !isNaN(input) && input >= -128 && input <= 127 && input === Math.floor(input)'),uint8:expression('typeof input === \'number\' && !isNaN(input) && input >= 0 && input <= 255 && input === Math.floor(input)'),int16:expression('typeof input === \'number\' && !isNaN(input) && input >= -32768 && input <= 32767 && input === Math.floor(input)'),uint16:expression('typeof input === \'number\' && !isNaN(input) && input >= 0 && input <= 65535 && input === Math.floor(input)'),int32:expression('typeof input === \'number\' && !isNaN(input) && input >= -2147483648 && input <= 2147483647 && input === Math.floor(input)'),uint32:expression('typeof input === \'number\' && !isNaN(input) && input >= 0 && input <= 4294967295 && input === Math.floor(input)'),float32:expression('typeof input === \'number\' && !isNaN(input) && input >= -3.40282347e+38 && input <= 3.40282347e+38'),float64:expression('typeof input === \'number\' && !isNaN(input)'),double:expression('typeof input === \'number\' && !isNaN(input)')};}function createStaticChecks(){return {symbol:function symbol(path){return maybeSymbolAnnotation(getAnnotation(path));},instanceof:function _instanceof(_ref7){var path=_ref7.path;var annotation=_ref7.annotation;var type=createTypeExpression(annotation.id);var node=path.node;var scope=path.scope;if(type.name==='Object'&&node.type==='ObjectExpression'&&!scope.getBinding('Object')){return true;}else if(type.name==='Map'&&!scope.getBinding('Map')){return null;}else if(type.name==='Set'&&!scope.getBinding('Set')){return null;}else if(type.name==='Class'&&!scope.hasBinding('Class')){return null;}else if(type.name==='int8'&&!scope.hasBinding('int8')){return null;}else if(type.name==='uint8'&&!scope.hasBinding('uint8')){return null;}else if(type.name==='int16'&&!scope.hasBinding('int16')){return null;}else if(type.name==='uint16'&&!scope.hasBinding('uint16')){return null;}else if(type.name==='int32'&&!scope.hasBinding('int32')){return null;}else if(type.name==='uint32'&&!scope.hasBinding('uint32')){return null;}else if(type.name==='float32'&&!scope.hasBinding('float32')){return null;}else if(type.name==='float64'&&!scope.hasBinding('float64')){return null;}else if(type.name==='double'&&!scope.hasBinding('double')){return null;}return maybeInstanceOfAnnotation(getAnnotation(path),type,annotation.typeParameters?annotation.typeParameters.params:[]);},type:function(_type){function type(_x){return _type.apply(this,arguments);}type.toString=function(){return _type.toString();};return type;}(function(_ref8){var path=_ref8.path;var type=_ref8.type;return null;})};}function compareAnnotations(a,b){if(a.type==='TypeAnnotation'){a=a.typeAnnotation;}if(b.type==='TypeAnnotation'){b=b.typeAnnotation;}switch(a.type){case 'StringTypeAnnotation':return maybeStringAnnotation(b);case 'StringLiteral':case 'StringLiteralTypeAnnotation':return compareStringLiteralAnnotations(a,b);case 'NumberTypeAnnotation':return maybeNumberAnnotation(b);case 'NumericLiteral':case 'NumericLiteralTypeAnnotation':return compareNumericLiteralAnnotations(a,b);case 'BooleanTypeAnnotation':return maybeBooleanAnnotation(b);case 'BooleanLiteral':case 'BooleanLiteralTypeAnnotation':return compareBooleanLiteralAnnotations(a,b);case 'FunctionTypeAnnotation':return maybeFunctionAnnotation(b);case 'AnyTypeAnnotation':return null;case 'MixedTypeAnnotation':return null;case 'ObjectTypeAnnotation':return compareObjectAnnotation(a,b);case 'ArrayTypeAnnotation':return compareArrayAnnotation(a,b);case 'GenericTypeAnnotation':return compareGenericAnnotation(a,b);case 'TupleTypeAnnotation':return compareTupleAnnotation(a,b);case 'UnionTypeAnnotation':return compareUnionAnnotation(a,b);case 'IntersectionTypeAnnotation':return compareIntersectionAnnotation(a,b);case 'NullableTypeAnnotation':return compareNullableAnnotation(a,b);default:return null;}}function compareStringLiteralAnnotations(a,b){if(b.type==='StringLiteralTypeAnnotation'||b.type==='StringLiteral'){return a.value===b.value;}else {return maybeStringAnnotation(b)===false?false:null;}}function compareBooleanLiteralAnnotations(a,b){if(b.type==='BooleanLiteralTypeAnnotation'||b.type==='BooleanLiteral'){return a.value===b.value;}else {return maybeBooleanAnnotation(b)===false?false:null;}}function compareNumericLiteralAnnotations(a,b){if(b.type==='NumericLiteralTypeAnnotation'||b.type==='NumericLiteral'){return a.value===b.value;}else {return maybeNumberAnnotation(b)===false?false:null;}}function unionComparer(a,b,comparator){if(!a.types||a.types.length===0){return null;}var falseCount=0;var trueCount=0;if(!a.types){return null;}var _iteratorNormalCompletion5=true;var _didIteratorError5=false;var _iteratorError5=undefined;try{for(var _iterator5=a.types[Symbol.iterator](),_step5;!(_iteratorNormalCompletion5=(_step5=_iterator5.next()).done);_iteratorNormalCompletion5=true){var _type2=_step5.value;var result=comparator(_type2,b);if(result===true){if(b.type!=='UnionTypeAnnotation'){return true;}trueCount++;}else if(result===false){if(b.type==='UnionTypeAnnotation'){return false;}falseCount++;}}}catch(err){_didIteratorError5=true;_iteratorError5=err;}finally {try{if(!_iteratorNormalCompletion5&&_iterator5.return){_iterator5.return();}}finally {if(_didIteratorError5){throw _iteratorError5;}}}if(falseCount===a.types.length){return false;}else if(trueCount===a.types.length){return true;}else {return null;}}function intersectionComparer(a,b,comparator){var falseCount=0;var trueCount=0;if(!a.types){return null;}var _iteratorNormalCompletion6=true;var _didIteratorError6=false;var _iteratorError6=undefined;try{for(var _iterator6=a.types[Symbol.iterator](),_step6;!(_iteratorNormalCompletion6=(_step6=_iterator6.next()).done);_iteratorNormalCompletion6=true){var _type3=_step6.value;var result=comparator(_type3,b);if(result===true){trueCount++;}else if(result===false){return false;}}}catch(err){_didIteratorError6=true;_iteratorError6=err;}finally {try{if(!_iteratorNormalCompletion6&&_iterator6.return){_iterator6.return();}}finally {if(_didIteratorError6){throw _iteratorError6;}}}if(trueCount===a.types.length){return true;}else {return null;}}function compareObjectAnnotation(a,b){switch(b.type){case 'ObjectTypeAnnotation':break;case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return compareObjectAnnotation(a,b.typeAnnotation);case 'UnionTypeAnnotation':return unionComparer(a,b,compareObjectAnnotation);case 'IntersectionTypeAnnotation':return intersectionComparer(a,b,compareObjectAnnotation);case 'VoidTypeAnnotation':case 'NullLiteralTypeAnnotation':case 'BooleanTypeAnnotation':case 'BooleanLiteralTypeAnnotation':case 'StringTypeAnnotation':case 'StringLiteralTypeAnnotation':case 'NumberTypeAnnotation':case 'NumericLiteralTypeAnnotation':case 'FunctionTypeAnnotation':return false;default:return null;} // We're comparing two object annotations. 15 | var allTrue=true;var _iteratorNormalCompletion7=true;var _didIteratorError7=false;var _iteratorError7=undefined;try{for(var _iterator7=a.properties[Symbol.iterator](),_step7;!(_iteratorNormalCompletion7=(_step7=_iterator7.next()).done);_iteratorNormalCompletion7=true){var aprop=_step7.value;var found=false;var _iteratorNormalCompletion8=true;var _didIteratorError8=false;var _iteratorError8=undefined;try{for(var _iterator8=b.properties[Symbol.iterator](),_step8;!(_iteratorNormalCompletion8=(_step8=_iterator8.next()).done);_iteratorNormalCompletion8=true){var bprop=_step8.value;if(bprop.key.name===aprop.key.name){var result=compareAnnotations(aprop.value,bprop.value);if(result===false&&!(aprop.optional&&(bprop.optional||maybeNullableAnnotation(bprop.value)===true))){return false;}else {found=result;}break;}}}catch(err){_didIteratorError8=true;_iteratorError8=err;}finally {try{if(!_iteratorNormalCompletion8&&_iterator8.return){_iterator8.return();}}finally {if(_didIteratorError8){throw _iteratorError8;}}}if(found===false&&!aprop.optional){return false;}allTrue=allTrue&&found===true;}}catch(err){_didIteratorError7=true;_iteratorError7=err;}finally {try{if(!_iteratorNormalCompletion7&&_iterator7.return){_iterator7.return();}}finally {if(_didIteratorError7){throw _iteratorError7;}}}return allTrue?true:null;}function compareArrayAnnotation(a,b){switch(b.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return compareArrayAnnotation(a,b.typeAnnotation);case 'UnionTypeAnnotation':return unionComparer(a,b,compareArrayAnnotation);case 'IntersectionTypeAnnotation':return intersectionComparer(a,b,compareArrayAnnotation);case 'VoidTypeAnnotation':case 'NullLiteralTypeAnnotation':case 'BooleanTypeAnnotation':case 'BooleanLiteralTypeAnnotation':case 'StringTypeAnnotation':case 'StringLiteralTypeAnnotation':case 'NumberTypeAnnotation':case 'NumericLiteralTypeAnnotation':case 'FunctionTypeAnnotation':return false;default:return null;}}function compareGenericAnnotation(a,b){switch(b.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return compareGenericAnnotation(a,b.typeAnnotation);case 'GenericTypeAnnotation':if(b.id.name===a.id.name){return true;}else {return null;}case 'UnionTypeAnnotation':return unionComparer(a,b,compareGenericAnnotation);case 'IntersectionTypeAnnotation':return intersectionComparer(a,b,compareGenericAnnotation);default:return null;}}function compareTupleAnnotation(a,b){if(b.type==='TupleTypeAnnotation'){if(b.types.length===0){return null;}else if(b.types.length=',t.memberExpression(input,t.identifier('length')),t.numericLiteral(types.length));return _checks.reduce(function(last,check,index){return t.logicalExpression("&&",last,check);},t.logicalExpression('&&',checkIsArray({input:input}),checkLength));}}function checkTuple(_ref22){var input=_ref22.input;var types=_ref22.types;var scope=_ref22.scope;if(types.length===0){return checkIsArray({input:input});} // This is a tuple 17 | var checks=types.map(function(type,index){return checkAnnotation(t.memberExpression(input,t.numericLiteral(index),true),type,scope);}).filter(identity);var checkLength=t.binaryExpression('>=',t.memberExpression(input,t.identifier('length')),t.numericLiteral(types.length));return checks.reduce(function(last,check,index){return t.logicalExpression("&&",last,check);},t.logicalExpression('&&',checkIsArray({input:input}),checkLength));}function checkObject(_ref23){var input=_ref23.input;var properties=_ref23.properties;var indexers=_ref23.indexers;var scope=_ref23.scope;if(input.type==='ObjectPattern'){return checkObjectPattern({input:input,properties:properties,scope:scope});}var propNames=[];var check=properties.length===0?checkIsObject({input:input}):properties.reduce(function(expr,prop,index){var target=prop.key.type==='Identifier'?t.memberExpression(input,prop.key):t.memberExpression(input,prop.key,true);propNames.push(prop.key.type==='Identifier'?t.stringLiteral(prop.key.name):prop.key);var check=checkAnnotation(target,prop.value,scope);if(check){if(prop.optional){check=t.logicalExpression('||',checks.void({input:target}),check);}return t.logicalExpression("&&",expr,check);}else {return expr;}},checkNotNull({input:input}));if(indexers.length){return indexers.reduceRight(function(expr,indexer){if(indexer.value.type==='AnyTypeAnnotation'){return expr;}var value=scope.generateUidIdentifier(indexer.id.name);var check=checkAnnotation(value,indexer.value,scope);var fixedKeys=t.arrayExpression(propNames);if(check){if(propNames.length){return t.logicalExpression('&&',expr,checkObjectIndexers({input:input,value:value,check:check,fixedKeys:fixedKeys}));}else {return t.logicalExpression('&&',expr,checkObjectIndexersNoFixed({input:input,value:value,check:check,fixedKeys:fixedKeys}));}}else {return expr;}},check);}return check;}function checkObjectPattern(_ref24){var input=_ref24.input;var properties=_ref24.properties;var scope=_ref24.scope;var propNames=properties.reduce(function(names,prop){names[prop.key.name]=prop;return names;},{});var propChecks={};var _iteratorNormalCompletion9=true;var _didIteratorError9=false;var _iteratorError9=undefined;try{for(var _iterator9=input.properties[Symbol.iterator](),_step9;!(_iteratorNormalCompletion9=(_step9=_iterator9.next()).done);_iteratorNormalCompletion9=true){var item=_step9.value;var key=item.key;var _id5=item.value;var prop=propNames[key.name];if(!prop){continue;}var check=checkAnnotation(_id5,prop.value,scope);if(check){propChecks[key.name]=check;}}}catch(err){_didIteratorError9=true;_iteratorError9=err;}finally {try{if(!_iteratorNormalCompletion9&&_iterator9.return){_iterator9.return();}}finally {if(_didIteratorError9){throw _iteratorError9;}}}return Object.keys(propChecks).reduce(function(last,name){var check=propChecks[name];if(last===null){return check;}else {return t.logicalExpression('&&',last,check);}},null);}function createTypeAliasChecks(path){var node=path.node;var scope=path.scope;var id=node.id;var annotation=node.right;var input=t.identifier('input');var check=checkAnnotation(input,annotation,scope)||t.booleanLiteral(true);var declaration=declareTypeChecker({id:id,check:check});declaration.isTypeChecker=true;declaration.savedTypeAnnotation=annotation;declaration.declarations[0].savedTypeAnnotation=annotation;return declaration;}function createInterfaceChecks(path){var node=path.node;var scope=path.scope;var id=node.id;var annotation=node.body;var input=t.identifier('input');var check=node.extends.reduce(function(check,extender){return t.logicalExpression('&&',check,checkAnnotation(input,t.genericTypeAnnotation(extender.id),path.scope));return check;},checkAnnotation(input,annotation,scope)||t.booleanLiteral(true));var declaration=declareTypeChecker({id:id,check:check});declaration.isTypeChecker=true;return declaration;}function checkAnnotation(input,annotation,scope){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':return checkAnnotation(input,annotation.typeAnnotation,scope);case 'TypeofTypeAnnotation':return checks.typeof({input:input,annotation:annotation.argument,scope:scope});case 'GenericTypeAnnotation':if(annotation.id.name==='Array'){return checks.array({input:input,types:annotation.typeParameters?annotation.typeParameters.params:[],scope:scope});}else if(annotation.id.name==='Generator'&&!scope.hasBinding('Generator')){return checks.generator({input:input,types:annotation.typeParameters?annotation.typeParameters.params:[],scope:scope});}else if(annotation.id.name==='Iterable'&&!scope.hasBinding('Iterable')){return checks.iterable({input:input,types:annotation.typeParameters?annotation.typeParameters.params:[],scope:scope});}else if(annotation.id.name==='Map'&&!scope.getBinding('Map')){return checks.map({input:input,types:annotation.typeParameters?annotation.typeParameters.params:[],scope:scope});}else if(annotation.id.name==='Set'&&!scope.getBinding('Set')){return checks.set({input:input,types:annotation.typeParameters?annotation.typeParameters.params:[],scope:scope});}else if(annotation.id.name==='Function'){return checks.function({input:input});}else if(annotation.id.name==='Class'&&!scope.hasBinding('Class')){return checks.class({input:input,types:annotation.typeParameters?annotation.typeParameters.params:[],scope:scope});}else if(annotation.id.name==='int8'&&!scope.hasBinding('int8')){return checks.int8({input:input});}else if(annotation.id.name==='uint8'&&!scope.hasBinding('uint8')){return checks.uint8({input:input});}else if(annotation.id.name==='int16'&&!scope.hasBinding('int16')){return checks.int16({input:input});}else if(annotation.id.name==='uint16'&&!scope.hasBinding('uint16')){return checks.uint16({input:input});}else if(annotation.id.name==='int32'&&!scope.hasBinding('int32')){return checks.int32({input:input});}else if(annotation.id.name==='uint32'&&!scope.hasBinding('uint32')){return checks.uint32({input:input});}else if(annotation.id.name==='float32'&&!scope.hasBinding('float32')){return checks.float32({input:input});}else if(annotation.id.name==='float64'&&!scope.hasBinding('float64')){return checks.float64({input:input});}else if(annotation.id.name==='double'&&!scope.hasBinding('double')){return checks.double({input:input});}else if(annotation.id.name==='Symbol'&&!scope.getBinding('Symbol')){return checks.symbol({input:input});}else if(isTypeChecker(annotation.id,scope)){return checks.type({input:input,type:annotation.id});}else if(isPolymorphicType(annotation.id,scope)){return;}else {return checks.instanceof({input:input,type:createTypeExpression(annotation.id)});}case 'TupleTypeAnnotation':return checks.tuple({input:input,types:annotation.types,scope:scope});case 'NumberTypeAnnotation':return checks.number({input:input});case 'NumericLiteralTypeAnnotation':return checks.numericLiteral({input:input,annotation:annotation});case 'BooleanTypeAnnotation':return checks.boolean({input:input});case 'BooleanLiteralTypeAnnotation':return checks.booleanLiteral({input:input,annotation:annotation});case 'StringTypeAnnotation':return checks.string({input:input});case 'StringLiteralTypeAnnotation':return checks.stringLiteral({input:input,annotation:annotation});case 'UnionTypeAnnotation':return checks.union({input:input,types:annotation.types,scope:scope});case 'IntersectionTypeAnnotation':return checks.intersection({input:input,types:annotation.types,scope:scope});case 'ObjectTypeAnnotation':return checks.object({input:input,properties:annotation.properties||[],indexers:annotation.indexers,scope:scope});case 'ArrayTypeAnnotation':return checks.array({input:input,types:[annotation.elementType||t.anyTypeAnnotation()],scope:scope});case 'FunctionTypeAnnotation':return checks.function({input:input,params:annotation.params,returnType:annotation.returnType});case 'MixedTypeAnnotation':return checks.mixed({input:input});case 'AnyTypeAnnotation':case 'ExistentialTypeParam':return checks.any({input:input});case 'NullableTypeAnnotation':return checks.nullable({input:input,type:annotation.typeAnnotation,scope:scope});case 'VoidTypeAnnotation':case 'NullLiteralTypeAnnotation':return checks.void({input:input});}}function staticCheckAnnotation(path,annotation){var other=getAnnotation(path);switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':return staticCheckAnnotation(path,annotation.typeAnnotation);case 'GenericTypeAnnotation':if(isTypeChecker(annotation.id,path.scope)){return staticChecks.type({path:path,type:annotation.id});}else if(isPolymorphicType(annotation.id,path.scope)){return;}else if(annotation.id.name==='Symbol'){return staticChecks.symbol(path);}else {return staticChecks.instanceof({path:path,annotation:annotation});}}return compareAnnotations(annotation,other);} /** 18 | * Get the type annotation for a given node. 19 | */function getAnnotation(path){var annotation=void 0;try{annotation=getAnnotationShallow(path);}catch(e){if(e instanceof SyntaxError){throw e;}if(process.env.TYPECHECK_DEBUG){console.error(e.stack);}}while(annotation&&annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}return annotation||t.anyTypeAnnotation();}function getAnnotationShallow(path){if(!path||!path.node){return t.voidTypeAnnotation();}var node=path.node;var scope=path.scope;if(node.type==='TypeAlias'){return node.right;}else if(node.type==='ClassProperty'&&node.typeAnnotation){return getClassPropertyAnnotation(path);}else if(node.type==='ClassMethod'&&node.returnType){return getClassMethodAnnotation(path);}else if(node.type==='ObjectProperty'&&node.typeAnnotation){return getObjectPropertyAnnotation(path);}else if(node.type==='SpreadProperty'&&node.typeAnnotation){return getSpreadPropertyAnnotation(path);}else if(node.type==='ObjectMethod'&&node.returnType){return getObjectMethodAnnotation(path);}else if(!node.typeAnnotation&&!node.savedTypeAnnotation&&!node.returnType){switch(path.type){case 'Identifier':var binding=scope.getBinding(node.name);if(!binding||!binding.identifier){return path.getTypeAnnotation();}var id=binding.identifier;if(binding.path.type==='ObjectPattern'){return getObjectPatternAnnotation(binding.path,node.name);}if(id.savedTypeAnnotation){return id.savedTypeAnnotation;}else if(id.returnType){return id.returnType;}else if(id.typeAnnotation){return id.typeAnnotation;}else if(isPolymorphicType(id,scope)){return t.anyTypeAnnotation();}return binding.constant?binding.path.getTypeAnnotation():path.getTypeAnnotation();case 'StringLiteral':case 'NumericLiteral':case 'BooleanLiteral':return createLiteralTypeAnnotation(path);case 'CallExpression':var callee=path.get('callee');if(callee.type==='Identifier'){if(callee.name==='Symbol'){return t.genericTypeAnnotation('Symbol');}var fn=getFunctionForIdentifier(callee);if(fn){return getAnnotation(fn);}}break;case 'ThisExpression':return getThisExpressionAnnotation(path);case 'AssignmentExpression':return getAssignmentExpressionAnnotation(path);case 'MemberExpression':return getMemberExpressionAnnotation(path);case 'ArrayExpression':return getArrayExpressionAnnotation(path);case 'ObjectExpression':return getObjectExpressionAnnotation(path);case 'BinaryExpression':return getBinaryExpressionAnnotation(path);case 'LogicalExpression':return getLogicalExpressionAnnotation(path);case 'ConditionalExpression':return getConditionalExpressionAnnotation(path);case 'ObjectMethod':return getObjectMethodAnnotation(path);case 'SpreadProperty':return getSpreadPropertyAnnotation(path);case 'ObjectProperty':return getObjectPropertyAnnotation(path);case 'ClassDeclaration':return getClassDeclarationAnnotation(path);case 'ClassMethod':return getClassMethodAnnotation(path);case 'ClassProperty':return getClassPropertyAnnotation(path);default:return path.getTypeAnnotation();}}return node.savedTypeAnnotation||node.returnType||node.typeAnnotation||path.getTypeAnnotation();}function createLiteralTypeAnnotation(path){var annotation=void 0;if(path.isStringLiteral()){annotation=t.stringLiteralTypeAnnotation();}else if(path.isNumericLiteral()){annotation=t.numericLiteralTypeAnnotation();}else if(path.isBooleanLiteral()){annotation=t.booleanLiteralTypeAnnotation();}else {return path.getTypeAnnotation();}annotation.value=path.node.value;return annotation;}function getObjectPatternAnnotation(path,name){var annotation=keyByName(getAnnotation(path),name);var found=void 0;if(!path.node.properties){return;}var _iteratorNormalCompletion10=true;var _didIteratorError10=false;var _iteratorError10=undefined;try{for(var _iterator10=path.get('properties')[Symbol.iterator](),_step10;!(_iteratorNormalCompletion10=(_step10=_iterator10.next()).done);_iteratorNormalCompletion10=true){var prop=_step10.value;if(prop.node.value&&prop.node.value.name===name){found=prop.get('key');break;}else if(prop.node.key.type==='Identifier'&&prop.node.key.name===name){found=prop.get('key');break;}}}catch(err){_didIteratorError10=true;_iteratorError10=err;}finally {try{if(!_iteratorNormalCompletion10&&_iterator10.return){_iterator10.return();}}finally {if(_didIteratorError10){throw _iteratorError10;}}}if(!annotation||!found){return;}if(found.type==='Identifier'){annotation.value.authoritative=false;return annotation.value;}}function keyByName(node,name){if(!node.properties){return;}var _iteratorNormalCompletion11=true;var _didIteratorError11=false;var _iteratorError11=undefined;try{for(var _iterator11=node.properties[Symbol.iterator](),_step11;!(_iteratorNormalCompletion11=(_step11=_iterator11.next()).done);_iteratorNormalCompletion11=true){var prop=_step11.value;if(prop.key&&prop.key.name===name){return prop;}}}catch(err){_didIteratorError11=true;_iteratorError11=err;}finally {try{if(!_iteratorNormalCompletion11&&_iterator11.return){_iterator11.return();}}finally {if(_didIteratorError11){throw _iteratorError11;}}}}function valueByName(node,name){if(!node.properties){return;}var _iteratorNormalCompletion12=true;var _didIteratorError12=false;var _iteratorError12=undefined;try{for(var _iterator12=node.properties[Symbol.iterator](),_step12;!(_iteratorNormalCompletion12=(_step12=_iterator12.next()).done);_iteratorNormalCompletion12=true){var prop=_step12.value;if(prop.value&&prop.value.name===name){return prop;}}}catch(err){_didIteratorError12=true;_iteratorError12=err;}finally {try{if(!_iteratorNormalCompletion12&&_iterator12.return){_iterator12.return();}}finally {if(_didIteratorError12){throw _iteratorError12;}}}}function getSpreadPropertyAnnotation(path){var node=path.node;var annotation=node.typeAnnotation||node.savedTypeAnnotation;if(!annotation){annotation=getAnnotation(path.get('argument'));}return annotation;}function getObjectPropertyAnnotation(path){var node=path.node;var annotation=node.typeAnnotation||node.savedTypeAnnotation;if(!annotation){if(node.value){if(node.value.typeAnnotation||node.value.savedTypeAnnotation){annotation=node.value.typeAnnotation||node.value.savedTypeAnnotation;}else if(node.value.type==='BooleanLiteral'||node.value.type==='NumericLiteral'||node.value.type==='StringLiteral'){annotation=t[node.value.type](node.value.value);}else {annotation=t.anyTypeAnnotation();}}else {annotation=t.anyTypeAnnotation();}}return t.objectTypeProperty(node.key,annotation);}function getObjectMethodAnnotation(path){var node=path.node;return t.objectTypeProperty(t.identifier(node.key.name),t.functionTypeAnnotation(null,node.params.map(function(param){return param.savedTypeAnnotation||param.typeAnnotation;}),null,node.savedTypeAnnotation||node.returnType||node.typeAnnotation||t.anyTypeAnnotation()));}function getThisExpressionAnnotation(path){var parent=path.parentPath;loop: while(parent){switch(parent.type){case 'ClassDeclaration':return getAnnotation(parent);case 'ClassBody':return getAnnotation(parent.parentPath);case 'ClassMethod':case 'ClassProperty':return getAnnotation(parent.parentPath.parentPath);case 'ObjectProperty':return getAnnotation(parent.parentPath);case 'ObjectMethod':return getAnnotation(parent.parentPath);case 'FunctionExpression':if(parent.parentPath.type==='ObjectProperty'){return getAnnotation(parent.parentPath.parentPath);}break loop;case 'ArrowFunctionExpression':parent=parent.parentPath;continue;}if(parent.isFunction()){break;}parent=parent.parentPath;}return t.objectTypeAnnotation([]);}function getClassDeclarationAnnotation(path){var body=path.get('body').get('body').map(getAnnotation).filter(function(annotation){return annotation&&annotation.type!=='AnyTypeAnnotation';});return t.objectTypeAnnotation(body);}function getAssignmentExpressionAnnotation(path){if(path.node.operator==='='){return getAnnotation(path.get('right'));}}function getClassPropertyAnnotation(path){var node=path.node;if(node.computed){return;}var annotation=node.typeAnnotation||(node.value?node.value.savedTypeAnnotation||node.value.typeAnnotation:t.anyTypeAnnotation());return t.objectTypeProperty(node.key,annotation||t.anyTypeAnnotation());}function getClassMethodAnnotation(path){var node=path.node;if(node.computed){return;}if(node.kind==='get'){return t.objectTypeProperty(node.key,node.savedTypeAnnotation||node.returnType||node.typeAnnotation||t.anyTypeAnnotation());}else if(node.kind==='set'){return t.objectTypeProperty(node.key,node.params.map(function(param){return param.savedTypeAnnotation||param.typeAnnotation;}).shift()||t.anyTypeAnnotation());}else {return t.objectTypeProperty(node.key,t.functionTypeAnnotation(null,node.params.map(function(param){return param.savedTypeAnnotation||param.typeAnnotation||t.anyTypeAnnotation();}),null,node.savedTypeAnnotation||node.returnType||node.typeAnnotation||t.anyTypeAnnotation()));}}function getBinaryExpressionAnnotation(path){var node=path.node;if(isBooleanExpression(node)){return t.booleanTypeAnnotation();}else {return t.anyTypeAnnotation();}}function getLogicalExpressionAnnotation(path){var node=path.node;if(isBooleanExpression(node)){return t.booleanTypeAnnotation();}else {var left=path.get('left');var right=path.get('right');switch(node.operator){case '&&':case '||':var _ref25=[getAnnotation(left),getAnnotation(right)];left=_ref25[0];right=_ref25[1];if(t.isUnionTypeAnnotation(left)){if(t.isUnionTypeAnnotation(right)){return t.unionTypeAnnotation(left.types.concat(right.types));}else {return t.unionTypeAnnotation(left.types.concat(right));}}else {return t.unionTypeAnnotation([left,right]);}}return t.anyTypeAnnotation();}}function getConditionalExpressionAnnotation(path){var node=path.node;var consequent=getAnnotation(path.get('consequent'));var alternate=getAnnotation(path.get('alternate'));if(t.isUnionTypeAnnotation(consequent)){if(t.isUnionTypeAnnotation(alternate)){return t.unionTypeAnnotation(consequent.types.concat(alternate.types));}else {return t.unionTypeAnnotation(consequent.types.concat(alternate));}}else {return t.unionTypeAnnotation([consequent,alternate]);}}function getArrayExpressionAnnotation(path){return t.genericTypeAnnotation(t.identifier('Array'),t.typeParameterDeclaration(path.get('elements').map(getAnnotation)));}function getObjectExpressionAnnotation(path){var annotation=t.objectTypeAnnotation(path.get('properties').filter(function(prop){return !prop.node.computed;}).map(getAnnotation).reduce(function(properties,prop){if(t.isObjectTypeProperty(prop)){properties.push(prop);}else if(t.isObjectTypeAnnotation(prop)){properties.push.apply(properties,_toConsumableArray(prop.properties));}return properties;},[]).filter(function(annotation){return !t.isAnyTypeAnnotation(annotation.value);}));return annotation;}function getMemberExpressionAnnotation(path){if(path.node.computed){return getComputedMemberExpressionAnnotation(path);}var stack=[];var target=path;while(target.isMemberExpression()){stack.push(target);if(target.node.computed){break;}target=target.get('object');}var objectAnnotation=stack.reduceRight(function(last,target){var annotation=last;if(annotation==null){if(stack.length===1){annotation=getAnnotation(target.get('object'));}else {return getAnnotation(target);}}switch(annotation.type){case 'AnyTypeAnnotation':return annotation;case 'NullableTypeAnnotation':case 'TypeAnnotation':annotation=annotation.typeAnnotation;}if(annotation.type==='GenericTypeAnnotation'){var typeChecker=getTypeChecker(annotation.id,path.scope);if(typeChecker){annotation=getAnnotation(typeChecker);}else if(isPolymorphicType(annotation.id,path.scope)){annotation=t.anyTypeAnnotation();}else {var binding=path.scope.getBinding(annotation.id.name);if(binding){annotation=getAnnotation(binding.path);}}}switch(annotation.type){case 'AnyTypeAnnotation':return annotation;case 'ObjectTypeAnnotation':var id=target.get('property').node;var _iteratorNormalCompletion13=true;var _didIteratorError13=false;var _iteratorError13=undefined;try{for(var _iterator13=(annotation.properties||[])[Symbol.iterator](),_step13;!(_iteratorNormalCompletion13=(_step13=_iterator13.next()).done);_iteratorNormalCompletion13=true){var _step13$value=_step13.value;var key=_step13$value.key;var value=_step13$value.value;if(key.name===id.name){return value.type==='VoidTypeAnnotation'||value.type==='NullLiteralTypeAnnotation'?t.anyTypeAnnotation():value;}}}catch(err){_didIteratorError13=true;_iteratorError13=err;}finally {try{if(!_iteratorNormalCompletion13&&_iterator13.return){_iterator13.return();}}finally {if(_didIteratorError13){throw _iteratorError13;}}}}return t.anyTypeAnnotation();},null);return objectAnnotation||path.getTypeAnnotation();}function getComputedMemberExpressionAnnotation(path){var object=path.get('object');var property=path.get('property');var objectAnnotation=getAnnotation(object);if(objectAnnotation.type==='TypeAnnotation'||objectAnnotation.type==='NullableTypeAnnotation'){objectAnnotation=objectAnnotation.typeAnnotation;}var propertyAnnotation=getAnnotation(property);if(propertyAnnotation.type==='TypeAnnotation'||propertyAnnotation.type==='NullableTypeAnnotation'){propertyAnnotation=propertyAnnotation.typeAnnotation;}var _property$evaluate=property.evaluate();var confident=_property$evaluate.confident;var value=_property$evaluate.value;if(!confident){return path.getTypeAnnotation();}switch(objectAnnotation.type){case 'TupleTypeAnnotation':if(objectAnnotation.types.length===0){break;}else if(typeof value==='number'){if(!objectAnnotation.types[value]){throw path.buildCodeFrameError('Invalid computed member expression for tuple: '+humanReadableType(objectAnnotation));}return objectAnnotation.types[value];}else {throw path.buildCodeFrameError('Invalid computed member expression for tuple: '+humanReadableType(objectAnnotation));}break;}return path.getTypeAnnotation();}function getFunctionForIdentifier(path){if(path.type!=='Identifier'){return false;}else if(isTypeChecker(path.node,path.scope)||isPolymorphicType(path.node,path.scope)){return false;}var ref=path.scope.getBinding(path.node.name);if(!ref){return false;}return t.isFunction(ref.path.parent)&&ref.path.parentPath;} /** 20 | * Determine whether the given annotation is for an array. 21 | */function isStrictlyArrayAnnotation(annotation){switch(annotation.type){case 'ArrayTypeAnnotation':case 'TupleTypeAnnotation':return true;case 'TypeAnnotation':case 'FunctionTypeParam':return isStrictlyArrayAnnotation(annotation.typeAnnotation);case 'GenericTypeAnnotation':return annotation.id.name==='Array'?true:null;case 'UnionTypeAnnotation':return annotation.types.every(isStrictlyArrayAnnotation);default:return false;}}function compareMaybeUnion(annotation,comparator){var falseCount=0;var _iteratorNormalCompletion14=true;var _didIteratorError14=false;var _iteratorError14=undefined;try{for(var _iterator14=annotation.types[Symbol.iterator](),_step14;!(_iteratorNormalCompletion14=(_step14=_iterator14.next()).done);_iteratorNormalCompletion14=true){var _type5=_step14.value;var result=comparator(_type5);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError14=true;_iteratorError14=err;}finally {try{if(!_iteratorNormalCompletion14&&_iterator14.return){_iterator14.return();}}finally {if(_didIteratorError14){throw _iteratorError14;}}}if(falseCount===annotation.types.length){return false;}else {return null;}} /** 22 | * Returns `true` if the annotation is compatible with a number, 23 | * `false` if it definitely isn't, or `null` if we're not sure. 24 | */function maybeNumberAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeNumberAnnotation(annotation.typeAnnotation);case 'NumberTypeAnnotation':case 'NumericLiteralTypeAnnotation':case 'NumericLiteral':return true;case 'GenericTypeAnnotation':switch(annotation.id.name){case 'Array':case 'Function':case 'Object':case 'String':case 'Boolean':case 'Date':case 'RegExp':return false;default:return null;}case 'UnionTypeAnnotation':return compareMaybeUnion(annotation,maybeNumberAnnotation);case 'AnyTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}} /** 25 | * Returns `true` if the annotation is compatible with a string, 26 | * `false` if it definitely isn't, or `null` if we're not sure. 27 | */function maybeStringAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeStringAnnotation(annotation.typeAnnotation);case 'StringTypeAnnotation':case 'StringLiteral':return true;case 'StringLiteralTypeAnnotation':return null;case 'GenericTypeAnnotation':switch(annotation.id.name){case 'Array':case 'Function':case 'Object':case 'Number':case 'Boolean':case 'Date':case 'RegExp':return false;default:return null;}case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion15=true;var _didIteratorError15=false;var _iteratorError15=undefined;try{for(var _iterator15=annotation.types[Symbol.iterator](),_step15;!(_iteratorNormalCompletion15=(_step15=_iterator15.next()).done);_iteratorNormalCompletion15=true){var _type6=_step15.value;var result=maybeStringAnnotation(_type6);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError15=true;_iteratorError15=err;}finally {try{if(!_iteratorNormalCompletion15&&_iterator15.return){_iterator15.return();}}finally {if(_didIteratorError15){throw _iteratorError15;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'AnyTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}} /** 28 | * Returns `true` if the annotation is compatible with a symbol, 29 | * `false` if it definitely isn't, or `null` if we're not sure. 30 | */function maybeSymbolAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeSymbolAnnotation(annotation.typeAnnotation);case 'GenericTypeAnnotation':switch(annotation.id.name){case 'Array':case 'Function':case 'Object':case 'Number':case 'Boolean':case 'Date':case 'RegExp':return false;case 'Symbol':return true;default:return null;}case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion16=true;var _didIteratorError16=false;var _iteratorError16=undefined;try{for(var _iterator16=annotation.types[Symbol.iterator](),_step16;!(_iteratorNormalCompletion16=(_step16=_iterator16.next()).done);_iteratorNormalCompletion16=true){var _type7=_step16.value;var result=maybeSymbolAnnotation(_type7);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError16=true;_iteratorError16=err;}finally {try{if(!_iteratorNormalCompletion16&&_iterator16.return){_iterator16.return();}}finally {if(_didIteratorError16){throw _iteratorError16;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'AnyTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}} /** 31 | * Returns `true` if the annotation is compatible with a boolean, 32 | * `false` if it definitely isn't, or `null` if we're not sure. 33 | */function maybeBooleanAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeBooleanAnnotation(annotation.typeAnnotation);case 'BooleanTypeAnnotation':case 'BooleanLiteralTypeAnnotation':case 'BooleanLiteral':return true;case 'GenericTypeAnnotation':switch(annotation.id.name){case 'Array':case 'Function':case 'Object':case 'String':case 'Number':case 'Date':case 'RegExp':return false;default:return null;}case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion17=true;var _didIteratorError17=false;var _iteratorError17=undefined;try{for(var _iterator17=annotation.types[Symbol.iterator](),_step17;!(_iteratorNormalCompletion17=(_step17=_iterator17.next()).done);_iteratorNormalCompletion17=true){var _type8=_step17.value;var result=maybeBooleanAnnotation(_type8);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError17=true;_iteratorError17=err;}finally {try{if(!_iteratorNormalCompletion17&&_iterator17.return){_iterator17.return();}}finally {if(_didIteratorError17){throw _iteratorError17;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'AnyTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}} /** 34 | * Returns `true` if the annotation is compatible with a function, 35 | * `false` if it definitely isn't, or `null` if we're not sure. 36 | */function maybeFunctionAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeFunctionAnnotation(annotation.typeAnnotation);case 'FunctionTypeAnnotation':return true;case 'GenericTypeAnnotation':switch(annotation.id.name){case 'Array':case 'Number':case 'Object':case 'String':case 'Boolean':case 'Date':case 'RegExp':return false;default:return null;}case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion18=true;var _didIteratorError18=false;var _iteratorError18=undefined;try{for(var _iterator18=annotation.types[Symbol.iterator](),_step18;!(_iteratorNormalCompletion18=(_step18=_iterator18.next()).done);_iteratorNormalCompletion18=true){var _type9=_step18.value;var result=maybeFunctionAnnotation(_type9);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError18=true;_iteratorError18=err;}finally {try{if(!_iteratorNormalCompletion18&&_iterator18.return){_iterator18.return();}}finally {if(_didIteratorError18){throw _iteratorError18;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'AnyTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}} /** 37 | * Returns `true` if the annotation is compatible with an undefined or null type, 38 | * `false` if it definitely isn't, or `null` if we're not sure. 39 | */function maybeNullableAnnotation(annotation){switch(annotation.type){case 'NullableTypeAnnotation':case 'VoidTypeAnnotation':case 'NullLiteralTypeAnnotation':case 'MixedTypeAnnotation':return true;case 'TypeAnnotation':case 'FunctionTypeParam':return maybeNullableAnnotation(annotation.typeAnnotation);case 'GenericTypeAnnotation':switch(annotation.id.name){case 'Array':case 'Number':case 'Object':case 'String':case 'Boolean':case 'Date':case 'RegExp':return false;case 'Generator':if(annotation.typeParameters&&annotation.typeParameters.params.length>1){return maybeNullableAnnotation(annotation.typeParameters.params[1]);}else {return null;}default:return null;}case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion19=true;var _didIteratorError19=false;var _iteratorError19=undefined;try{for(var _iterator19=annotation.types[Symbol.iterator](),_step19;!(_iteratorNormalCompletion19=(_step19=_iterator19.next()).done);_iteratorNormalCompletion19=true){var _type10=_step19.value;var result=maybeNullableAnnotation(_type10);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError19=true;_iteratorError19=err;}finally {try{if(!_iteratorNormalCompletion19&&_iterator19.return){_iterator19.return();}}finally {if(_didIteratorError19){throw _iteratorError19;}}}if(falseCount===annotation.types.length){return false;}else {return null;}default:return false;}} /** 40 | * Returns `true` if the annotation is compatible with an object type, 41 | * `false` if it definitely isn't, or `null` if we're not sure. 42 | */function maybeInstanceOfAnnotation(annotation,expected,typeParameters){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeInstanceOfAnnotation(annotation.typeAnnotation,expected,typeParameters);case 'GenericTypeAnnotation':if(annotation.id.name===expected.name){if(typeParameters.length===0){return true;}if(annotation.typeParameters&&annotation.typeParameters.params.length){var trueCount=0;var nullCount=0;for(var i=0;i0&&nullCount===0?true:null;}}return null;case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion20=true;var _didIteratorError20=false;var _iteratorError20=undefined;try{for(var _iterator20=annotation.types[Symbol.iterator](),_step20;!(_iteratorNormalCompletion20=(_step20=_iterator20.next()).done);_iteratorNormalCompletion20=true){var _type11=_step20.value;var _result=maybeInstanceOfAnnotation(_type11,expected,typeParameters);if(_result===true){return true;}else if(_result===false){falseCount++;}}}catch(err){_didIteratorError20=true;_iteratorError20=err;}finally {try{if(!_iteratorNormalCompletion20&&_iterator20.return){_iterator20.return();}}finally {if(_didIteratorError20){throw _iteratorError20;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'VoidTypeAnnotation':case 'NullLiteralTypeAnnotation':if(expected.name==='Array'||expected.name==='RegExp'||expected.name==='Error'||expected.name==='Function'||expected.name==='String'||expected.name==='Object'){return false;}else {return null;}case 'BooleanTypeAnnotation':case 'BooleanLiteralTypeAnnotation':case 'StringTypeAnnotation':case 'StringLiteralTypeAnnotation':case 'NumberTypeAnnotation':case 'NumericLiteralTypeAnnotation':if(expected.name==='Array'||expected.name==='RegExp'||expected.name==='Error'||expected.name==='Function'){return false;}else {return null;}case 'FunctionTypeAnnotation':if(expected.name==='Function'){return true;}else {return null;}default:return null;}} /** 43 | * Returns `true` if the annotation is compatible with an array, 44 | * `false` if it definitely isn't, or `null` if we're not sure. 45 | */function maybeArrayAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeArrayAnnotation(annotation.typeAnnotation);case 'TupleTypeAnnotation':case 'ArrayTypeAnnotation':return true;case 'GenericTypeAnnotation':return annotation.id.name==='Array'?true:null;case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion21=true;var _didIteratorError21=false;var _iteratorError21=undefined;try{for(var _iterator21=annotation.types[Symbol.iterator](),_step21;!(_iteratorNormalCompletion21=(_step21=_iterator21.next()).done);_iteratorNormalCompletion21=true){var _type12=_step21.value;var result=maybeArrayAnnotation(_type12);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError21=true;_iteratorError21=err;}finally {try{if(!_iteratorNormalCompletion21&&_iterator21.return){_iterator21.return();}}finally {if(_didIteratorError21){throw _iteratorError21;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'AnyTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}} /** 46 | * Returns `true` if the annotation is compatible with an iterable, 47 | * `false` if it definitely isn't, or `null` if we're not sure. 48 | */function maybeIterableAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeIterableAnnotation(annotation.typeAnnotation);case 'TupleTypeAnnotation':case 'ArrayTypeAnnotation':return true;case 'GenericTypeAnnotation':return annotation.id.name==='Iterable'?true:null;case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion22=true;var _didIteratorError22=false;var _iteratorError22=undefined;try{for(var _iterator22=annotation.types[Symbol.iterator](),_step22;!(_iteratorNormalCompletion22=(_step22=_iterator22.next()).done);_iteratorNormalCompletion22=true){var _type13=_step22.value;var result=maybeIterableAnnotation(_type13);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError22=true;_iteratorError22=err;}finally {try{if(!_iteratorNormalCompletion22&&_iterator22.return){_iterator22.return();}}finally {if(_didIteratorError22){throw _iteratorError22;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'BooleanTypeAnnotation':case 'BooleanLiteralTypeAnnotation':case 'NumericLiteralTypeAnnotation':case 'NumberTypeAnnotation':case 'VoidTypeAnnotation':case 'NullLiteralTypeAnnotation':return false;default:return null;}} /** 49 | * Returns `true` if the annotation is compatible with a tuple, 50 | * `false` if it definitely isn't, or `null` if we're not sure. 51 | */function maybeTupleAnnotation(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':case 'NullableTypeAnnotation':return maybeTupleAnnotation(annotation.typeAnnotation);case 'TupleTypeAnnotation':return true;case 'UnionTypeAnnotation':var falseCount=0;var _iteratorNormalCompletion23=true;var _didIteratorError23=false;var _iteratorError23=undefined;try{for(var _iterator23=annotation.types[Symbol.iterator](),_step23;!(_iteratorNormalCompletion23=(_step23=_iterator23.next()).done);_iteratorNormalCompletion23=true){var _type14=_step23.value;var result=maybeTupleAnnotation(_type14);if(result===true){return true;}else if(result===false){falseCount++;}}}catch(err){_didIteratorError23=true;_iteratorError23=err;}finally {try{if(!_iteratorNormalCompletion23&&_iterator23.return){_iterator23.return();}}finally {if(_didIteratorError23){throw _iteratorError23;}}}if(falseCount===annotation.types.length){return false;}else {return null;}case 'GenericTypeAnnotation':case 'AnyTypeAnnotation':case 'ArrayTypeAnnotation':case 'MixedTypeAnnotation':case 'IntersectionTypeAnnotation':return null;default:return false;}}function humanReadableType(annotation){switch(annotation.type){case 'TypeAnnotation':case 'FunctionTypeParam':return humanReadableType(annotation.typeAnnotation);case 'FunctionTypeAnnotation': // @fixme babel doesn't seem to like generating FunctionTypeAnnotations yet 52 | return '('+annotation.params.map(humanReadableType).join(', ')+') => '+humanReadableType(annotation.returnType);case 'GenericTypeAnnotation':var path=getNodePath(annotation);var checker=path&&getTypeChecker(annotation.id,path.scope);if(checker&&checker.node.savedTypeAnnotation){return humanReadableType(checker.node.savedTypeAnnotation);}else {return (0,_babelGenerator2.default)(annotation).code;}default:return (0,_babelGenerator2.default)(annotation).code;}} /** 53 | * Get the path directly from a node. 54 | */function getNodePath(node){if(node._paths&&node._paths.length){return node._paths[0];}else {return null;}}function getTypeChecker(id,scope){var checker=scope.getData('typechecker:'+id.name);if(checker){return checker;}return false;}function isTypeChecker(id,scope){return scope.getData('typechecker:'+id.name)!==undefined;}function isPolymorphicType(id,scope){return scope.getData('typeparam:'+id.name)!==undefined;}function getPolymorphicType(id,scope){var path=scope.getData('typeparam:'+id.name);if(path){return path.node;}}function collectParamChecks(path,context){return path.get('params').map(function(param){var node=param.node;if(node.type==='AssignmentPattern'){if(node.left.typeAnnotation){return createDefaultParamGuard(param,context);}}else if(node.type==='RestElement'){if(node.typeAnnotation){return createRestParamGuard(param,context);}}else if(node.typeAnnotation){return createParamGuard(param,context);}}).filter(identity);}function createParamGuard(path,context){var node=path.node;var scope=path.scope;node.hasBeenTypeChecked=true;node.savedTypeAnnotation=node.typeAnnotation;var checkable=void 0;if(node.type==='ObjectPattern'){node.name=path.key;checkable=t.memberExpression(t.identifier('arguments'),t.numericLiteral(path.key),true);}else {checkable=node;}var check=checkAnnotation(checkable,node.typeAnnotation,scope);if(!check){return;}if(node.optional){check=t.logicalExpression('||',checks.void({input:checkable}),check);}var message=paramTypeErrorMessage(checkable,context,node.typeAnnotation);return guard({check:check,message:message});}function createDefaultParamGuard(path,context){var node=path.node;var scope=path.scope;var id=node.left;var value=node.right;var ok=staticCheckAnnotation(path.get('right'),id.typeAnnotation);if(ok===false){throw path.buildCodeFrameError(buildErrorMessage('Invalid default value for argument "'+id.name+'".',id.typeAnnotation,getAnnotation(path.get('right'))));}return createParamGuard(path.get('left'),context);}function createRestParamGuard(path,context){var node=path.node;var scope=path.scope;var id=node.argument;id.hasBeenTypeChecked=true;node.savedTypeAnnotation=node.typeAnnotation;if(isStrictlyArrayAnnotation(node.typeAnnotation)===false){throw path.buildCodeFrameError(buildErrorMessage('Invalid type annotation for rest argument "'+id.name+'".',t.genericTypeAnnotation(t.identifier('Array')),node.typeAnnotation));}var check=checkAnnotation(id,node.typeAnnotation,scope);if(!check){return;}if(node.optional){check=t.logicalExpression('||',checks.void({input:id}),check);}var message=paramTypeErrorMessage(id,context,node.typeAnnotation);return guard({check:check,message:message});}function returnTypeErrorMessage(path,fn,id,context){var node=path.node;var scope=path.scope;var name=fn.id?fn.id.name:'';var annotation=fn.returnType;if(annotation.type==='TypeAnnotation'){annotation=annotation.typeAnnotation;}if(fn.generator&&isGeneratorAnnotation(annotation)&&annotation.typeParameters&&annotation.typeParameters.params.length>1){annotation=annotation.typeParameters.params[1];}var message='Function '+(name?'"'+name+'" ':'')+'return value violates contract.\n\nExpected:\n'+humanReadableType(annotation)+'\n\nGot:\n';return t.binaryExpression('+',t.stringLiteral(message),id?readableName({inspect:context.inspect,input:id}):node.argument?readableName({inspect:context.inspect,input:node.argument}):t.stringLiteral('undefined'));}function yieldTypeErrorMessage(fn,annotation,id,context){var name=fn.id?fn.id.name:'';var message='Function '+(name?'"'+name+'" ':'')+'yielded an invalid value.\n\nExpected:\n'+humanReadableType(annotation)+'\n\nGot:\n';return t.binaryExpression('+',t.stringLiteral(message),readableName({inspect:context.inspect,input:id}));}function yieldNextTypeErrorMessage(fn,annotation,id,context){var name=fn.id?fn.id.name:'';var message='Generator '+(name?'"'+name+'" ':'')+'received an invalid next value.\n\nExpected:\n'+humanReadableType(annotation)+'\n\nGot:\n';return t.binaryExpression('+',t.stringLiteral(message),readableName({inspect:context.inspect,input:id}));}function paramTypeErrorMessage(node,context){var typeAnnotation=arguments.length<=2||arguments[2]===undefined?node.typeAnnotation:arguments[2];var name=node.name;if(node.type==='MemberExpression'&&node.object.name==='arguments'){name=node.property.value;}var message='Value of '+(node.optional?'optional ':'')+'argument '+JSON.stringify(name)+' violates contract.\n\nExpected:\n'+humanReadableType(typeAnnotation)+'\n\nGot:\n';return t.binaryExpression('+',t.stringLiteral(message),readableName({inspect:context.inspect,input:node}));}function varTypeErrorMessage(node,context){var annotation=node.typeAnnotation;if(node.type==='Identifier'){var _name3=node.name;var message='Value of variable "'+_name3+'" violates contract.\n\nExpected:\n'+humanReadableType(annotation)+'\n\nGot:\n';return t.binaryExpression('+',t.stringLiteral(message),readableName({inspect:context.inspect,input:node}));}else {var _message='Value of "'+humanReadableType(node)+'" violates contract.\n\nExpected:\n'+humanReadableType(annotation)+'\n\nGot:\n';return t.binaryExpression('+',t.stringLiteral(_message),readableName({inspect:context.inspect,input:node}));}} /** 55 | * Create a React property validator 56 | */function generatePropType(annotation,scope,context){var prop=t.identifier('prop');var check=checkAnnotation(prop,annotation,scope);if(check){return propType({check:check,prop:prop,expected:t.stringLiteral(humanReadableType(annotation)),got:readableName({inspect:context.inspect,input:prop})});}else {return t.functionExpression(null,[],t.blockStatement([]));}} /** 57 | * Determine whether the given node can produce purely boolean results. 58 | */function isBooleanExpression(node){if(node.type==='BinaryExpression'&&BOOLEAN_BINARY_OPERATORS.indexOf(node.operator)>-1){return true;}else if(node.type==='LogicalExpression'){return isBooleanExpression(node.left)&&isBooleanExpression(node.right);}else {return false;}} /** 59 | * Convert type specifier to expression. 60 | */function createTypeExpression(node){if(node.type=='Identifier'){return node;}else if(node.type=='QualifiedTypeIdentifier'){return t.memberExpression(createTypeExpression(node.qualification),createTypeExpression(node.id));}throw this.errorWithNode('Unsupported type: '+node.type);} /** 61 | * Get name of a type as a string. 62 | */function getTypeName(node){if(node.type=='Identifier'){return node.name;}else if(node.type=='QualifiedTypeIdentifier'){return getTypeName(node.qualification)+'.'+getTypeName(node.id);}throw this.errorWithNode('Unsupported type: '+node.type);} /** 63 | * Union two arrays. 64 | */function union(arr1,arr2){for(var i=0;i