From cf45afba61e1d3930db20c4b1d7021271c4a7f2f Mon Sep 17 00:00:00 2001 From: Christopher Chedeau Date: Fri, 23 Dec 2016 19:31:38 +0000 Subject: [PATCH] Add testing - This brings in the flow test suite that contains a ton of JavaScript parsing edge cases - This creates snapshot tests using the pretty printer for all of them - If uncomment `RUN_AST_TESTS` line in `tests/run_specs.js`, it checks ast(pretty_print(x)) == ast(x). Right now, "178 failed, 197 passed, 375 of 377 total". So half of the tests are not passing, most of them are crashes and many of the rest are subtle issues. --- package.json | 15 +- .../abnormal/__snapshots__/jsfmt.spec.js.snap | 127 + tests/abnormal/break-continue.js | 7 + tests/abnormal/jsfmt.spec.js | 1 + tests/abnormal/return.js | 6 + tests/abnormal/toplevel_break.js | 3 + tests/abnormal/toplevel_continue.js | 3 + tests/abnormal/toplevel_return.js | 3 + tests/abnormal/toplevel_throw.js | 3 + tests/annot/__snapshots__/jsfmt.spec.js.snap | 234 + tests/annot/annot.js | 60 + tests/annot/any/A.js | 9 + tests/annot/any/B.js | 5 + .../any/__snapshots__/jsfmt.spec.js.snap | 36 + tests/annot/any/jsfmt.spec.js | 1 + tests/annot/forward_ref.js | 14 + tests/annot/issue-530.js | 3 + tests/annot/jsfmt.spec.js | 1 + tests/annot/leak.js | 22 + tests/annot/other.js | 2 + tests/annot/scope.js | 24 + tests/annot/test.js | 2 + tests/annot2/A.js | 14 + tests/annot2/B.js | 9 + tests/annot2/T.js | 3 + tests/annot2/__snapshots__/jsfmt.spec.js.snap | 62 + tests/annot2/jsfmt.spec.js | 1 + tests/any/__snapshots__/jsfmt.spec.js.snap | 202 + tests/any/any.js | 9 + tests/any/anyexportflowfile.js | 3 + tests/any/flowfixme.js | 19 + tests/any/flowissue.js | 19 + tests/any/jsfmt.spec.js | 1 + tests/any/nonflowfile.js | 3 + tests/any/propagate.js | 25 + tests/any/reach.js | 13 + tests/arith/Arith.js | 91 + tests/arith/__snapshots__/jsfmt.spec.js.snap | 318 + tests/arith/exponent.js | 11 + tests/arith/generic.js | 7 + tests/arith/jsfmt.spec.js | 1 + tests/arith/mult.js | 12 + tests/arith/relational.js | 30 + .../__snapshots__/jsfmt.spec.js.snap | 63 + tests/array-filter/jsfmt.spec.js | 1 + tests/array-filter/test.js | 9 + tests/array-filter/test2.js | 15 + .../__snapshots__/jsfmt.spec.js.snap | 27 + tests/array_spread/jsfmt.spec.js | 1 + tests/array_spread/test.js | 8 + .../arraylib/__snapshots__/jsfmt.spec.js.snap | 76 + tests/arraylib/array_lib.js | 57 + tests/arraylib/jsfmt.spec.js | 1 + tests/arrays/Arrays.js | 39 + tests/arrays/__snapshots__/jsfmt.spec.js.snap | 77 + tests/arrays/jsfmt.spec.js | 1 + tests/arrays/numeric_elem.js | 7 + tests/arrows/__snapshots__/jsfmt.spec.js.snap | 60 + tests/arrows/advanced_arrows.js | 11 + tests/arrows/arrows.js | 10 + tests/arrows/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 34 + tests/ast_tokens/foo.js | 15 + tests/ast_tokens/jsfmt.spec.js | 1 + tests/async/__snapshots__/jsfmt.spec.js.snap | 471 ++ tests/async/async.js | 52 + tests/async/async2.js | 60 + tests/async/async3.js | 32 + tests/async/async_base_class.js | 14 + tests/async/async_parse.js | 24 + tests/async/async_promise.js | 3 + tests/async/async_return_void.js | 14 + tests/async/await_not_in_async.js | 6 + tests/async/await_not_in_async2.js | 6 + tests/async/await_not_in_async3.js | 6 + tests/async/await_parse.js | 24 + tests/async/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 213 + tests/async_iteration/delegate_yield.js | 26 + tests/async_iteration/generator.js | 25 + tests/async_iteration/jsfmt.spec.js | 1 + tests/async_iteration/return.js | 22 + tests/async_iteration/throw.js | 32 + .../__snapshots__/jsfmt.spec.js.snap | 582 ++ tests/autocomplete/bar.js | 4 + tests/autocomplete/bool.js | 3 + tests/autocomplete/customfun.js | 11 + tests/autocomplete/foo.js | 10 + tests/autocomplete/foo_parse_fail.js | 10 + tests/autocomplete/fun.js | 5 + tests/autocomplete/function_builtins.js | 5 + tests/autocomplete/generics.js | 7 + tests/autocomplete/if.js | 3 + tests/autocomplete/issue-1368.js | 22 + tests/autocomplete/jsfmt.spec.js | 1 + tests/autocomplete/jsx1.js | 8 + tests/autocomplete/jsx2.js | 8 + tests/autocomplete/num.js | 4 + tests/autocomplete/object_builtins.js | 5 + tests/autocomplete/optional.js | 5 + tests/autocomplete/override.js | 10 + tests/autocomplete/qux.js | 6 + tests/autocomplete/str.js | 3 + tests/autocomplete/this.js | 10 + tests/autocomplete/typeparams.js | 8 + tests/autocomplete/union.js | 11 + tests/autocomplete/unknown.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 7 + tests/auxiliary/client.js | 1 + tests/auxiliary/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 7 + tests/auxiliary/lib/jsfmt.spec.js | 1 + tests/auxiliary/lib/lib.js | 1 + tests/binary/__snapshots__/jsfmt.spec.js.snap | 112 + tests/binary/in.js | 54 + tests/binary/jsfmt.spec.js | 1 + .../binding/__snapshots__/jsfmt.spec.js.snap | 594 ++ tests/binding/const.js | 27 + tests/binding/jsfmt.spec.js | 1 + tests/binding/rebinding.js | 197 + tests/binding/scope.js | 109 + tests/binding/tdz.js | 100 + tests/bom/FormData.js | 67 + tests/bom/MutationObserver.js | 29 + tests/bom/__snapshots__/jsfmt.spec.js.snap | 135 + tests/bom/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 68 + tests/bounded_poly/jsfmt.spec.js | 1 + tests/bounded_poly/scope.js | 4 + tests/bounded_poly/test.js | 25 + tests/break/__snapshots__/jsfmt.spec.js.snap | 87 + tests/break/break.js | 68 + tests/break/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 21 + tests/builtin_uses/jsfmt.spec.js | 1 + tests/builtin_uses/test.js | 3 + tests/builtin_uses/test2.js | 2 + .../builtins/__snapshots__/jsfmt.spec.js.snap | 78 + tests/builtins/array.js | 17 + tests/builtins/genericfoo.js | 9 + tests/builtins/jsfmt.spec.js | 1 + tests/call_properties/A.js | 30 + tests/call_properties/B.js | 20 + tests/call_properties/C.js | 34 + tests/call_properties/D.js | 22 + tests/call_properties/E.js | 10 + tests/call_properties/F.js | 21 + .../__snapshots__/jsfmt.spec.js.snap | 256 + tests/call_properties/jsfmt.spec.js | 1 + .../callable/__snapshots__/jsfmt.spec.js.snap | 70 + tests/callable/jsfmt.spec.js | 1 + tests/callable/optional.js | 10 + tests/callable/primitives.js | 21 + .../__snapshots__/jsfmt.spec.js.snap | 30 + tests/check-contents/jsfmt.spec.js | 1 + tests/check-contents/not_flow.js | 1 + tests/check-contents/syntax_error.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 523 ++ tests/class_fields/base_class.js | 72 + tests/class_fields/derived_class.js | 134 + tests/class_fields/generic_class.js | 31 + tests/class_fields/jsfmt.spec.js | 1 + tests/class_fields/scoping.js | 40 + .../__snapshots__/jsfmt.spec.js.snap | 69 + tests/class_munging/jsfmt.spec.js | 1 + tests/class_munging/with_munging.js | 15 + tests/class_munging/without_munging.js | 16 + .../__snapshots__/jsfmt.spec.js.snap | 80 + tests/class_statics/jsfmt.spec.js | 1 + tests/class_statics/test.js | 61 + .../__snapshots__/jsfmt.spec.js.snap | 91 + tests/class_subtyping/jsfmt.spec.js | 1 + tests/class_subtyping/test.js | 5 + tests/class_subtyping/test2.js | 7 + tests/class_subtyping/test3.js | 6 + tests/class_subtyping/test4.js | 13 + .../__snapshots__/jsfmt.spec.js.snap | 64 + tests/class_type/jsfmt.spec.js | 1 + tests/class_type/test.js | 11 + tests/class_type/test2.js | 14 + tests/classes/A.js | 5 + tests/classes/B.js | 8 + tests/classes/C.js | 10 + tests/classes/D.js | 3 + .../classes/__snapshots__/jsfmt.spec.js.snap | 249 + tests/classes/class_shapes.js | 35 + tests/classes/expr.js | 30 + tests/classes/jsfmt.spec.js | 1 + tests/classes/loc.js | 5 + tests/classes/statics.js | 13 + tests/closure/Closure.js | 80 + .../closure/__snapshots__/jsfmt.spec.js.snap | 256 + tests/closure/cond_havoc.js | 13 + tests/closure/const.js | 47 + tests/closure/jsfmt.spec.js | 1 + tests/commonjs/Abs.js | 4 + tests/commonjs/Rel.js | 4 + .../commonjs/__snapshots__/jsfmt.spec.js.snap | 25 + tests/commonjs/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 133 + tests/computed_props/jsfmt.spec.js | 1 + tests/computed_props/test.js | 23 + tests/computed_props/test2.js | 10 + tests/computed_props/test3.js | 4 + tests/computed_props/test4.js | 1 + tests/computed_props/test5.js | 7 + tests/computed_props/test6.js | 2 + tests/computed_props/test7.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 50 + tests/conditional/conditional.js | 24 + tests/conditional/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 7 + tests/config_all/jsfmt.spec.js | 1 + tests/config_all/no_at_flow.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 7 + tests/config_all_false/jsfmt.spec.js | 1 + tests/config_all_false/no_at_flow.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 10 + tests/config_all_weak/jsfmt.spec.js | 1 + tests/config_all_weak/no_at_flow.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 25 + tests/config_file_extensions/jsfmt.spec.js | 1 + tests/config_file_extensions/test.js | 11 + .../__snapshots__/jsfmt.spec.js.snap | 12 + .../dir/__snapshots__/jsfmt.spec.js.snap | 10 + tests/config_ignore/dir/foo.js | 3 + tests/config_ignore/dir/jsfmt.spec.js | 1 + tests/config_ignore/foo.js | 4 + tests/config_ignore/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 15 + .../jsfmt.spec.js | 1 + .../main.js | 6 + .../src/__snapshots__/jsfmt.spec.js.snap | 10 + .../src/jsfmt.spec.js | 1 + .../src/testmodule.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 12 + .../jsfmt.spec.js | 1 + .../test.js | 4 + tests/config_module_name_rewrite_haste/A.js | 13 + .../Exists.js | 8 + .../__snapshots__/jsfmt.spec.js.snap | 48 + .../jsfmt.spec.js | 1 + tests/config_module_name_rewrite_node/A.js | 25 + .../config_module_name_rewrite_node/Exists.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 65 + .../jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 15 + .../testproj/__snapshots__/jsfmt.spec.js.snap | 10 + .../custom_resolve_dir/testproj/index.js | 3 + .../custom_resolve_dir/testproj/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 10 + .../custom_resolve_dir/testproj2/index.js | 3 + .../testproj2/jsfmt.spec.js | 1 + .../jsfmt.spec.js | 1 + .../subdir/__snapshots__/jsfmt.spec.js.snap | 15 + .../__snapshots__/jsfmt.spec.js.snap | 10 + .../custom_resolve_dir/testproj2/index.js | 3 + .../testproj2/jsfmt.spec.js | 1 + .../subdir/jsfmt.spec.js | 1 + .../subdir/sublevel.js | 6 + .../toplevel.js | 6 + .../__snapshots__/jsfmt.spec.js.snap | 98 + tests/config_munging_underscores/chain.js | 34 + .../commonjs_export.js | 7 + .../commonjs_import.js | 3 + .../config_munging_underscores/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 69 + tests/config_munging_underscores2/chain.js | 34 + .../config_munging_underscores2/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 63 + tests/const_params/jsfmt.spec.js | 1 + tests/const_params/test.js | 29 + .../__snapshots__/jsfmt.spec.js.snap | 25 + tests/constructor/constructor.js | 9 + tests/constructor/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 63 + tests/constructor_annots/constructors.js | 21 + tests/constructor_annots/jsfmt.spec.js | 1 + tests/constructor_annots/test.js | 9 + .../ignore/__snapshots__/jsfmt.spec.js.snap | 18 + tests/contents/ignore/dummy.js | 0 tests/contents/ignore/jsfmt.spec.js | 1 + tests/contents/ignore/test.js | 3 + .../no_flow/__snapshots__/jsfmt.spec.js.snap | 18 + tests/contents/no_flow/dummy.js | 0 tests/contents/no_flow/jsfmt.spec.js | 1 + tests/contents/no_flow/test.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 253 + tests/core_tests/boolean.js | 42 + tests/core_tests/jsfmt.spec.js | 1 + tests/core_tests/map.js | 32 + tests/core_tests/regexp.js | 29 + tests/core_tests/weakset.js | 36 + .../__snapshots__/jsfmt.spec.js.snap | 68 + tests/covariance/jsfmt.spec.js | 1 + tests/covariance/test.js | 49 + .../coverage/__snapshots__/jsfmt.spec.js.snap | 80 + tests/coverage/crash.js | 11 + tests/coverage/declare_module.js | 4 + tests/coverage/jsfmt.spec.js | 1 + tests/coverage/no_pragma.js | 2 + tests/coverage/non-termination.js | 14 + tests/cycle/A.js | 5 + tests/cycle/B.js | 5 + tests/cycle/__snapshots__/jsfmt.spec.js.snap | 27 + tests/cycle/jsfmt.spec.js | 1 + tests/date/__snapshots__/jsfmt.spec.js.snap | 57 + tests/date/date.js | 28 + tests/date/jsfmt.spec.js | 1 + .../ExplicitProvidesModuleDifferentName.js | 6 + .../ExplicitProvidesModuleSameName.js | 6 + .../ImplicitProvidesModule.js | 6 + .../__snapshots__/jsfmt.spec.js.snap | 81 + .../_d3/__snapshots__/jsfmt.spec.js.snap | 7 + .../external/_d3/jsfmt.spec.js | 1 + .../external/_d3/min.js | 1 + .../foo/bar/__snapshots__/jsfmt.spec.js.snap | 28 + .../foo/bar/jsfmt.spec.js | 1 + .../foo/bar/nested_test.js | 13 + tests/declaration_files_haste/jsfmt.spec.js | 1 + tests/declaration_files_haste/md5.js | 1 + tests/declaration_files_haste/test.js | 10 + .../ws/__snapshots__/jsfmt.spec.js.snap | 6 + tests/declaration_files_haste/ws/index.js | 0 .../declaration_files_haste/ws/jsfmt.spec.js | 1 + .../ws/test/__snapshots__/jsfmt.spec.js.snap | 7 + .../declaration_files_haste/ws/test/client.js | 1 + .../ws/test/jsfmt.spec.js | 1 + .../declaration_files_incremental_haste/A.js | 3 + .../ExplicitProvidesModuleDifferentName.js | 7 + .../ExplicitProvidesModuleSameName.js | 7 + .../ImplicitProvidesModule.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 101 + .../_d3/__snapshots__/jsfmt.spec.js.snap | 9 + .../external/_d3/jsfmt.spec.js | 1 + .../external/_d3/min.js | 2 + .../foo/bar/__snapshots__/jsfmt.spec.js.snap | 21 + .../foo/bar/jsfmt.spec.js | 1 + .../foo/bar/nested_test.js | 9 + .../jsfmt.spec.js | 1 + .../md5.js | 1 + .../test.js | 10 + .../ws/__snapshots__/jsfmt.spec.js.snap | 6 + .../ws/index.js | 0 .../ws/jsfmt.spec.js | 1 + .../ws/test/__snapshots__/jsfmt.spec.js.snap | 7 + .../ws/test/client.js | 1 + .../ws/test/jsfmt.spec.js | 1 + tests/declaration_files_incremental_node/A.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 98 + .../jsfmt.spec.js | 1 + .../test_absolute.js | 41 + .../test_relative.js | 3 + tests/declaration_files_node/A.js | 3 + tests/declaration_files_node/CJS.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 91 + tests/declaration_files_node/jsfmt.spec.js | 1 + tests/declaration_files_node/test_absolute.js | 21 + tests/declaration_files_node/test_relative.js | 13 + .../__snapshots__/jsfmt.spec.js.snap | 29 + tests/declare_class/declare_class.js | 10 + tests/declare_class/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 28 + tests/declare_class/lib/jsfmt.spec.js | 1 + tests/declare_class/lib/test.js | 9 + tests/declare_export/B.js | 3 + tests/declare_export/C.js | 1 + .../CommonJS_Clobbering_Class.js | 21 + .../declare_export/CommonJS_Clobbering_Lit.js | 12 + tests/declare_export/CommonJS_Named.js | 10 + tests/declare_export/ES6_DefaultAndNamed.js | 4 + .../ES6_Default_AnonFunction1.js | 6 + .../ES6_Default_AnonFunction2.js | 6 + .../declare_export/ES6_Default_NamedClass1.js | 12 + .../declare_export/ES6_Default_NamedClass2.js | 6 + .../ES6_Default_NamedFunction1.js | 6 + .../ES6_Default_NamedFunction2.js | 6 + .../declare_export/ES6_ExportAllFromMulti.js | 4 + .../ES6_ExportAllFrom_Intermediary1.js | 6 + .../ES6_ExportAllFrom_Intermediary2.js | 6 + .../ES6_ExportAllFrom_Source1.js | 6 + .../ES6_ExportAllFrom_Source2.js | 6 + .../ES6_ExportFrom_Intermediary1.js | 9 + .../ES6_ExportFrom_Intermediary2.js | 9 + .../declare_export/ES6_ExportFrom_Source1.js | 7 + .../declare_export/ES6_ExportFrom_Source2.js | 7 + tests/declare_export/ES6_Named1.js | 21 + tests/declare_export/ES6_Named2.js | 19 + tests/declare_export/ProvidesModuleA.js | 10 + .../ProvidesModuleCJSDefault.js | 8 + tests/declare_export/ProvidesModuleD.js | 4 + .../ProvidesModuleES6Default.js | 10 + tests/declare_export/SideEffects.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 1212 ++++ tests/declare_export/es6modules.js | 291 + tests/declare_export/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 26 + tests/declare_fun/jsfmt.spec.js | 1 + tests/declare_fun/test.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 49 + .../__snapshots__/jsfmt.spec.js.snap | 60 + .../flow-typed/jsfmt.spec.js | 1 + .../declare_module_exports/flow-typed/libs.js | 30 + tests/declare_module_exports/jsfmt.spec.js | 1 + tests/declare_module_exports/main.js | 25 + .../__snapshots__/jsfmt.spec.js.snap | 49 + tests/declare_type/import_declare_type.js | 30 + tests/declare_type/jsfmt.spec.js | 1 + .../lib/DeclareModule_TypeAlias.js | 9 + .../lib/__snapshots__/jsfmt.spec.js.snap | 65 + .../declare_type/lib/declare_type_exports.js | 17 + tests/declare_type/lib/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 50 + tests/def_site_variance/jsfmt.spec.js | 1 + tests/def_site_variance/test.js | 31 + tests/demo/1/__snapshots__/jsfmt.spec.js.snap | 20 + tests/demo/1/f.js | 8 + tests/demo/1/jsfmt.spec.js | 1 + tests/demo/2/A.js | 19 + tests/demo/2/B.js | 3 + tests/demo/2/__snapshots__/jsfmt.spec.js.snap | 54 + tests/demo/2/jsfmt.spec.js | 1 + tests/deps/A.js | 1 + tests/deps/B.js | 1 + tests/deps/C.js | 4 + tests/deps/D.js | 1 + tests/deps/E.js | 1 + tests/deps/F.js | 1 + tests/deps/G.js | 1 + tests/deps/H.js | 1 + tests/deps/I.js | 1 + tests/deps/__snapshots__/jsfmt.spec.js.snap | 77 + tests/deps/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 480 ++ tests/destructuring/array_rest.js | 12 + tests/destructuring/computed.js | 9 + tests/destructuring/defaults.js | 82 + tests/destructuring/destructuring.js | 71 + tests/destructuring/destructuring_init.js | 5 + tests/destructuring/destructuring_param.js | 11 + tests/destructuring/eager.js | 2 + tests/destructuring/jsfmt.spec.js | 1 + tests/destructuring/poly.js | 32 + tests/destructuring/rec.js | 20 + tests/destructuring/string_lit.js | 5 + tests/destructuring/unannotated.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 561 ++ tests/dictionary/any.js | 5 + tests/dictionary/compatible.js | 15 + tests/dictionary/dictionary.js | 320 + tests/dictionary/incompatible.js | 57 + tests/dictionary/issue-1745.js | 25 + tests/dictionary/jsfmt.spec.js | 1 + tests/dictionary/test.js | 10 + tests/dictionary/test_client.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 840 +++ tests/disjoint-union-perf/ast.js | 80 + tests/disjoint-union-perf/emit.js | 65 + tests/disjoint-union-perf/jsAst.js | 636 ++ tests/disjoint-union-perf/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 108 + tests/docblock_flow/jsfmt.spec.js | 1 + tests/docblock_flow/license_with_flow.js | 4 + tests/docblock_flow/max_header_tokens.js | 8 + tests/docblock_flow/multiple_flows_1.js | 2 + tests/docblock_flow/multiple_flows_2.js | 4 + .../multiple_providesModule_1.js | 5 + .../multiple_providesModule_2.js | 7 + tests/docblock_flow/use_strict_with_flow.js | 4 + tests/docblock_flow/with_flow.js | 3 + tests/docblock_flow/without_flow.js | 3 + tests/dom/CanvasRenderingContext2D.js | 13 + tests/dom/CustomEvent.js | 9 + tests/dom/Document.js | 11 + tests/dom/Element.js | 18 + tests/dom/HTMLCanvasElement.js | 8 + tests/dom/HTMLElement.js | 18 + tests/dom/HTMLInputElement.js | 12 + tests/dom/URL.js | 20 + tests/dom/__snapshots__/jsfmt.spec.js.snap | 700 +++ tests/dom/eventtarget.js | 25 + tests/dom/jsfmt.spec.js | 1 + tests/dom/path2d.js | 11 + tests/dom/registerElement.js | 58 + tests/dom/traversal.js | 195 + .../__snapshots__/jsfmt.spec.js.snap | 58 + tests/dump-types/import.js | 5 + tests/dump-types/jsfmt.spec.js | 1 + tests/dump-types/test.js | 21 + .../__snapshots__/jsfmt.spec.js.snap | 88 + tests/duplicate_methods/jsfmt.spec.js | 1 + tests/duplicate_methods/test.js | 35 + tests/encaps/__snapshots__/jsfmt.spec.js.snap | 34 + tests/encaps/encaps.js | 16 + tests/encaps/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 45 + tests/enumerror/enumerror.js | 26 + tests/enumerror/jsfmt.spec.js | 1 + tests/equals/__snapshots__/jsfmt.spec.js.snap | 27 + tests/equals/equals.js | 12 + tests/equals/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + tests/error_messages/errors.js | 1 + tests/error_messages/jsfmt.spec.js | 1 + tests/es6modules/B.js | 3 + tests/es6modules/C.js | 1 + tests/es6modules/CommonJS_Clobbering_Class.js | 21 + .../es6modules/CommonJS_Clobbering_Frozen.js | 8 + tests/es6modules/CommonJS_Clobbering_Lit.js | 12 + tests/es6modules/CommonJS_Named.js | 10 + tests/es6modules/ES6_DefaultAndNamed.js | 4 + tests/es6modules/ES6_Default_AnonClass1.js | 6 + tests/es6modules/ES6_Default_AnonClass2.js | 6 + tests/es6modules/ES6_Default_AnonFunction1.js | 6 + tests/es6modules/ES6_Default_AnonFunction2.js | 6 + tests/es6modules/ES6_Default_NamedClass1.js | 11 + tests/es6modules/ES6_Default_NamedClass2.js | 6 + .../es6modules/ES6_Default_NamedFunction1.js | 6 + .../es6modules/ES6_Default_NamedFunction2.js | 6 + tests/es6modules/ES6_ExportAllFromMulti.js | 4 + .../ES6_ExportAllFrom_Intermediary1.js | 6 + .../ES6_ExportAllFrom_Intermediary2.js | 6 + tests/es6modules/ES6_ExportAllFrom_Source1.js | 6 + tests/es6modules/ES6_ExportAllFrom_Source2.js | 6 + .../ES6_ExportFrom_Intermediary1.js | 9 + .../ES6_ExportFrom_Intermediary2.js | 9 + tests/es6modules/ES6_ExportFrom_Source1.js | 6 + tests/es6modules/ES6_ExportFrom_Source2.js | 6 + tests/es6modules/ES6_Named1.js | 22 + tests/es6modules/ES6_Named2.js | 20 + tests/es6modules/ExportType.js | 3 + tests/es6modules/ProvidesModuleA.js | 10 + tests/es6modules/ProvidesModuleCJSDefault.js | 8 + tests/es6modules/ProvidesModuleD.js | 4 + tests/es6modules/ProvidesModuleES6Default.js | 10 + tests/es6modules/SideEffects.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 1297 ++++ tests/es6modules/es6modules.js | 296 + tests/es6modules/jsfmt.spec.js | 1 + tests/es6modules/test_imports_are_frozen.js | 52 + .../__snapshots__/jsfmt.spec.js.snap | 80 + tests/es_declare_module/es_declare_module.js | 41 + .../__snapshots__/jsfmt.spec.js.snap | 40 + .../es_declare_module/flow-typed/declares.js | 21 + .../flow-typed/jsfmt.spec.js | 1 + tests/es_declare_module/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 20 + .../jsfmt.spec.js | 1 + .../test.js | 8 + .../__snapshots__/jsfmt.spec.js.snap | 18 + .../jsfmt.spec.js | 1 + .../test.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 18 + .../jsfmt.spec.js | 1 + .../test.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 18 + .../jsfmt.spec.js | 1 + .../test.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 29 + .../jsfmt.spec.js | 1 + tests/esproposal_decorators.ignore/test.js | 11 + .../__snapshots__/jsfmt.spec.js.snap | 29 + .../esproposal_decorators.warn/jsfmt.spec.js | 1 + tests/esproposal_decorators.warn/test.js | 11 + .../__snapshots__/jsfmt.spec.js.snap | 56 + .../esproposal_export_star_as.enable/dest.js | 9 + .../jsfmt.spec.js | 1 + .../source.js | 4 + .../esproposal_export_star_as.enable/test.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 56 + .../esproposal_export_star_as.ignore/dest.js | 9 + .../jsfmt.spec.js | 1 + .../source.js | 4 + .../esproposal_export_star_as.ignore/test.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 22 + .../jsfmt.spec.js | 1 + tests/esproposal_export_star_as.warn/test.js | 3 + tests/export_default/P.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 27 + tests/export_default/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 30 + tests/export_default/lib/jsfmt.spec.js | 1 + tests/export_default/lib/lib.js | 11 + tests/export_default/test.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 141 + tests/export_type/cjs_with_types.js | 6 + tests/export_type/importer.js | 32 + tests/export_type/jsfmt.spec.js | 1 + tests/export_type/types_only.js | 15 + tests/export_type/types_only2.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 9 + tests/extensions/foo.js | 2 + tests/extensions/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 23 + tests/facebook_fbt_none/jsfmt.spec.js | 1 + tests/facebook_fbt_none/main.js | 4 + .../__snapshots__/jsfmt.spec.js.snap | 12 + .../__snapshots__/jsfmt.spec.js.snap | 7 + tests/facebook_fbt_some/flow-typed/fbt.js | 1 + .../flow-typed/jsfmt.spec.js | 1 + tests/facebook_fbt_some/jsfmt.spec.js | 1 + tests/facebook_fbt_some/main.js | 4 + tests/facebookisms/Bar.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 242 + tests/facebookisms/copyProperties.js | 39 + tests/facebookisms/invariant.js | 14 + tests/facebookisms/jsfmt.spec.js | 1 + tests/facebookisms/lib.js | 11 + tests/facebookisms/mergeInto.js | 34 + tests/facebookisms/test.js | 9 + tests/fetch/__snapshots__/jsfmt.spec.js.snap | 329 + tests/fetch/fetch.js | 25 + tests/fetch/headers.js | 28 + tests/fetch/jsfmt.spec.js | 1 + tests/fetch/request.js | 51 + tests/fetch/response.js | 46 + tests/fetch/urlsearchparams.js | 28 + .../__snapshots__/jsfmt.spec.js.snap | 20 + tests/find-module/jsfmt.spec.js | 1 + tests/find-module/req.js | 1 + tests/find-module/test.js | 4 + .../__snapshots__/jsfmt.spec.js.snap | 77 + tests/find-refs/jsfmt.spec.js | 1 + tests/find-refs/locals.js | 58 + tests/fixpoint/Fun.js | 30 + tests/fixpoint/Ycombinator.js | 21 + .../fixpoint/__snapshots__/jsfmt.spec.js.snap | 120 + tests/fixpoint/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 7 + tests/flow_ast.template_strings/foo.js | 1 + tests/flow_ast.template_strings/jsfmt.spec.js | 1 + tests/for/__snapshots__/jsfmt.spec.js.snap | 272 + tests/for/abnormal.js | 47 + tests/for/abnormal_for_in.js | 42 + tests/for/abnormal_for_of.js | 42 + tests/for/jsfmt.spec.js | 1 + tests/forof/__snapshots__/jsfmt.spec.js.snap | 72 + tests/forof/forof.js | 53 + tests/forof/jsfmt.spec.js | 1 + .../function/__snapshots__/jsfmt.spec.js.snap | 287 + tests/function/apply.js | 42 + tests/function/bind.js | 9 + tests/function/call.js | 35 + tests/function/function.js | 66 + tests/function/jsfmt.spec.js | 1 + tests/function/rest.js | 19 + tests/funrec/__snapshots__/jsfmt.spec.js.snap | 19 + tests/funrec/funrec.js | 6 + tests/funrec/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 454 ++ tests/generators/class.js | 129 + tests/generators/class_failure.js | 20 + tests/generators/generators.js | 129 + tests/generators/jsfmt.spec.js | 1 + tests/generators/return.js | 21 + tests/generators/throw.js | 25 + tests/generators/variance.js | 2 + .../generics/__snapshots__/jsfmt.spec.js.snap | 62 + tests/generics/generics.js | 43 + tests/generics/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 39 + tests/geolocation/a.js | 20 + tests/geolocation/jsfmt.spec.js | 1 + .../get-def/__snapshots__/jsfmt.spec.js.snap | 83 + tests/get-def/example.js | 15 + .../helpers/__snapshots__/jsfmt.spec.js.snap | 26 + tests/get-def/helpers/exports_default.js | 5 + tests/get-def/helpers/exports_named.js | 4 + tests/get-def/helpers/jsfmt.spec.js | 1 + tests/get-def/imports.js | 11 + tests/get-def/jsfmt.spec.js | 1 + tests/get-def/library.js | 13 + tests/get-def2/Parent.js | 4 + .../get-def2/__snapshots__/jsfmt.spec.js.snap | 127 + tests/get-def2/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 26 + tests/get-def2/lib/jsfmt.spec.js | 1 + tests/get-def2/lib/jsx.js | 7 + tests/get-def2/main.js | 23 + tests/get-def2/override.js | 11 + tests/get-def2/react.js | 11 + tests/get-def2/types.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 35 + tests/get-imports-and-importers/a.js | 1 + tests/get-imports-and-importers/b.js | 5 + tests/get-imports-and-importers/c.js | 3 + tests/get-imports-and-importers/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 26 + .../getters_and_setters.js | 9 + .../jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 451 ++ tests/getters_and_setters_enabled/class.js | 55 + .../getters_and_setters_enabled/jsfmt.spec.js | 1 + tests/getters_and_setters_enabled/object.js | 60 + tests/getters_and_setters_enabled/react.js | 11 + tests/getters_and_setters_enabled/variance.js | 70 + tests/haste_cycle/API.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 10 + tests/haste_cycle/jsfmt.spec.js | 1 + tests/haste_cycle/models/OpenGraphAction.js | 3 + tests/haste_cycle/models/OpenGraphObject.js | 3 + .../models/OpenGraphValueContainer.js | 3 + .../models/__snapshots__/jsfmt.spec.js.snap | 32 + tests/haste_cycle/models/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 51 + tests/haste_dupe/dupe1.js | 6 + tests/haste_dupe/dupe2.js | 6 + tests/haste_dupe/jsfmt.spec.js | 1 + tests/haste_dupe/requires_dupe.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 31 + tests/ignore_package/foo.js | 14 + tests/ignore_package/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 29 + tests/immutable_methods/jsfmt.spec.js | 1 + tests/immutable_methods/test.js | 9 + tests/import_type/ExportCJSDefault_Class.js | 12 + tests/import_type/ExportCJSNamed_Class.js | 22 + tests/import_type/ExportDefault_Class.js | 10 + tests/import_type/ExportNamed_Alias.js | 12 + tests/import_type/ExportNamed_Class.js | 10 + tests/import_type/ExportsANumber.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 340 + tests/import_type/import_type.js | 82 + tests/import_type/issue-359.js | 5 + tests/import_type/jsfmt.spec.js | 1 + tests/import_typeof/ExportCJSDefault_Class.js | 12 + .../import_typeof/ExportCJSDefault_Number.js | 3 + tests/import_typeof/ExportCJSNamed_Class.js | 7 + tests/import_typeof/ExportCJSNamed_Number.js | 3 + tests/import_typeof/ExportDefault_Class.js | 9 + tests/import_typeof/ExportDefault_Number.js | 3 + tests/import_typeof/ExportNamed_Alias.js | 12 + tests/import_typeof/ExportNamed_Class.js | 9 + tests/import_typeof/ExportNamed_Multi.js | 4 + tests/import_typeof/ExportNamed_Number.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 371 ++ tests/import_typeof/import_typeof.js | 103 + tests/import_typeof/jsfmt.spec.js | 1 + .../batman/__snapshots__/jsfmt.spec.js.snap | 10 + tests/include/foo/batman/baz.js | 3 + tests/include/foo/batman/jsfmt.spec.js | 1 + .../included/__snapshots__/jsfmt.spec.js.snap | 7 + tests/include/included/jsfmt.spec.js | 1 + tests/include/included/test.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 33 + tests/incremental/a.js | 1 + tests/incremental/b.js | 5 + tests/incremental/dup_a.js | 3 + tests/incremental/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 39 + tests/incremental_basic/a.js | 3 + tests/incremental_basic/b.js | 4 + tests/incremental_basic/c.js | 4 + tests/incremental_basic/jsfmt.spec.js | 1 + .../tmp1/__snapshots__/jsfmt.spec.js.snap | 13 + tests/incremental_basic/tmp1/b.js | 4 + tests/incremental_basic/tmp1/jsfmt.spec.js | 1 + .../tmp2/__snapshots__/jsfmt.spec.js.snap | 11 + tests/incremental_basic/tmp2/a.js | 3 + tests/incremental_basic/tmp2/jsfmt.spec.js | 1 + .../tmp3/__snapshots__/jsfmt.spec.js.snap | 13 + tests/incremental_basic/tmp3/b.js | 4 + tests/incremental_basic/tmp3/jsfmt.spec.js | 1 + tests/incremental_cycle/A.js | 8 + tests/incremental_cycle/B.js | 9 + tests/incremental_cycle/C.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 63 + tests/incremental_cycle/jsfmt.spec.js | 1 + tests/incremental_cycle/tmp1/B.js | 5 + tests/incremental_cycle/tmp1/C.js | 9 + .../tmp1/__snapshots__/jsfmt.spec.js.snap | 36 + tests/incremental_cycle/tmp1/jsfmt.spec.js | 1 + tests/incremental_cycle/tmp2/B.js | 5 + .../tmp2/__snapshots__/jsfmt.spec.js.snap | 14 + tests/incremental_cycle/tmp2/jsfmt.spec.js | 1 + tests/incremental_cycle/tmp3/B.js | 6 + .../tmp3/__snapshots__/jsfmt.spec.js.snap | 15 + tests/incremental_cycle/tmp3/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 123 + tests/incremental_delete/a.js | 3 + tests/incremental_delete/b.js | 4 + tests/incremental_delete/c.js | 4 + tests/incremental_delete/dupe1.js | 6 + tests/incremental_delete/dupe2.js | 6 + tests/incremental_delete/jsfmt.spec.js | 1 + tests/incremental_delete/requires_dupe.js | 5 + .../incremental_delete/requires_unchecked.js | 5 + tests/incremental_delete/unchecked.js | 5 + tests/incremental_duplicate_delete/A.js | 4 + .../__snapshots__/jsfmt.spec.js.snap | 10 + .../jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 15 + tests/incremental_json/jsfmt.spec.js | 1 + tests/incremental_json/test.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 102 + tests/incremental_mixed_naming_cycle/a.js | 9 + tests/incremental_mixed_naming_cycle/b.js | 9 + tests/incremental_mixed_naming_cycle/c.js | 9 + tests/incremental_mixed_naming_cycle/d.js | 8 + .../jsfmt.spec.js | 1 + tests/incremental_mixed_naming_cycle/root.js | 6 + .../tmp1/__snapshots__/jsfmt.spec.js.snap | 18 + .../tmp1/jsfmt.spec.js | 1 + .../tmp1/root.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 24 + tests/incremental_non_flow_move/foo.js | 3 + tests/incremental_non_flow_move/jsfmt.spec.js | 1 + tests/incremental_non_flow_move/test.js | 5 + .../dir/__snapshots__/jsfmt.spec.js.snap | 9 + tests/incremental_path/dir/a.js | 2 + tests/incremental_path/dir/jsfmt.spec.js | 1 + tests/indexer/A.js | 39 + .../indexer/__snapshots__/jsfmt.spec.js.snap | 101 + tests/indexer/jsfmt.spec.js | 1 + tests/indexer/multiple.js | 10 + tests/init/__snapshots__/jsfmt.spec.js.snap | 552 ++ tests/init/hoisted.js | 46 + tests/init/hoisted2.js | 268 + tests/init/jsfmt.spec.js | 1 + tests/init/let.js | 157 + tests/init/nullable-init.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 106 + tests/instanceof/instanceof.js | 87 + tests/instanceof/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 17 + tests/integration/bar.js | 1 + tests/integration/foo.js | 2 + tests/integration/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 211 + tests/interface/import.js | 2 + tests/interface/indexer.js | 10 + tests/interface/interface.js | 12 + tests/interface/jsfmt.spec.js | 1 + tests/interface/test.js | 22 + tests/interface/test2.js | 10 + tests/interface/test3.js | 7 + tests/interface/test4.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 207 + tests/intersection/intersection.js | 7 + tests/intersection/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 53 + tests/intersection/lib/jsfmt.spec.js | 1 + tests/intersection/lib/lib.js | 34 + tests/intersection/objassign.js | 11 + tests/intersection/pred.js | 24 + tests/intersection/test_fun.js | 31 + tests/intersection/test_obj.js | 29 + .../__snapshots__/jsfmt.spec.js.snap | 25 + tests/issues-11/export.js | 3 + tests/issues-11/import.js | 4 + tests/issues-11/jsfmt.spec.js | 1 + tests/iter/__snapshots__/jsfmt.spec.js.snap | 73 + tests/iter/iter.js | 37 + tests/iter/jsfmt.spec.js | 1 + .../iterable/__snapshots__/jsfmt.spec.js.snap | 270 + tests/iterable/array.js | 10 + tests/iterable/caching_bug.js | 21 + tests/iterable/iter.js | 11 + tests/iterable/iterator_result.js | 29 + tests/iterable/jsfmt.spec.js | 1 + tests/iterable/map.js | 15 + tests/iterable/set.js | 15 + tests/iterable/string.js | 5 + tests/iterable/variance.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 76 + tests/jsx_intrinsics.builtin/jsfmt.spec.js | 1 + tests/jsx_intrinsics.builtin/main.js | 21 + tests/jsx_intrinsics.builtin/strings.js | 18 + .../__snapshots__/jsfmt.spec.js.snap | 73 + tests/jsx_intrinsics.custom/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 26 + tests/jsx_intrinsics.custom/lib/jsfmt.spec.js | 1 + tests/jsx_intrinsics.custom/lib/jsx.js | 7 + tests/jsx_intrinsics.custom/main.js | 17 + tests/jsx_intrinsics.custom/strings.js | 18 + tests/keys/__snapshots__/jsfmt.spec.js.snap | 64 + tests/keys/jsfmt.spec.js | 1 + tests/keys/keys.js | 45 + .../keyvalue/__snapshots__/jsfmt.spec.js.snap | 18 + tests/keyvalue/jsfmt.spec.js | 1 + tests/keyvalue/keyvalue.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 95 + .../jsfmt.spec.js | 1 + tests/last_duplicate_property_wins/test.js | 41 + tests/lib/__snapshots__/jsfmt.spec.js.snap | 26 + tests/lib/jsfmt.spec.js | 1 + tests/lib/libtest.js | 11 + .../__snapshots__/jsfmt.spec.js.snap | 26 + .../lib_interfaces/declarations/jsfmt.spec.js | 1 + .../lib_interfaces/declarations/underscore.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 51 + tests/libconfig/jsfmt.spec.js | 1 + tests/libconfig/libA.js | 1 + tests/libconfig/libB.js | 1 + tests/libconfig/libtest.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 13 + tests/libdef_ignored_module/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 11 + tests/libdef_ignored_module/lib/foo.js | 3 + tests/libdef_ignored_module/lib/jsfmt.spec.js | 1 + tests/libdef_ignored_module/test.js | 5 + tests/liberr/__snapshots__/jsfmt.spec.js.snap | 15 + tests/liberr/a.js | 5 + tests/liberr/jsfmt.spec.js | 1 + .../libs/__snapshots__/jsfmt.spec.js.snap | 51 + tests/liberr/libs/jsfmt.spec.js | 1 + tests/liberr/libs/parse_error.js | 10 + tests/liberr/libs/type_error.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 9 + .../__snapshots__/jsfmt.spec.js.snap | 20 + tests/libflow-typed/flow-typed/dino.js | 1 + tests/libflow-typed/flow-typed/jsfmt.spec.js | 1 + tests/libflow-typed/jsfmt.spec.js | 1 + tests/libflow-typed/libtest.js | 2 + tests/librec/__snapshots__/jsfmt.spec.js.snap | 9 + tests/librec/jsfmt.spec.js | 1 + .../lib/A/__snapshots__/jsfmt.spec.js.snap | 20 + tests/librec/lib/A/jsfmt.spec.js | 1 + tests/librec/lib/A/libA.js | 1 + .../lib/B/__snapshots__/jsfmt.spec.js.snap | 20 + tests/librec/lib/B/jsfmt.spec.js | 1 + tests/librec/lib/B/libB.js | 1 + tests/librec/libtest.js | 2 + .../literal/__snapshots__/jsfmt.spec.js.snap | 104 + tests/literal/enum.js | 6 + tests/literal/enum_client.js | 21 + tests/literal/jsfmt.spec.js | 1 + tests/literal/number.js | 23 + tests/locals/__snapshots__/jsfmt.spec.js.snap | 122 + tests/locals/jsfmt.spec.js | 1 + tests/locals/lex.js | 60 + tests/locals/locals.js | 23 + .../logical/__snapshots__/jsfmt.spec.js.snap | 533 ++ tests/logical/jsfmt.spec.js | 1 + tests/logical/logical.js | 514 ++ tests/loners/__snapshots__/jsfmt.spec.js.snap | 28 + tests/loners/jsfmt.spec.js | 1 + tests/loners/loners.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 74 + .../exports_optional_prop.js | 7 + tests/method_properties/jsfmt.spec.js | 1 + tests/method_properties/test.js | 18 + tests/misc/A.js | 14 + tests/misc/B.js | 15 + tests/misc/C.js | 14 + tests/misc/D.js | 14 + tests/misc/E.js | 10 + tests/misc/F.js | 6 + tests/misc/G.js | 7 + tests/misc/__snapshots__/jsfmt.spec.js.snap | 191 + tests/misc/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 107 + tests/missing_annotation/array.js | 5 + tests/missing_annotation/async_return.js | 5 + tests/missing_annotation/infer.js | 58 + tests/missing_annotation/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 13 + tests/modified_lib/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 22 + tests/modified_lib/lib/jsfmt.spec.js | 1 + tests/modified_lib/lib/lib.js | 3 + tests/modified_lib/test.js | 5 + .../src/__snapshots__/jsfmt.spec.js.snap | 17 + tests/module_not_found_errors/src/index.js | 7 + .../module_not_found_errors/src/jsfmt.spec.js | 1 + tests/module_redirect/A.js | 3 + tests/module_redirect/B.js | 6 + tests/module_redirect/C.js | 6 + tests/module_redirect/D.js | 8 + .../__snapshots__/jsfmt.spec.js.snap | 77 + tests/module_redirect/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 22 + tests/module_use_strict/jsfmt.spec.js | 1 + tests/module_use_strict/test.js | 3 + .../modules/__snapshots__/jsfmt.spec.js.snap | 53 + tests/modules/cli.js | 5 + tests/modules/cli2.js | 5 + tests/modules/jsfmt.spec.js | 1 + tests/modules/lib.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 81 + tests/more_annot/client_object.js | 3 + tests/more_annot/jsfmt.spec.js | 1 + tests/more_annot/object.js | 9 + tests/more_annot/proto.js | 6 + tests/more_annot/super.js | 4 + tests/more_classes/Bar.js | 20 + tests/more_classes/Foo.js | 26 + tests/more_classes/Qux.js | 12 + .../__snapshots__/jsfmt.spec.js.snap | 121 + tests/more_classes/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 48 + tests/more_generics/jsfmt.spec.js | 1 + tests/more_generics/poly.js | 29 + tests/more_path/Condition.js | 57 + tests/more_path/FlowSA.js | 12 + tests/more_path/Sigma.js | 40 + .../__snapshots__/jsfmt.spec.js.snap | 271 + tests/more_path/jsfmt.spec.js | 1 + tests/more_path/test.js | 14 + tests/more_react/API.react.js | 8 + tests/more_react/App.react.js | 43 + tests/more_react/JSX.js | 12 + .../__snapshots__/jsfmt.spec.js.snap | 160 + tests/more_react/jsfmt.spec.js | 1 + tests/more_react/propTypes.js | 18 + .../__snapshots__/jsfmt.spec.js.snap | 27 + tests/more_statics/class_static.js | 10 + tests/more_statics/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 34 + tests/name_prop/class.js | 10 + tests/name_prop/function.js | 4 + tests/name_prop/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 47 + tests/namespace/client.js | 3 + tests/namespace/jsfmt.spec.js | 1 + tests/namespace/namespace.js | 17 + tests/new_react/FeedUFI.react.js | 42 + tests/new_react/Mixin.js | 4 + tests/new_react/UFILikeCount.react.js | 23 + .../__snapshots__/jsfmt.spec.js.snap | 845 +++ tests/new_react/bad_default_props.js | 30 + tests/new_react/classes.js | 83 + .../fakelib/__snapshots__/jsfmt.spec.js.snap | 25 + tests/new_react/fakelib/jsfmt.spec.js | 1 + tests/new_react/fakelib/type_aliases.js | 6 + tests/new_react/import-react.js | 19 + tests/new_react/jsfmt.spec.js | 1 + tests/new_react/new_react.js | 32 + tests/new_react/propTypes.js | 21 + tests/new_react/props.js | 27 + tests/new_react/props2.js | 17 + tests/new_react/props3.js | 52 + tests/new_react/props4.js | 26 + tests/new_react/props5.js | 9 + tests/new_react/state.js | 23 + tests/new_react/state2.js | 17 + tests/new_react/state3.js | 18 + tests/new_react/state4.js | 13 + tests/new_react/state5.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 15 + tests/node_haste/client.js | 1 + .../_d3/__snapshots__/jsfmt.spec.js.snap | 6 + tests/node_haste/external/_d3/jsfmt.spec.js | 1 + tests/node_haste/external/_d3/min.js | 0 .../foo/bar/__snapshots__/jsfmt.spec.js.snap | 18 + tests/node_haste/foo/bar/client.js | 7 + tests/node_haste/foo/bar/jsfmt.spec.js | 1 + tests/node_haste/jsfmt.spec.js | 1 + tests/node_haste/md5.js | 1 + .../ws/__snapshots__/jsfmt.spec.js.snap | 6 + tests/node_haste/ws/index.js | 0 tests/node_haste/ws/jsfmt.spec.js | 1 + .../ws/test/__snapshots__/jsfmt.spec.js.snap | 7 + tests/node_haste/ws/test/client.js | 1 + tests/node_haste/ws/test/jsfmt.spec.js | 1 + .../root/__snapshots__/jsfmt.spec.js.snap | 13 + tests/node_modules_with_symlinks/root/foo.js | 4 + .../root/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 7 + .../root/symlink_lib/index.js | 1 + .../root/symlink_lib/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 7 + .../symlink_lib_outside_root/index.js | 1 + .../symlink_lib_outside_root/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 10 + tests/node_modules_without_json/jsfmt.spec.js | 1 + tests/node_modules_without_json/test.js | 3 + .../assert/__snapshots__/jsfmt.spec.js.snap | 14 + tests/node_tests/assert/assert.js | 5 + tests/node_tests/assert/jsfmt.spec.js | 1 + .../basic/__snapshots__/jsfmt.spec.js.snap | 17 + tests/node_tests/basic/bar.js | 1 + tests/node_tests/basic/foo.js | 2 + tests/node_tests/basic/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 17 + tests/node_tests/basic_file/bar.js | 1 + tests/node_tests/basic_file/foo.js | 2 + tests/node_tests/basic_file/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + tests/node_tests/basic_node_modules/foo.js | 2 + .../basic_node_modules/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + .../basic_node_modules_with_path/foo.js | 2 + .../jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + .../bar_lib/__snapshots__/jsfmt.spec.js.snap | 7 + tests/node_tests/basic_package/bar_lib/bar.js | 1 + .../basic_package/bar_lib/jsfmt.spec.js | 1 + tests/node_tests/basic_package/foo.js | 2 + tests/node_tests/basic_package/jsfmt.spec.js | 1 + .../buffer/__snapshots__/jsfmt.spec.js.snap | 76 + tests/node_tests/buffer/buffer.js | 57 + tests/node_tests/buffer/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 200 + tests/node_tests/child_process/exec.js | 16 + tests/node_tests/child_process/execFile.js | 27 + tests/node_tests/child_process/execSync.js | 10 + tests/node_tests/child_process/jsfmt.spec.js | 1 + tests/node_tests/child_process/spawn.js | 30 + .../crypto/__snapshots__/jsfmt.spec.js.snap | 57 + tests/node_tests/crypto/crypto.js | 38 + tests/node_tests/crypto/jsfmt.spec.js | 1 + .../fs/__snapshots__/jsfmt.spec.js.snap | 76 + tests/node_tests/fs/fs.js | 33 + tests/node_tests/fs/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 42 + tests/node_tests/json_file/jsfmt.spec.js | 1 + .../package2/__snapshots__/jsfmt.spec.js.snap | 12 + tests/node_tests/json_file/package2/index.js | 5 + .../json_file/package2/jsfmt.spec.js | 1 + tests/node_tests/json_file/test.js | 23 + .../os/__snapshots__/jsfmt.spec.js.snap | 31 + tests/node_tests/os/jsfmt.spec.js | 1 + tests/node_tests/os/userInfo.js | 15 + .../__snapshots__/jsfmt.spec.js.snap | 17 + tests/node_tests/package_file/bar_lib.js | 1 + .../bar_lib/__snapshots__/jsfmt.spec.js.snap | 7 + tests/node_tests/package_file/bar_lib/bar.js | 1 + .../package_file/bar_lib/jsfmt.spec.js | 1 + tests/node_tests/package_file/foo.js | 2 + tests/node_tests/package_file/jsfmt.spec.js | 1 + .../foo/__snapshots__/jsfmt.spec.js.snap | 9 + .../package_file_node_modules/foo/foo.js | 2 + .../foo/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + tests/node_tests/path_node_modules/foo.js | 2 + .../path_node_modules/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + .../path_node_modules_with_short_main/foo.js | 2 + .../jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + .../path_node_modules_without_main/foo.js | 2 + .../jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 9 + tests/node_tests/path_package/foo.js | 2 + tests/node_tests/path_package/jsfmt.spec.js | 1 + .../stream/__snapshots__/jsfmt.spec.js.snap | 84 + tests/node_tests/stream/jsfmt.spec.js | 1 + tests/node_tests/stream/stream.js | 33 + .../timers/__snapshots__/jsfmt.spec.js.snap | 17 + tests/node_tests/timers/jsfmt.spec.js | 1 + tests/node_tests/timers/timers.js | 7 + .../url/__snapshots__/jsfmt.spec.js.snap | 9 + tests/node_tests/url/jsfmt.spec.js | 1 + tests/node_tests/url/url.js | 2 + .../nullable/__snapshots__/jsfmt.spec.js.snap | 77 + tests/nullable/jsfmt.spec.js | 1 + tests/nullable/maybe.js | 5 + tests/nullable/nullable.js | 18 + tests/nullable/simple_nullable.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 29 + tests/number_constants/jsfmt.spec.js | 1 + tests/number_constants/number_constants.js | 12 + .../__snapshots__/jsfmt.spec.js.snap | 150 + tests/object-method/id.js | 3 + tests/object-method/jsfmt.spec.js | 1 + tests/object-method/subtype.js | 6 + tests/object-method/test.js | 13 + tests/object-method/test2.js | 17 + tests/object-method/test3.js | 18 + .../__snapshots__/jsfmt.spec.js.snap | 27 + tests/object_annot/jsfmt.spec.js | 1 + tests/object_annot/test.js | 8 + .../__snapshots__/jsfmt.spec.js.snap | 401 ++ tests/object_api/a.js | 3 + tests/object_api/b.js | 6 + tests/object_api/c.js | 5 + tests/object_api/jsfmt.spec.js | 1 + tests/object_api/object_assign.js | 12 + tests/object_api/object_create.js | 17 + tests/object_api/object_getprototypeof.js | 11 + tests/object_api/object_keys.js | 32 + tests/object_api/object_missing.js | 7 + tests/object_api/object_prototype.js | 164 + tests/object_assign/A.js | 26 + tests/object_assign/B.js | 17 + .../__snapshots__/jsfmt.spec.js.snap | 166 + tests/object_assign/apply.js | 4 + tests/object_assign/jsfmt.spec.js | 1 + tests/object_assign/non_objects.js | 5 + tests/object_assign/undefined.js | 20 + .../__snapshots__/jsfmt.spec.js.snap | 41 + tests/object_freeze/jsfmt.spec.js | 1 + tests/object_freeze/object_freeze.js | 20 + .../__snapshots__/jsfmt.spec.js.snap | 46 + tests/object_is/jsfmt.spec.js | 1 + tests/object_is/object_is.js | 22 + .../objects/__snapshots__/jsfmt.spec.js.snap | 125 + tests/objects/conversion.js | 19 + tests/objects/jsfmt.spec.js | 1 + tests/objects/objects.js | 18 + tests/objects/unaliased_assign.js | 27 + tests/objmap/__snapshots__/jsfmt.spec.js.snap | 37 + tests/objmap/jsfmt.spec.js | 1 + tests/objmap/objmap.js | 18 + .../optional/__snapshots__/jsfmt.spec.js.snap | 407 ++ tests/optional/client_optional.js | 3 + tests/optional/default.js | 3 + tests/optional/generic.js | 5 + tests/optional/jsfmt.spec.js | 1 + tests/optional/maybe.js | 3 + tests/optional/nullable.js | 49 + tests/optional/optional.js | 12 + tests/optional/optional_param.js | 35 + tests/optional/optional_param2.js | 7 + tests/optional/optional_param3.js | 7 + tests/optional/optional_param4.js | 13 + tests/optional/undefined.js | 9 + tests/optional/undefined2.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 199 + tests/optional_props/jsfmt.spec.js | 1 + tests/optional_props/test.js | 12 + tests/optional_props/test2.js | 13 + tests/optional_props/test3.js | 56 + tests/optional_props/test3_failure.js | 9 + .../overload/__snapshots__/jsfmt.spec.js.snap | 176 + tests/overload/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 23 + tests/overload/lib/jsfmt.spec.js | 1 + tests/overload/lib/lib.js | 4 + tests/overload/overload.js | 51 + tests/overload/test.js | 4 + tests/overload/test2.js | 7 + tests/overload/test3.js | 21 + tests/overload/union.js | 4 + tests/parse/__snapshots__/jsfmt.spec.js.snap | 90 + tests/parse/fail-flow-2.js | 4 + tests/parse/fail-flow.js | 3 + tests/parse/fail.js | 1 + tests/parse/jsfmt.spec.js | 1 + tests/parse/no_parse_error.js | 11 + tests/parse_error_haste/Client.js | 11 + tests/parse_error_haste/NoProvides.js | 9 + tests/parse_error_haste/ParseError.js | 6 + tests/parse_error_haste/Provides.js | 12 + tests/parse_error_haste/Unimported.js | 10 + .../__snapshots__/jsfmt.spec.js.snap | 142 + tests/parse_error_haste/jsfmt.spec.js | 1 + tests/parse_error_node/Client.js | 10 + tests/parse_error_node/Imported.js | 9 + tests/parse_error_node/ParseError.js | 6 + tests/parse_error_node/Unimported.js | 10 + .../__snapshots__/jsfmt.spec.js.snap | 108 + tests/parse_error_node/jsfmt.spec.js | 1 + tests/path/__snapshots__/jsfmt.spec.js.snap | 18 + tests/path/jsfmt.spec.js | 1 + tests/path/while.js | 6 + .../plsummit/__snapshots__/jsfmt.spec.js.snap | 132 + tests/plsummit/arrays.js | 4 + tests/plsummit/export_class.js | 6 + tests/plsummit/generics.js | 4 + tests/plsummit/import_class.js | 3 + tests/plsummit/jsfmt.spec.js | 1 + tests/plsummit/locals.js | 11 + tests/plsummit/objects.js | 13 + tests/poly/__snapshots__/jsfmt.spec.js.snap | 192 + tests/poly/annot.js | 11 + tests/poly/implicit_bounded_instantiation.js | 20 + tests/poly/issue-1029.js | 18 + tests/poly/jsfmt.spec.js | 1 + tests/poly/poly.js | 18 + tests/poly/test.js | 12 + tests/poly_class_export/A.js | 7 + tests/poly_class_export/B.js | 11 + tests/poly_class_export/C.js | 14 + .../__snapshots__/jsfmt.spec.js.snap | 88 + tests/poly_class_export/jsfmt.spec.js | 1 + .../decls/__snapshots__/jsfmt.spec.js.snap | 35 + tests/poly_overload/decls/jsfmt.spec.js | 1 + .../decls/typescript-deferred.js | 16 + .../__snapshots__/jsfmt.spec.js.snap | 278 + tests/predicates-abstract/filter-union.js | 17 + tests/predicates-abstract/filter.js | 13 + tests/predicates-abstract/jsfmt.spec.js | 1 + tests/predicates-abstract/refine.js | 46 + .../sanity-filter-union.js | 17 + tests/predicates-abstract/sanity-filter.js | 22 + tests/predicates-abstract/sanity-refine.js | 44 + .../__snapshots__/jsfmt.spec.js.snap | 473 ++ tests/predicates-declared/function-bind.js | 40 + tests/predicates-declared/function-union.js | 18 + tests/predicates-declared/is-string-decl.js | 18 + tests/predicates-declared/jsfmt.spec.js | 1 + tests/predicates-declared/logical-or.js | 22 + tests/predicates-declared/object-invariant.js | 24 + .../orig-string-tag-check.js | 12 + .../predicates-declared/sanity-conditional.js | 5 + .../sanity-fall-through.js | 13 + .../sanity-invalid-calls.js | 19 + .../sanity-is-string-bug.js | 15 + .../sanity-parameter-mismatch.js | 10 + .../sanity-pred-with-body.js | 15 + .../predicates-declared/sanity-return-type.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 289 + tests/predicates-inferred/jsfmt.spec.js | 1 + .../sanity-multi-params.js | 14 + tests/predicates-inferred/sanity-ordering.js | 18 + .../predicates-inferred/sanity-unbound-var.js | 17 + tests/predicates-inferred/sanity.js | 27 + .../simple-predicate-func-post.js | 21 + .../simple-predicate-func.js | 73 + .../__snapshots__/jsfmt.spec.js.snap | 224 + tests/predicates-parsing/fail-0.js | 5 + tests/predicates-parsing/fail-1.js | 5 + tests/predicates-parsing/fail-2.js | 5 + tests/predicates-parsing/fail-3.js | 7 + tests/predicates-parsing/jsfmt.spec.js | 1 + tests/predicates-parsing/pass.js | 27 + tests/predicates-parsing/unsupported-0.js | 5 + tests/predicates-parsing/unsupported-1.js | 5 + tests/predicates-parsing/unsupported-2.js | 6 + .../private/__snapshots__/jsfmt.spec.js.snap | 36 + tests/private/jsfmt.spec.js | 1 + tests/private/private.js | 14 + .../promises/__snapshots__/jsfmt.spec.js.snap | 428 ++ tests/promises/all.js | 39 + tests/promises/covariance.js | 16 + tests/promises/jsfmt.spec.js | 1 + tests/promises/promise.js | 228 + tests/promises/resolve_global.js | 41 + tests/promises/resolve_void.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 16 + tests/pure_component/jsfmt.spec.js | 1 + tests/pure_component/test.js | 6 + .../__snapshots__/jsfmt.spec.js.snap | 25 + tests/qualified/jsfmt.spec.js | 1 + tests/qualified/qualified.js | 12 + tests/react/ArityError.react.js | 11 + tests/react/__snapshots__/jsfmt.spec.js.snap | 395 ++ .../react/createElementRequiredProp_string.js | 22 + tests/react/createElement_string.js | 11 + tests/react/import_react.js | 7 + tests/react/jsfmt.spec.js | 1 + tests/react/jsx_spread.js | 11 + tests/react/proptype_arrayOf.js | 14 + tests/react/proptype_func.js | 14 + tests/react/proptype_missing.js | 30 + tests/react/proptype_object.js | 13 + tests/react/proptype_objectOf.js | 14 + tests/react/proptype_oneOf.js | 11 + tests/react/proptype_oneOfType.js | 23 + .../__snapshots__/jsfmt.spec.js.snap | 32 + tests/react_functional/jsfmt.spec.js | 1 + tests/react_functional/test.js | 13 + .../__snapshots__/jsfmt.spec.js.snap | 241 + tests/react_modules/createclass-callsite.js | 26 + tests/react_modules/createclass-module.js | 14 + .../es6class-proptypes-callsite.js | 26 + .../es6class-proptypes-module.js | 15 + .../react_modules/es6class-types-callsite.js | 26 + tests/react_modules/es6class-types-module.js | 15 + tests/react_modules/jsfmt.spec.js | 1 + tests/rec/__snapshots__/jsfmt.spec.js.snap | 226 + tests/rec/issue-1228.js | 8 + tests/rec/issue-598.js | 19 + tests/rec/jsfmt.spec.js | 1 + tests/rec/test.js | 16 + tests/rec/test2.js | 30 + tests/rec/test3.js | 16 + tests/rec/test4.js | 1 + tests/rec/test5.js | 10 + tests/recheck-haste/A1.js | 4 + tests/recheck-haste/A3.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 21 + tests/recheck-haste/jsfmt.spec.js | 1 + tests/recheck-haste/tmp1A/A2.js | 4 + .../tmp1A/__snapshots__/jsfmt.spec.js.snap | 10 + tests/recheck-haste/tmp1A/jsfmt.spec.js | 1 + tests/recheck-haste/tmp2A/A3.js | 3 + .../tmp2A/__snapshots__/jsfmt.spec.js.snap | 10 + tests/recheck-haste/tmp2A/jsfmt.spec.js | 1 + .../recheck/__snapshots__/jsfmt.spec.js.snap | 352 ++ tests/recheck/a1.js | 7 + tests/recheck/a2.js | 5 + tests/recheck/a3.js | 5 + tests/recheck/b0.js | 6 + tests/recheck/b1.js | 9 + tests/recheck/b2.js | 3 + tests/recheck/b3.js | 5 + tests/recheck/c1.js | 3 + tests/recheck/c2.js | 7 + tests/recheck/c3.js | 5 + tests/recheck/d1.js | 5 + tests/recheck/d2.js | 4 + tests/recheck/e1.js | 8 + tests/recheck/e2.js | 11 + tests/recheck/f1.js | 10 + tests/recheck/f2.js | 4 + tests/recheck/g1.js | 3 + tests/recheck/g2.js | 7 + tests/recheck/g3.js | 6 + tests/recheck/h1.js | 3 + tests/recheck/h2.js | 3 + tests/recheck/jsfmt.spec.js | 1 + .../tmp1a/__snapshots__/jsfmt.spec.js.snap | 18 + tests/recheck/tmp1a/a1.js | 7 + tests/recheck/tmp1a/jsfmt.spec.js | 1 + .../tmp1b/__snapshots__/jsfmt.spec.js.snap | 26 + tests/recheck/tmp1b/b1.js | 9 + tests/recheck/tmp1b/jsfmt.spec.js | 1 + .../tmp1c/__snapshots__/jsfmt.spec.js.snap | 17 + tests/recheck/tmp1c/c2.js | 7 + tests/recheck/tmp1c/jsfmt.spec.js | 1 + .../tmp1d/__snapshots__/jsfmt.spec.js.snap | 14 + tests/recheck/tmp1d/d1.js | 5 + tests/recheck/tmp1d/jsfmt.spec.js | 1 + .../tmp1e/__snapshots__/jsfmt.spec.js.snap | 30 + tests/recheck/tmp1e/e2.js | 11 + tests/recheck/tmp1e/jsfmt.spec.js | 1 + .../tmp1f/__snapshots__/jsfmt.spec.js.snap | 22 + tests/recheck/tmp1f/f1.js | 10 + tests/recheck/tmp1f/jsfmt.spec.js | 1 + .../tmp1g/__snapshots__/jsfmt.spec.js.snap | 12 + tests/recheck/tmp1g/g1.js | 4 + tests/recheck/tmp1g/jsfmt.spec.js | 1 + .../tmp1h/__snapshots__/jsfmt.spec.js.snap | 10 + tests/recheck/tmp1h/h1.js | 3 + tests/recheck/tmp1h/jsfmt.spec.js | 1 + .../tmp2a/__snapshots__/jsfmt.spec.js.snap | 18 + tests/recheck/tmp2a/a1.js | 7 + tests/recheck/tmp2a/jsfmt.spec.js | 1 + .../tmp2b/__snapshots__/jsfmt.spec.js.snap | 19 + tests/recheck/tmp2b/b0.js | 6 + tests/recheck/tmp2b/jsfmt.spec.js | 1 + .../tmp2c/__snapshots__/jsfmt.spec.js.snap | 12 + tests/recheck/tmp2c/c1.js | 3 + tests/recheck/tmp2c/jsfmt.spec.js | 1 + .../tmp2e/__snapshots__/jsfmt.spec.js.snap | 27 + tests/recheck/tmp2e/e1.js | 8 + tests/recheck/tmp2e/jsfmt.spec.js | 1 + .../tmp2f/__snapshots__/jsfmt.spec.js.snap | 22 + tests/recheck/tmp2f/f1.js | 10 + tests/recheck/tmp2f/jsfmt.spec.js | 1 + .../tmp3e/__snapshots__/jsfmt.spec.js.snap | 58 + tests/recheck/tmp3e/e1.js | 8 + tests/recheck/tmp3e/e2.js | 11 + tests/recheck/tmp3e/jsfmt.spec.js | 1 + .../tmp3f/__snapshots__/jsfmt.spec.js.snap | 22 + tests/recheck/tmp3f/f1.js | 10 + tests/recheck/tmp3f/jsfmt.spec.js | 1 + .../tmp4f/__snapshots__/jsfmt.spec.js.snap | 22 + tests/recheck/tmp4f/f1.js | 10 + tests/recheck/tmp4f/jsfmt.spec.js | 1 + tests/record/__snapshots__/jsfmt.spec.js.snap | 43 + tests/record/jsfmt.spec.js | 1 + tests/record/test.js | 24 + tests/refi/__snapshots__/jsfmt.spec.js.snap | 1196 ++++ tests/refi/bound.js | 64 + tests/refi/heap.js | 237 + tests/refi/jsfmt.spec.js | 1 + tests/refi/lex.js | 36 + tests/refi/local.js | 84 + tests/refi/null_tests.js | 154 + tests/refi/switch.js | 63 + tests/refi/typeof_tests.js | 130 + tests/refi/undef_tests.js | 74 + tests/refi/void_tests.js | 74 + .../__snapshots__/jsfmt.spec.js.snap | 2290 +++++++ tests/refinements/assignment.js | 32 + tests/refinements/ast_node.js | 11 + tests/refinements/bool.js | 46 + tests/refinements/computed_string_literal.js | 19 + tests/refinements/cond_prop.js | 52 + tests/refinements/constants.js | 4 + tests/refinements/eq.js | 22 + tests/refinements/exists.js | 15 + tests/refinements/func_call.js | 12 + tests/refinements/hasOwnProperty.js | 21 + tests/refinements/heap_defassign.js | 84 + tests/refinements/jsfmt.spec.js | 1 + tests/refinements/lib.js | 3 + tests/refinements/missing-property-cond.js | 50 + tests/refinements/mixed.js | 121 + tests/refinements/node1.js | 1 + tests/refinements/not.js | 52 + tests/refinements/null.js | 10 + tests/refinements/number.js | 121 + tests/refinements/property.js | 82 + tests/refinements/refinements.js | 78 + tests/refinements/string.js | 133 + tests/refinements/super_member.js | 26 + tests/refinements/switch.js | 55 + tests/refinements/tagged_union.js | 232 + tests/refinements/tagged_union_import.js | 23 + tests/refinements/typeof.js | 64 + tests/refinements/undef.js | 80 + tests/refinements/union.js | 21 + tests/refinements/void.js | 95 + .../__snapshots__/jsfmt.spec.js.snap | 18 + tests/reflection/jsfmt.spec.js | 1 + tests/reflection/type.js | 8 + tests/regexp/__snapshots__/jsfmt.spec.js.snap | 9 + tests/regexp/jsfmt.spec.js | 1 + tests/regexp/regexp.js | 2 + .../replace/__snapshots__/jsfmt.spec.js.snap | 15 + tests/replace/jsfmt.spec.js | 1 + tests/replace/test.js | 5 + tests/require/B.js | 3 + tests/require/C.js | 1 + tests/require/E.js | 10 + tests/require/ProvidesModuleA.js | 6 + tests/require/ProvidesModuleD.js | 4 + .../require/__snapshots__/jsfmt.spec.js.snap | 168 + tests/require/jsfmt.spec.js | 1 + tests/require/not_builtin_require.js | 4 + tests/require/not_builtin_require2.js | 4 + tests/require/require.js | 35 + tests/requireLazy/A.js | 9 + tests/requireLazy/B.js | 9 + .../__snapshots__/jsfmt.spec.js.snap | 93 + tests/requireLazy/jsfmt.spec.js | 1 + tests/requireLazy/requireLazy.js | 22 + tests/return/__snapshots__/jsfmt.spec.js.snap | 104 + tests/return/function_return.js | 36 + tests/return/jsfmt.spec.js | 1 + tests/return/void.js | 12 + .../__snapshots__/jsfmt.spec.js.snap | 65 + tests/return_new/jsfmt.spec.js | 1 + tests/return_new/test.js | 12 + tests/return_new/test2.js | 11 + tests/seal/__snapshots__/jsfmt.spec.js.snap | 33 + tests/seal/imp.js | 4 + tests/seal/jsfmt.spec.js | 1 + tests/seal/obj_annot.js | 9 + tests/sealed/__snapshots__/jsfmt.spec.js.snap | 88 + tests/sealed/function.js | 9 + tests/sealed/jsfmt.spec.js | 1 + tests/sealed/proto.js | 14 + tests/sealed/sealed.js | 11 + .../__snapshots__/jsfmt.spec.js.snap | 40 + tests/sealed_objects/jsfmt.spec.js | 1 + tests/sealed_objects/test.js | 19 + tests/shape/__snapshots__/jsfmt.spec.js.snap | 26 + tests/shape/jsfmt.spec.js | 1 + tests/shape/test.js | 7 + .../__snapshots__/jsfmt.spec.js.snap | 77 + tests/simple_arrays/array.js | 20 + tests/simple_arrays/array2.js | 8 + tests/simple_arrays/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 117 + tests/singleton/boolean.js | 37 + tests/singleton/jsfmt.spec.js | 1 + tests/singleton/number.js | 23 + tests/singleton/string.js | 7 + tests/spread/__snapshots__/jsfmt.spec.js.snap | 225 + tests/spread/jsfmt.spec.js | 1 + tests/spread/test.js | 30 + tests/spread/test2.js | 9 + tests/spread/test3.js | 17 + tests/spread/test4.js | 4 + tests/spread/test5.js | 25 + tests/spread/test6.js | 20 + tests/spread/test7.js | 8 + .../__snapshots__/jsfmt.spec.js.snap | 7 + tests/static_overload/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 23 + tests/static_overload/lib/jsfmt.spec.js | 1 + tests/static_overload/lib/lib.js | 4 + tests/static_overload/test.js | 1 + .../statics/__snapshots__/jsfmt.spec.js.snap | 47 + tests/statics/class_statics.js | 10 + tests/statics/funstatics.js | 5 + tests/statics/jsfmt.spec.js | 1 + tests/strict/__snapshots__/jsfmt.spec.js.snap | 83 + tests/strict/annot.js | 9 + tests/strict/fun.js | 13 + tests/strict/jsfmt.spec.js | 1 + tests/strict/obj.js | 12 + tests/strict_requires/A.js | 2 + tests/strict_requires/B.js | 2 + tests/strict_requires/C.js | 6 + tests/strict_requires/D.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 50 + tests/strict_requires/jsfmt.spec.js | 1 + .../strings/__snapshots__/jsfmt.spec.js.snap | 42 + tests/strings/jsfmt.spec.js | 1 + tests/strings/strings.js | 21 + .../__snapshots__/jsfmt.spec.js.snap | 146 + tests/structural_subtyping/builtin.js | 12 + tests/structural_subtyping/class.js | 23 + tests/structural_subtyping/jsfmt.spec.js | 1 + tests/structural_subtyping/obj.js | 20 + tests/structural_subtyping/optional.js | 12 + .../suggest/__snapshots__/jsfmt.spec.js.snap | 39 + tests/suggest/jsfmt.spec.js | 1 + tests/suggest/lib.js | 5 + tests/suggest/suggest.js | 10 + tests/super/__snapshots__/jsfmt.spec.js.snap | 263 + tests/super/constructor.js | 154 + tests/super/import.js | 4 + tests/super/jsfmt.spec.js | 1 + tests/super/super.js | 22 + tests/super/test.js | 6 + tests/suppress/A.js | 24 + tests/suppress/B.js | 2 + tests/suppress/C.js | 8 + .../suppress/__snapshots__/jsfmt.spec.js.snap | 86 + tests/suppress/jsfmt.spec.js | 1 + tests/suppress/lib.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 10 + tests/suppress_incremental/jsfmt.spec.js | 1 + tests/suppress_incremental/test.js | 3 + .../__snapshots__/jsfmt.spec.js.snap | 34 + tests/suppress_traces/jsfmt.spec.js | 1 + tests/suppress_traces/traces.js | 15 + tests/switch/__snapshots__/jsfmt.spec.js.snap | 262 + tests/switch/jsfmt.spec.js | 1 + tests/switch/more_switch.js | 26 + tests/switch/switch.js | 30 + tests/switch/switch_default_fallthrough.js | 47 + tests/switch/trailing_cases.js | 80 + tests/symbol/__snapshots__/jsfmt.spec.js.snap | 14 + tests/symbol/jsfmt.spec.js | 1 + tests/symbol/symbol.js | 5 + .../symlink/__snapshots__/jsfmt.spec.js.snap | 25 + tests/symlink/bar.js | 1 + tests/symlink/foo.js | 1 + tests/symlink/jsfmt.spec.js | 1 + tests/symlink/qux.js | 2 + .../__snapshots__/jsfmt.spec.js.snap | 242 + tests/tagged-unions/classes.js | 31 + tests/tagged-unions/interfaces-neg.js | 26 + tests/tagged-unions/interfaces-pos.js | 26 + tests/tagged-unions/jsfmt.spec.js | 1 + tests/tagged-unions/type-decls-neg.js | 30 + tests/tagged-unions/type-decls-pos.js | 30 + tests/taint/__snapshots__/jsfmt.spec.js.snap | 453 ++ tests/taint/adder.js | 31 + tests/taint/any_object.js | 25 + tests/taint/call-object-property.js | 25 + tests/taint/comparator.js | 18 + tests/taint/function.js | 14 + tests/taint/globals.js | 12 + tests/taint/jsfmt.spec.js | 1 + tests/taint/lib.js | 12 + tests/taint/taint1.js | 10 + tests/taint/taint2.js | 10 + tests/taint/taint3.js | 12 + tests/taint/taint4.js | 13 + tests/taint/use-types.js | 32 + .../template/__snapshots__/jsfmt.spec.js.snap | 64 + tests/template/jsfmt.spec.js | 1 + tests/template/template.js | 31 + tests/this/This.js | 60 + tests/this/__snapshots__/jsfmt.spec.js.snap | 184 + tests/this/arrows.js | 27 + tests/this/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 36 + tests/this_ctor/jsfmt.spec.js | 1 + tests/this_ctor/test.js | 16 + .../__snapshots__/jsfmt.spec.js.snap | 474 ++ tests/this_type/class_expr.js | 8 + tests/this_type/contra.js | 54 + tests/this_type/export.js | 12 + tests/this_type/generics.js | 8 + tests/this_type/import.js | 22 + tests/this_type/interface.js | 8 + tests/this_type/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 38 + tests/this_type/lib/decl.js | 19 + tests/this_type/lib/jsfmt.spec.js | 1 + tests/this_type/lib_client.js | 10 + tests/this_type/self.js | 6 + tests/this_type/statics.js | 17 + tests/this_type/test.js | 70 + tests/throw/__snapshots__/jsfmt.spec.js.snap | 46 + tests/throw/jsfmt.spec.js | 1 + tests/throw/test.js | 22 + tests/traces/Traces.js | 20 + tests/traces/Traces2.js | 19 + tests/traces/__snapshots__/jsfmt.spec.js.snap | 78 + tests/traces/jsfmt.spec.js | 1 + tests/traits/__snapshots__/jsfmt.spec.js.snap | 54 + tests/traits/jsfmt.spec.js | 1 + tests/traits/test.js | 20 + tests/traits/test2.js | 2 + tests/try/__snapshots__/jsfmt.spec.js.snap | 567 ++ tests/try/abnormals.js | 15 + tests/try/init.js | 154 + tests/try/jsfmt.spec.js | 1 + tests/try/return.js | 65 + tests/try/test.js | 42 + tests/tuples/__snapshots__/jsfmt.spec.js.snap | 105 + tests/tuples/array.js | 9 + tests/tuples/jsfmt.spec.js | 1 + tests/tuples/optional.js | 6 + tests/tuples/too-few.js | 5 + tests/tuples/tuples.js | 6 + .../__snapshots__/jsfmt.spec.js.snap | 275 + tests/type-at-pos/destructuring.js | 19 + tests/type-at-pos/function_expressions.js | 10 + tests/type-at-pos/generics.js | 26 + tests/type-at-pos/import.js | 5 + tests/type-at-pos/jsfmt.spec.js | 1 + tests/type-at-pos/object_special_cases.js | 8 + tests/type-at-pos/optional.js | 15 + tests/type-at-pos/predicates.js | 6 + tests/type-at-pos/react.js | 2 + tests/type-at-pos/templates.js | 2 + tests/type-at-pos/test.js | 14 + tests/type-at-pos/trycatch.js | 5 + .../__snapshots__/jsfmt.spec.js.snap | 86 + tests/type-destructors/jsfmt.spec.js | 1 + tests/type-destructors/non_maybe_type.js | 12 + tests/type-destructors/property_type.js | 11 + tests/type-destructors/union.js | 4 + .../__snapshots__/jsfmt.spec.js.snap | 5104 +++++++++++++++ tests/type-printer/jsfmt.spec.js | 1 + tests/type-printer/printBinaryExpression.js | 20 + tests/type-printer/types.js | 5045 +++++++++++++++ .../__snapshots__/jsfmt.spec.js.snap | 91 + tests/type_args_nonstrict/jsfmt.spec.js | 1 + tests/type_args_nonstrict/test.js | 72 + .../__snapshots__/jsfmt.spec.js.snap | 90 + tests/type_args_strict/jsfmt.spec.js | 1 + tests/type_args_strict/test.js | 71 + tests/type_only_vars/A.js | 14 + .../__snapshots__/jsfmt.spec.js.snap | 174 + tests/type_only_vars/bad_shadowing.js | 18 + tests/type_only_vars/good_shadowing.js | 20 + tests/type_only_vars/import_type.js | 17 + tests/type_only_vars/jsfmt.spec.js | 1 + tests/type_only_vars/type_alias.js | 13 + .../__snapshots__/jsfmt.spec.js.snap | 84 + tests/type_param_defaults/classes.js | 65 + tests/type_param_defaults/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 132 + tests/type_param_scope/class.js | 8 + tests/type_param_scope/default_params.js | 12 + tests/type_param_scope/jsfmt.spec.js | 1 + tests/type_param_scope/method_shadow.js | 53 + .../__snapshots__/jsfmt.spec.js.snap | 46 + tests/type_param_variance/jsfmt.spec.js | 1 + tests/type_param_variance/promise.js | 27 + .../__snapshots__/jsfmt.spec.js.snap | 43 + tests/type_param_variance2/jsfmt.spec.js | 1 + tests/type_param_variance2/libs/Promise.js | 47 + .../libs/__snapshots__/jsfmt.spec.js.snap | 66 + tests/type_param_variance2/libs/jsfmt.spec.js | 1 + tests/type_param_variance2/promise.js | 24 + .../__snapshots__/jsfmt.spec.js.snap | 79 + tests/typeapp_perf/jsfmt.spec.js | 1 + tests/typeapp_perf/test1.js | 20 + tests/typeapp_perf/test2.js | 20 + .../typecast/__snapshots__/jsfmt.spec.js.snap | 45 + tests/typecast/jsfmt.spec.js | 1 + tests/typecast/typecast.js | 26 + tests/typeof/__snapshots__/jsfmt.spec.js.snap | 101 + tests/typeof/jsfmt.spec.js | 1 + tests/typeof/typeof.js | 82 + tests/unary/__snapshots__/jsfmt.spec.js.snap | 113 + tests/unary/jsfmt.spec.js | 1 + tests/unary/unary.js | 19 + tests/unary/update.js | 38 + .../__snapshots__/jsfmt.spec.js.snap | 59 + tests/unchecked_haste_module_vs_lib/buffer.js | 12 + .../jsfmt.spec.js | 1 + tests/unchecked_haste_module_vs_lib/test.js | 13 + .../__snapshots__/jsfmt.spec.js.snap | 53 + .../jsfmt.spec.js | 1 + tests/unchecked_node_module_vs_lib/test.js | 26 + .../__snapshots__/jsfmt.spec.js.snap | 119 + tests/undefined/issue-518.js | 12 + tests/undefined/jsfmt.spec.js | 1 + tests/undefined/undefined.js | 11 + tests/undefined/undefined2.js | 31 + tests/unicode/UnicodeUtils.js | 34 + .../unicode/__snapshots__/jsfmt.spec.js.snap | 70 + tests/unicode/jsfmt.spec.js | 1 + .../__snapshots__/jsfmt.spec.js.snap | 4057 ++++++++++++ .../gen_big_disjoint_union.js | 4003 ++++++++++++ tests/union-intersection/jsfmt.spec.js | 1 + tests/union-intersection/test.js | 15 + tests/union/__snapshots__/jsfmt.spec.js.snap | 5533 +++++++++++++++++ tests/union/fields.js | 6 + tests/union/fields2.js | 9 + tests/union/issue-17.js | 16 + tests/union/issue-198.js | 10 + tests/union/issue-256.js | 7 + tests/union/issue-323-lib.js | 3 + tests/union/issue-323.js | 3 + tests/union/issue-324.js | 8 + tests/union/issue-325.js | 14 + tests/union/issue-326.js | 4 + tests/union/issue-582.js | 14 + tests/union/issue-963.js | 34 + tests/union/jsfmt.spec.js | 1 + tests/union/test-lib.js | 4 + tests/union/test.js | 18 + tests/union/type-app.js | 14 + tests/union/union.js | 21 + tests/union/yuge.js | 5031 +++++++++++++++ .../__snapshots__/jsfmt.spec.js.snap | 1768 ++++++ tests/union_new/issue-1349.js | 6 + tests/union_new/issue-1371.js | 7 + tests/union_new/issue-1455-helper.js | 3 + tests/union_new/issue-1455.js | 9 + tests/union_new/issue-1462-i.js | 22 + tests/union_new/issue-1462-ii.js | 27 + tests/union_new/issue-1664.js | 26 + tests/union_new/issue-1759.js | 8 + tests/union_new/issue-2232.js | 24 + tests/union_new/issue-815.js | 21 + tests/union_new/issue-824-helper.js | 12 + tests/union_new/issue-824.js | 16 + tests/union_new/jsfmt.spec.js | 1 + .../lib/__snapshots__/jsfmt.spec.js.snap | 69 + tests/union_new/lib/jsfmt.spec.js | 1 + tests/union_new/lib/test23_lib.js | 1 + tests/union_new/lib/test25_lib.js | 21 + tests/union_new/lib/test32_lib.js | 1 + tests/union_new/test1.js | 60 + tests/union_new/test10.js | 72 + tests/union_new/test11.js | 18 + tests/union_new/test12.js | 9 + tests/union_new/test13.js | 11 + tests/union_new/test14.js | 13 + tests/union_new/test15.js | 24 + tests/union_new/test16.js | 18 + tests/union_new/test17.js | 7 + tests/union_new/test18.js | 12 + tests/union_new/test19.js | 12 + tests/union_new/test2.js | 77 + tests/union_new/test20.js | 14 + tests/union_new/test21.js | 21 + tests/union_new/test22.js | 21 + tests/union_new/test23.js | 12 + tests/union_new/test24.js | 30 + tests/union_new/test25.js | 13 + tests/union_new/test26.js | 20 + tests/union_new/test27.js | 20 + tests/union_new/test29.js | 31 + tests/union_new/test3.js | 29 + tests/union_new/test30-helper.js | 6 + tests/union_new/test30.js | 9 + tests/union_new/test31.js | 25 + tests/union_new/test32.js | 9 + tests/union_new/test4.js | 36 + tests/union_new/test5.js | 27 + tests/union_new/test6.js | 25 + tests/union_new/test7.js | 29 + tests/union_new/test8.js | 23 + tests/union_new/test9.js | 16 + .../__snapshots__/jsfmt.spec.js.snap | 95 + tests/unreachable/jsfmt.spec.js | 1 + tests/unreachable/typecheck.js | 23 + tests/unreachable/unreachable.js | 27 + tests/value/__snapshots__/jsfmt.spec.js.snap | 16 + tests/value/jsfmt.spec.js | 1 + tests/value/value.js | 6 + .../__snapshots__/jsfmt.spec.js.snap | 10 + tests/vim_emacs_errors/jsfmt.spec.js | 1 + tests/vim_emacs_errors/test.js | 3 + .../weakmode/__snapshots__/jsfmt.spec.js.snap | 47 + tests/weakmode/jsfmt.spec.js | 1 + tests/weakmode/should_fail_without_weak.js | 10 + tests/weakmode/should_pass_with_weak.js | 10 + tests/while/__snapshots__/jsfmt.spec.js.snap | 73 + tests/while/abnormal.js | 20 + tests/while/jsfmt.spec.js | 1 + tests/while/test.js | 11 + tests/window/__snapshots__/jsfmt.spec.js.snap | 24 + tests/window/jsfmt.spec.js | 1 + tests/window/window1.js | 4 + tests/window/window2.js | 3 + tests/x/XControllerURIBuilder.js | 30 + tests/x/__snapshots__/jsfmt.spec.js.snap | 61 + tests/x/jsfmt.spec.js | 1 + tests/yield/__snapshots__/jsfmt.spec.js.snap | 34 + tests/yield/jsfmt.spec.js | 1 + tests/yield/yield_arrow_error.js | 3 + tests/yield/yield_arrow_error2.js | 3 + tests_config/run_spec.js | 80 + 1873 files changed, 93549 insertions(+), 1 deletion(-) create mode 100644 tests/abnormal/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/abnormal/break-continue.js create mode 100644 tests/abnormal/jsfmt.spec.js create mode 100644 tests/abnormal/return.js create mode 100644 tests/abnormal/toplevel_break.js create mode 100644 tests/abnormal/toplevel_continue.js create mode 100644 tests/abnormal/toplevel_return.js create mode 100644 tests/abnormal/toplevel_throw.js create mode 100644 tests/annot/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/annot/annot.js create mode 100644 tests/annot/any/A.js create mode 100644 tests/annot/any/B.js create mode 100644 tests/annot/any/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/annot/any/jsfmt.spec.js create mode 100644 tests/annot/forward_ref.js create mode 100644 tests/annot/issue-530.js create mode 100644 tests/annot/jsfmt.spec.js create mode 100644 tests/annot/leak.js create mode 100644 tests/annot/other.js create mode 100644 tests/annot/scope.js create mode 100644 tests/annot/test.js create mode 100644 tests/annot2/A.js create mode 100644 tests/annot2/B.js create mode 100644 tests/annot2/T.js create mode 100644 tests/annot2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/annot2/jsfmt.spec.js create mode 100644 tests/any/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/any/any.js create mode 100644 tests/any/anyexportflowfile.js create mode 100644 tests/any/flowfixme.js create mode 100644 tests/any/flowissue.js create mode 100644 tests/any/jsfmt.spec.js create mode 100644 tests/any/nonflowfile.js create mode 100644 tests/any/propagate.js create mode 100644 tests/any/reach.js create mode 100644 tests/arith/Arith.js create mode 100644 tests/arith/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/arith/exponent.js create mode 100644 tests/arith/generic.js create mode 100644 tests/arith/jsfmt.spec.js create mode 100644 tests/arith/mult.js create mode 100644 tests/arith/relational.js create mode 100644 tests/array-filter/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/array-filter/jsfmt.spec.js create mode 100644 tests/array-filter/test.js create mode 100644 tests/array-filter/test2.js create mode 100644 tests/array_spread/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/array_spread/jsfmt.spec.js create mode 100644 tests/array_spread/test.js create mode 100644 tests/arraylib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/arraylib/array_lib.js create mode 100644 tests/arraylib/jsfmt.spec.js create mode 100644 tests/arrays/Arrays.js create mode 100644 tests/arrays/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/arrays/jsfmt.spec.js create mode 100644 tests/arrays/numeric_elem.js create mode 100644 tests/arrows/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/arrows/advanced_arrows.js create mode 100644 tests/arrows/arrows.js create mode 100644 tests/arrows/jsfmt.spec.js create mode 100644 tests/ast_tokens/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/ast_tokens/foo.js create mode 100644 tests/ast_tokens/jsfmt.spec.js create mode 100644 tests/async/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/async/async.js create mode 100644 tests/async/async2.js create mode 100644 tests/async/async3.js create mode 100644 tests/async/async_base_class.js create mode 100644 tests/async/async_parse.js create mode 100644 tests/async/async_promise.js create mode 100644 tests/async/async_return_void.js create mode 100644 tests/async/await_not_in_async.js create mode 100644 tests/async/await_not_in_async2.js create mode 100644 tests/async/await_not_in_async3.js create mode 100644 tests/async/await_parse.js create mode 100644 tests/async/jsfmt.spec.js create mode 100644 tests/async_iteration/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/async_iteration/delegate_yield.js create mode 100644 tests/async_iteration/generator.js create mode 100644 tests/async_iteration/jsfmt.spec.js create mode 100644 tests/async_iteration/return.js create mode 100644 tests/async_iteration/throw.js create mode 100644 tests/autocomplete/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/autocomplete/bar.js create mode 100644 tests/autocomplete/bool.js create mode 100644 tests/autocomplete/customfun.js create mode 100644 tests/autocomplete/foo.js create mode 100644 tests/autocomplete/foo_parse_fail.js create mode 100644 tests/autocomplete/fun.js create mode 100644 tests/autocomplete/function_builtins.js create mode 100644 tests/autocomplete/generics.js create mode 100644 tests/autocomplete/if.js create mode 100644 tests/autocomplete/issue-1368.js create mode 100644 tests/autocomplete/jsfmt.spec.js create mode 100644 tests/autocomplete/jsx1.js create mode 100644 tests/autocomplete/jsx2.js create mode 100644 tests/autocomplete/num.js create mode 100644 tests/autocomplete/object_builtins.js create mode 100644 tests/autocomplete/optional.js create mode 100644 tests/autocomplete/override.js create mode 100644 tests/autocomplete/qux.js create mode 100644 tests/autocomplete/str.js create mode 100644 tests/autocomplete/this.js create mode 100644 tests/autocomplete/typeparams.js create mode 100644 tests/autocomplete/union.js create mode 100644 tests/autocomplete/unknown.js create mode 100644 tests/auxiliary/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/auxiliary/client.js create mode 100644 tests/auxiliary/jsfmt.spec.js create mode 100644 tests/auxiliary/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/auxiliary/lib/jsfmt.spec.js create mode 100644 tests/auxiliary/lib/lib.js create mode 100644 tests/binary/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/binary/in.js create mode 100644 tests/binary/jsfmt.spec.js create mode 100644 tests/binding/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/binding/const.js create mode 100644 tests/binding/jsfmt.spec.js create mode 100644 tests/binding/rebinding.js create mode 100644 tests/binding/scope.js create mode 100644 tests/binding/tdz.js create mode 100644 tests/bom/FormData.js create mode 100644 tests/bom/MutationObserver.js create mode 100644 tests/bom/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/bom/jsfmt.spec.js create mode 100644 tests/bounded_poly/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/bounded_poly/jsfmt.spec.js create mode 100644 tests/bounded_poly/scope.js create mode 100644 tests/bounded_poly/test.js create mode 100644 tests/break/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/break/break.js create mode 100644 tests/break/jsfmt.spec.js create mode 100644 tests/builtin_uses/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/builtin_uses/jsfmt.spec.js create mode 100644 tests/builtin_uses/test.js create mode 100644 tests/builtin_uses/test2.js create mode 100644 tests/builtins/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/builtins/array.js create mode 100644 tests/builtins/genericfoo.js create mode 100644 tests/builtins/jsfmt.spec.js create mode 100644 tests/call_properties/A.js create mode 100644 tests/call_properties/B.js create mode 100644 tests/call_properties/C.js create mode 100644 tests/call_properties/D.js create mode 100644 tests/call_properties/E.js create mode 100644 tests/call_properties/F.js create mode 100644 tests/call_properties/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/call_properties/jsfmt.spec.js create mode 100644 tests/callable/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/callable/jsfmt.spec.js create mode 100644 tests/callable/optional.js create mode 100644 tests/callable/primitives.js create mode 100644 tests/check-contents/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/check-contents/jsfmt.spec.js create mode 100644 tests/check-contents/not_flow.js create mode 100644 tests/check-contents/syntax_error.js create mode 100644 tests/class_fields/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/class_fields/base_class.js create mode 100644 tests/class_fields/derived_class.js create mode 100644 tests/class_fields/generic_class.js create mode 100644 tests/class_fields/jsfmt.spec.js create mode 100644 tests/class_fields/scoping.js create mode 100644 tests/class_munging/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/class_munging/jsfmt.spec.js create mode 100644 tests/class_munging/with_munging.js create mode 100644 tests/class_munging/without_munging.js create mode 100644 tests/class_statics/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/class_statics/jsfmt.spec.js create mode 100644 tests/class_statics/test.js create mode 100644 tests/class_subtyping/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/class_subtyping/jsfmt.spec.js create mode 100644 tests/class_subtyping/test.js create mode 100644 tests/class_subtyping/test2.js create mode 100644 tests/class_subtyping/test3.js create mode 100644 tests/class_subtyping/test4.js create mode 100644 tests/class_type/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/class_type/jsfmt.spec.js create mode 100644 tests/class_type/test.js create mode 100644 tests/class_type/test2.js create mode 100644 tests/classes/A.js create mode 100644 tests/classes/B.js create mode 100644 tests/classes/C.js create mode 100644 tests/classes/D.js create mode 100644 tests/classes/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/classes/class_shapes.js create mode 100644 tests/classes/expr.js create mode 100644 tests/classes/jsfmt.spec.js create mode 100644 tests/classes/loc.js create mode 100644 tests/classes/statics.js create mode 100644 tests/closure/Closure.js create mode 100644 tests/closure/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/closure/cond_havoc.js create mode 100644 tests/closure/const.js create mode 100644 tests/closure/jsfmt.spec.js create mode 100644 tests/commonjs/Abs.js create mode 100644 tests/commonjs/Rel.js create mode 100644 tests/commonjs/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/commonjs/jsfmt.spec.js create mode 100644 tests/computed_props/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/computed_props/jsfmt.spec.js create mode 100644 tests/computed_props/test.js create mode 100644 tests/computed_props/test2.js create mode 100644 tests/computed_props/test3.js create mode 100644 tests/computed_props/test4.js create mode 100644 tests/computed_props/test5.js create mode 100644 tests/computed_props/test6.js create mode 100644 tests/computed_props/test7.js create mode 100644 tests/conditional/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/conditional/conditional.js create mode 100644 tests/conditional/jsfmt.spec.js create mode 100644 tests/config_all/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_all/jsfmt.spec.js create mode 100644 tests/config_all/no_at_flow.js create mode 100644 tests/config_all_false/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_all_false/jsfmt.spec.js create mode 100644 tests/config_all_false/no_at_flow.js create mode 100644 tests/config_all_weak/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_all_weak/jsfmt.spec.js create mode 100644 tests/config_all_weak/no_at_flow.js create mode 100644 tests/config_file_extensions/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_file_extensions/jsfmt.spec.js create mode 100644 tests/config_file_extensions/test.js create mode 100644 tests/config_ignore/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_ignore/dir/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_ignore/dir/foo.js create mode 100644 tests/config_ignore/dir/jsfmt.spec.js create mode 100644 tests/config_ignore/foo.js create mode 100644 tests/config_ignore/jsfmt.spec.js create mode 100644 tests/config_module_name_mapper_PROJECT_ROOT-1.0/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_name_mapper_PROJECT_ROOT-1.0/jsfmt.spec.js create mode 100644 tests/config_module_name_mapper_PROJECT_ROOT-1.0/main.js create mode 100644 tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/jsfmt.spec.js create mode 100644 tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/testmodule.js create mode 100644 tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_name_mapper_filetype/jsfmt.spec.js create mode 100644 tests/config_module_name_mapper_filetype/test.js create mode 100644 tests/config_module_name_rewrite_haste/A.js create mode 100644 tests/config_module_name_rewrite_haste/Exists.js create mode 100644 tests/config_module_name_rewrite_haste/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_name_rewrite_haste/jsfmt.spec.js create mode 100644 tests/config_module_name_rewrite_node/A.js create mode 100644 tests/config_module_name_rewrite_node/Exists.js create mode 100644 tests/config_module_name_rewrite_node/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_name_rewrite_node/jsfmt.spec.js create mode 100644 tests/config_module_system_node_resolve_dirname/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/index.js create mode 100644 tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/jsfmt.spec.js create mode 100644 tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/index.js create mode 100644 tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/jsfmt.spec.js create mode 100644 tests/config_module_system_node_resolve_dirname/jsfmt.spec.js create mode 100644 tests/config_module_system_node_resolve_dirname/subdir/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/index.js create mode 100644 tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/jsfmt.spec.js create mode 100644 tests/config_module_system_node_resolve_dirname/subdir/jsfmt.spec.js create mode 100644 tests/config_module_system_node_resolve_dirname/subdir/sublevel.js create mode 100644 tests/config_module_system_node_resolve_dirname/toplevel.js create mode 100644 tests/config_munging_underscores/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_munging_underscores/chain.js create mode 100644 tests/config_munging_underscores/commonjs_export.js create mode 100644 tests/config_munging_underscores/commonjs_import.js create mode 100644 tests/config_munging_underscores/jsfmt.spec.js create mode 100644 tests/config_munging_underscores2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/config_munging_underscores2/chain.js create mode 100644 tests/config_munging_underscores2/jsfmt.spec.js create mode 100644 tests/const_params/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/const_params/jsfmt.spec.js create mode 100644 tests/const_params/test.js create mode 100644 tests/constructor/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/constructor/constructor.js create mode 100644 tests/constructor/jsfmt.spec.js create mode 100644 tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/constructor_annots/constructors.js create mode 100644 tests/constructor_annots/jsfmt.spec.js create mode 100644 tests/constructor_annots/test.js create mode 100644 tests/contents/ignore/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/contents/ignore/dummy.js create mode 100644 tests/contents/ignore/jsfmt.spec.js create mode 100644 tests/contents/ignore/test.js create mode 100644 tests/contents/no_flow/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/contents/no_flow/dummy.js create mode 100644 tests/contents/no_flow/jsfmt.spec.js create mode 100644 tests/contents/no_flow/test.js create mode 100644 tests/core_tests/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/core_tests/boolean.js create mode 100644 tests/core_tests/jsfmt.spec.js create mode 100644 tests/core_tests/map.js create mode 100644 tests/core_tests/regexp.js create mode 100644 tests/core_tests/weakset.js create mode 100644 tests/covariance/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/covariance/jsfmt.spec.js create mode 100644 tests/covariance/test.js create mode 100644 tests/coverage/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/coverage/crash.js create mode 100644 tests/coverage/declare_module.js create mode 100644 tests/coverage/jsfmt.spec.js create mode 100644 tests/coverage/no_pragma.js create mode 100644 tests/coverage/non-termination.js create mode 100644 tests/cycle/A.js create mode 100644 tests/cycle/B.js create mode 100644 tests/cycle/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/cycle/jsfmt.spec.js create mode 100644 tests/date/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/date/date.js create mode 100644 tests/date/jsfmt.spec.js create mode 100644 tests/declaration_files_haste/ExplicitProvidesModuleDifferentName.js create mode 100644 tests/declaration_files_haste/ExplicitProvidesModuleSameName.js create mode 100644 tests/declaration_files_haste/ImplicitProvidesModule.js create mode 100644 tests/declaration_files_haste/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_haste/external/_d3/jsfmt.spec.js create mode 100644 tests/declaration_files_haste/external/_d3/min.js create mode 100644 tests/declaration_files_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_haste/foo/bar/jsfmt.spec.js create mode 100644 tests/declaration_files_haste/foo/bar/nested_test.js create mode 100644 tests/declaration_files_haste/jsfmt.spec.js create mode 100644 tests/declaration_files_haste/md5.js create mode 100644 tests/declaration_files_haste/test.js create mode 100644 tests/declaration_files_haste/ws/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_haste/ws/index.js create mode 100644 tests/declaration_files_haste/ws/jsfmt.spec.js create mode 100644 tests/declaration_files_haste/ws/test/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_haste/ws/test/client.js create mode 100644 tests/declaration_files_haste/ws/test/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_haste/A.js create mode 100644 tests/declaration_files_incremental_haste/ExplicitProvidesModuleDifferentName.js create mode 100644 tests/declaration_files_incremental_haste/ExplicitProvidesModuleSameName.js create mode 100644 tests/declaration_files_incremental_haste/ImplicitProvidesModule.js create mode 100644 tests/declaration_files_incremental_haste/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_incremental_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_incremental_haste/external/_d3/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_haste/external/_d3/min.js create mode 100644 tests/declaration_files_incremental_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_incremental_haste/foo/bar/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_haste/foo/bar/nested_test.js create mode 100644 tests/declaration_files_incremental_haste/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_haste/md5.js create mode 100644 tests/declaration_files_incremental_haste/test.js create mode 100644 tests/declaration_files_incremental_haste/ws/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_incremental_haste/ws/index.js create mode 100644 tests/declaration_files_incremental_haste/ws/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_haste/ws/test/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_incremental_haste/ws/test/client.js create mode 100644 tests/declaration_files_incremental_haste/ws/test/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_node/A.js create mode 100644 tests/declaration_files_incremental_node/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_incremental_node/jsfmt.spec.js create mode 100644 tests/declaration_files_incremental_node/test_absolute.js create mode 100644 tests/declaration_files_incremental_node/test_relative.js create mode 100644 tests/declaration_files_node/A.js create mode 100644 tests/declaration_files_node/CJS.js create mode 100644 tests/declaration_files_node/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declaration_files_node/jsfmt.spec.js create mode 100644 tests/declaration_files_node/test_absolute.js create mode 100644 tests/declaration_files_node/test_relative.js create mode 100644 tests/declare_class/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_class/declare_class.js create mode 100644 tests/declare_class/jsfmt.spec.js create mode 100644 tests/declare_class/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_class/lib/jsfmt.spec.js create mode 100644 tests/declare_class/lib/test.js create mode 100644 tests/declare_export/B.js create mode 100644 tests/declare_export/C.js create mode 100644 tests/declare_export/CommonJS_Clobbering_Class.js create mode 100644 tests/declare_export/CommonJS_Clobbering_Lit.js create mode 100644 tests/declare_export/CommonJS_Named.js create mode 100644 tests/declare_export/ES6_DefaultAndNamed.js create mode 100644 tests/declare_export/ES6_Default_AnonFunction1.js create mode 100644 tests/declare_export/ES6_Default_AnonFunction2.js create mode 100644 tests/declare_export/ES6_Default_NamedClass1.js create mode 100644 tests/declare_export/ES6_Default_NamedClass2.js create mode 100644 tests/declare_export/ES6_Default_NamedFunction1.js create mode 100644 tests/declare_export/ES6_Default_NamedFunction2.js create mode 100644 tests/declare_export/ES6_ExportAllFromMulti.js create mode 100644 tests/declare_export/ES6_ExportAllFrom_Intermediary1.js create mode 100644 tests/declare_export/ES6_ExportAllFrom_Intermediary2.js create mode 100644 tests/declare_export/ES6_ExportAllFrom_Source1.js create mode 100644 tests/declare_export/ES6_ExportAllFrom_Source2.js create mode 100644 tests/declare_export/ES6_ExportFrom_Intermediary1.js create mode 100644 tests/declare_export/ES6_ExportFrom_Intermediary2.js create mode 100644 tests/declare_export/ES6_ExportFrom_Source1.js create mode 100644 tests/declare_export/ES6_ExportFrom_Source2.js create mode 100644 tests/declare_export/ES6_Named1.js create mode 100644 tests/declare_export/ES6_Named2.js create mode 100644 tests/declare_export/ProvidesModuleA.js create mode 100644 tests/declare_export/ProvidesModuleCJSDefault.js create mode 100644 tests/declare_export/ProvidesModuleD.js create mode 100644 tests/declare_export/ProvidesModuleES6Default.js create mode 100644 tests/declare_export/SideEffects.js create mode 100644 tests/declare_export/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_export/es6modules.js create mode 100644 tests/declare_export/jsfmt.spec.js create mode 100644 tests/declare_fun/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_fun/jsfmt.spec.js create mode 100644 tests/declare_fun/test.js create mode 100644 tests/declare_module_exports/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_module_exports/flow-typed/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_module_exports/flow-typed/jsfmt.spec.js create mode 100644 tests/declare_module_exports/flow-typed/libs.js create mode 100644 tests/declare_module_exports/jsfmt.spec.js create mode 100644 tests/declare_module_exports/main.js create mode 100644 tests/declare_type/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_type/import_declare_type.js create mode 100644 tests/declare_type/jsfmt.spec.js create mode 100644 tests/declare_type/lib/DeclareModule_TypeAlias.js create mode 100644 tests/declare_type/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/declare_type/lib/declare_type_exports.js create mode 100644 tests/declare_type/lib/jsfmt.spec.js create mode 100644 tests/def_site_variance/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/def_site_variance/jsfmt.spec.js create mode 100644 tests/def_site_variance/test.js create mode 100644 tests/demo/1/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/demo/1/f.js create mode 100644 tests/demo/1/jsfmt.spec.js create mode 100644 tests/demo/2/A.js create mode 100644 tests/demo/2/B.js create mode 100644 tests/demo/2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/demo/2/jsfmt.spec.js create mode 100644 tests/deps/A.js create mode 100644 tests/deps/B.js create mode 100644 tests/deps/C.js create mode 100644 tests/deps/D.js create mode 100644 tests/deps/E.js create mode 100644 tests/deps/F.js create mode 100644 tests/deps/G.js create mode 100644 tests/deps/H.js create mode 100644 tests/deps/I.js create mode 100644 tests/deps/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/deps/jsfmt.spec.js create mode 100644 tests/destructuring/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/destructuring/array_rest.js create mode 100644 tests/destructuring/computed.js create mode 100644 tests/destructuring/defaults.js create mode 100644 tests/destructuring/destructuring.js create mode 100644 tests/destructuring/destructuring_init.js create mode 100644 tests/destructuring/destructuring_param.js create mode 100644 tests/destructuring/eager.js create mode 100644 tests/destructuring/jsfmt.spec.js create mode 100644 tests/destructuring/poly.js create mode 100644 tests/destructuring/rec.js create mode 100644 tests/destructuring/string_lit.js create mode 100644 tests/destructuring/unannotated.js create mode 100644 tests/dictionary/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/dictionary/any.js create mode 100644 tests/dictionary/compatible.js create mode 100644 tests/dictionary/dictionary.js create mode 100644 tests/dictionary/incompatible.js create mode 100644 tests/dictionary/issue-1745.js create mode 100644 tests/dictionary/jsfmt.spec.js create mode 100644 tests/dictionary/test.js create mode 100644 tests/dictionary/test_client.js create mode 100644 tests/disjoint-union-perf/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/disjoint-union-perf/ast.js create mode 100644 tests/disjoint-union-perf/emit.js create mode 100644 tests/disjoint-union-perf/jsAst.js create mode 100644 tests/disjoint-union-perf/jsfmt.spec.js create mode 100644 tests/docblock_flow/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/docblock_flow/jsfmt.spec.js create mode 100644 tests/docblock_flow/license_with_flow.js create mode 100644 tests/docblock_flow/max_header_tokens.js create mode 100644 tests/docblock_flow/multiple_flows_1.js create mode 100644 tests/docblock_flow/multiple_flows_2.js create mode 100644 tests/docblock_flow/multiple_providesModule_1.js create mode 100644 tests/docblock_flow/multiple_providesModule_2.js create mode 100644 tests/docblock_flow/use_strict_with_flow.js create mode 100644 tests/docblock_flow/with_flow.js create mode 100644 tests/docblock_flow/without_flow.js create mode 100644 tests/dom/CanvasRenderingContext2D.js create mode 100644 tests/dom/CustomEvent.js create mode 100644 tests/dom/Document.js create mode 100644 tests/dom/Element.js create mode 100644 tests/dom/HTMLCanvasElement.js create mode 100644 tests/dom/HTMLElement.js create mode 100644 tests/dom/HTMLInputElement.js create mode 100644 tests/dom/URL.js create mode 100644 tests/dom/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/dom/eventtarget.js create mode 100644 tests/dom/jsfmt.spec.js create mode 100644 tests/dom/path2d.js create mode 100644 tests/dom/registerElement.js create mode 100644 tests/dom/traversal.js create mode 100644 tests/dump-types/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/dump-types/import.js create mode 100644 tests/dump-types/jsfmt.spec.js create mode 100644 tests/dump-types/test.js create mode 100644 tests/duplicate_methods/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/duplicate_methods/jsfmt.spec.js create mode 100644 tests/duplicate_methods/test.js create mode 100644 tests/encaps/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/encaps/encaps.js create mode 100644 tests/encaps/jsfmt.spec.js create mode 100644 tests/enumerror/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/enumerror/enumerror.js create mode 100644 tests/enumerror/jsfmt.spec.js create mode 100644 tests/equals/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/equals/equals.js create mode 100644 tests/equals/jsfmt.spec.js create mode 100644 tests/error_messages/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/error_messages/errors.js create mode 100644 tests/error_messages/jsfmt.spec.js create mode 100644 tests/es6modules/B.js create mode 100644 tests/es6modules/C.js create mode 100644 tests/es6modules/CommonJS_Clobbering_Class.js create mode 100644 tests/es6modules/CommonJS_Clobbering_Frozen.js create mode 100644 tests/es6modules/CommonJS_Clobbering_Lit.js create mode 100644 tests/es6modules/CommonJS_Named.js create mode 100644 tests/es6modules/ES6_DefaultAndNamed.js create mode 100644 tests/es6modules/ES6_Default_AnonClass1.js create mode 100644 tests/es6modules/ES6_Default_AnonClass2.js create mode 100644 tests/es6modules/ES6_Default_AnonFunction1.js create mode 100644 tests/es6modules/ES6_Default_AnonFunction2.js create mode 100644 tests/es6modules/ES6_Default_NamedClass1.js create mode 100644 tests/es6modules/ES6_Default_NamedClass2.js create mode 100644 tests/es6modules/ES6_Default_NamedFunction1.js create mode 100644 tests/es6modules/ES6_Default_NamedFunction2.js create mode 100644 tests/es6modules/ES6_ExportAllFromMulti.js create mode 100644 tests/es6modules/ES6_ExportAllFrom_Intermediary1.js create mode 100644 tests/es6modules/ES6_ExportAllFrom_Intermediary2.js create mode 100644 tests/es6modules/ES6_ExportAllFrom_Source1.js create mode 100644 tests/es6modules/ES6_ExportAllFrom_Source2.js create mode 100644 tests/es6modules/ES6_ExportFrom_Intermediary1.js create mode 100644 tests/es6modules/ES6_ExportFrom_Intermediary2.js create mode 100644 tests/es6modules/ES6_ExportFrom_Source1.js create mode 100644 tests/es6modules/ES6_ExportFrom_Source2.js create mode 100644 tests/es6modules/ES6_Named1.js create mode 100644 tests/es6modules/ES6_Named2.js create mode 100644 tests/es6modules/ExportType.js create mode 100644 tests/es6modules/ProvidesModuleA.js create mode 100644 tests/es6modules/ProvidesModuleCJSDefault.js create mode 100644 tests/es6modules/ProvidesModuleD.js create mode 100644 tests/es6modules/ProvidesModuleES6Default.js create mode 100644 tests/es6modules/SideEffects.js create mode 100644 tests/es6modules/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/es6modules/es6modules.js create mode 100644 tests/es6modules/jsfmt.spec.js create mode 100644 tests/es6modules/test_imports_are_frozen.js create mode 100644 tests/es_declare_module/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/es_declare_module/es_declare_module.js create mode 100644 tests/es_declare_module/flow-typed/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/es_declare_module/flow-typed/declares.js create mode 100644 tests/es_declare_module/flow-typed/jsfmt.spec.js create mode 100644 tests/es_declare_module/jsfmt.spec.js create mode 100644 tests/esproposal_class_instance_fields.ignore/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_class_instance_fields.ignore/jsfmt.spec.js create mode 100644 tests/esproposal_class_instance_fields.ignore/test.js create mode 100644 tests/esproposal_class_instance_fields.warn/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_class_instance_fields.warn/jsfmt.spec.js create mode 100644 tests/esproposal_class_instance_fields.warn/test.js create mode 100644 tests/esproposal_class_static_fields.ignore/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_class_static_fields.ignore/jsfmt.spec.js create mode 100644 tests/esproposal_class_static_fields.ignore/test.js create mode 100644 tests/esproposal_class_static_fields.warn/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_class_static_fields.warn/jsfmt.spec.js create mode 100644 tests/esproposal_class_static_fields.warn/test.js create mode 100644 tests/esproposal_decorators.ignore/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_decorators.ignore/jsfmt.spec.js create mode 100644 tests/esproposal_decorators.ignore/test.js create mode 100644 tests/esproposal_decorators.warn/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_decorators.warn/jsfmt.spec.js create mode 100644 tests/esproposal_decorators.warn/test.js create mode 100644 tests/esproposal_export_star_as.enable/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_export_star_as.enable/dest.js create mode 100644 tests/esproposal_export_star_as.enable/jsfmt.spec.js create mode 100644 tests/esproposal_export_star_as.enable/source.js create mode 100644 tests/esproposal_export_star_as.enable/test.js create mode 100644 tests/esproposal_export_star_as.ignore/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_export_star_as.ignore/dest.js create mode 100644 tests/esproposal_export_star_as.ignore/jsfmt.spec.js create mode 100644 tests/esproposal_export_star_as.ignore/source.js create mode 100644 tests/esproposal_export_star_as.ignore/test.js create mode 100644 tests/esproposal_export_star_as.warn/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/esproposal_export_star_as.warn/jsfmt.spec.js create mode 100644 tests/esproposal_export_star_as.warn/test.js create mode 100644 tests/export_default/P.js create mode 100644 tests/export_default/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/export_default/jsfmt.spec.js create mode 100644 tests/export_default/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/export_default/lib/jsfmt.spec.js create mode 100644 tests/export_default/lib/lib.js create mode 100644 tests/export_default/test.js create mode 100644 tests/export_type/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/export_type/cjs_with_types.js create mode 100644 tests/export_type/importer.js create mode 100644 tests/export_type/jsfmt.spec.js create mode 100644 tests/export_type/types_only.js create mode 100644 tests/export_type/types_only2.js create mode 100644 tests/extensions/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/extensions/foo.js create mode 100644 tests/extensions/jsfmt.spec.js create mode 100644 tests/facebook_fbt_none/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/facebook_fbt_none/jsfmt.spec.js create mode 100644 tests/facebook_fbt_none/main.js create mode 100644 tests/facebook_fbt_some/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/facebook_fbt_some/flow-typed/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/facebook_fbt_some/flow-typed/fbt.js create mode 100644 tests/facebook_fbt_some/flow-typed/jsfmt.spec.js create mode 100644 tests/facebook_fbt_some/jsfmt.spec.js create mode 100644 tests/facebook_fbt_some/main.js create mode 100644 tests/facebookisms/Bar.js create mode 100644 tests/facebookisms/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/facebookisms/copyProperties.js create mode 100644 tests/facebookisms/invariant.js create mode 100644 tests/facebookisms/jsfmt.spec.js create mode 100644 tests/facebookisms/lib.js create mode 100644 tests/facebookisms/mergeInto.js create mode 100644 tests/facebookisms/test.js create mode 100644 tests/fetch/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/fetch/fetch.js create mode 100644 tests/fetch/headers.js create mode 100644 tests/fetch/jsfmt.spec.js create mode 100644 tests/fetch/request.js create mode 100644 tests/fetch/response.js create mode 100644 tests/fetch/urlsearchparams.js create mode 100644 tests/find-module/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/find-module/jsfmt.spec.js create mode 100644 tests/find-module/req.js create mode 100644 tests/find-module/test.js create mode 100644 tests/find-refs/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/find-refs/jsfmt.spec.js create mode 100644 tests/find-refs/locals.js create mode 100644 tests/fixpoint/Fun.js create mode 100644 tests/fixpoint/Ycombinator.js create mode 100644 tests/fixpoint/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/fixpoint/jsfmt.spec.js create mode 100644 tests/flow_ast.template_strings/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/flow_ast.template_strings/foo.js create mode 100644 tests/flow_ast.template_strings/jsfmt.spec.js create mode 100644 tests/for/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/for/abnormal.js create mode 100644 tests/for/abnormal_for_in.js create mode 100644 tests/for/abnormal_for_of.js create mode 100644 tests/for/jsfmt.spec.js create mode 100644 tests/forof/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/forof/forof.js create mode 100644 tests/forof/jsfmt.spec.js create mode 100644 tests/function/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/function/apply.js create mode 100644 tests/function/bind.js create mode 100644 tests/function/call.js create mode 100644 tests/function/function.js create mode 100644 tests/function/jsfmt.spec.js create mode 100644 tests/function/rest.js create mode 100644 tests/funrec/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/funrec/funrec.js create mode 100644 tests/funrec/jsfmt.spec.js create mode 100644 tests/generators/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/generators/class.js create mode 100644 tests/generators/class_failure.js create mode 100644 tests/generators/generators.js create mode 100644 tests/generators/jsfmt.spec.js create mode 100644 tests/generators/return.js create mode 100644 tests/generators/throw.js create mode 100644 tests/generators/variance.js create mode 100644 tests/generics/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/generics/generics.js create mode 100644 tests/generics/jsfmt.spec.js create mode 100644 tests/geolocation/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/geolocation/a.js create mode 100644 tests/geolocation/jsfmt.spec.js create mode 100644 tests/get-def/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/get-def/example.js create mode 100644 tests/get-def/helpers/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/get-def/helpers/exports_default.js create mode 100644 tests/get-def/helpers/exports_named.js create mode 100644 tests/get-def/helpers/jsfmt.spec.js create mode 100644 tests/get-def/imports.js create mode 100644 tests/get-def/jsfmt.spec.js create mode 100644 tests/get-def/library.js create mode 100644 tests/get-def2/Parent.js create mode 100644 tests/get-def2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/get-def2/jsfmt.spec.js create mode 100644 tests/get-def2/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/get-def2/lib/jsfmt.spec.js create mode 100644 tests/get-def2/lib/jsx.js create mode 100644 tests/get-def2/main.js create mode 100644 tests/get-def2/override.js create mode 100644 tests/get-def2/react.js create mode 100644 tests/get-def2/types.js create mode 100644 tests/get-imports-and-importers/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/get-imports-and-importers/a.js create mode 100644 tests/get-imports-and-importers/b.js create mode 100644 tests/get-imports-and-importers/c.js create mode 100644 tests/get-imports-and-importers/jsfmt.spec.js create mode 100644 tests/getters_and_setters_disabled/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/getters_and_setters_disabled/getters_and_setters.js create mode 100644 tests/getters_and_setters_disabled/jsfmt.spec.js create mode 100644 tests/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/getters_and_setters_enabled/class.js create mode 100644 tests/getters_and_setters_enabled/jsfmt.spec.js create mode 100644 tests/getters_and_setters_enabled/object.js create mode 100644 tests/getters_and_setters_enabled/react.js create mode 100644 tests/getters_and_setters_enabled/variance.js create mode 100644 tests/haste_cycle/API.js create mode 100644 tests/haste_cycle/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/haste_cycle/jsfmt.spec.js create mode 100644 tests/haste_cycle/models/OpenGraphAction.js create mode 100644 tests/haste_cycle/models/OpenGraphObject.js create mode 100644 tests/haste_cycle/models/OpenGraphValueContainer.js create mode 100644 tests/haste_cycle/models/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/haste_cycle/models/jsfmt.spec.js create mode 100644 tests/haste_dupe/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/haste_dupe/dupe1.js create mode 100644 tests/haste_dupe/dupe2.js create mode 100644 tests/haste_dupe/jsfmt.spec.js create mode 100644 tests/haste_dupe/requires_dupe.js create mode 100644 tests/ignore_package/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/ignore_package/foo.js create mode 100644 tests/ignore_package/jsfmt.spec.js create mode 100644 tests/immutable_methods/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/immutable_methods/jsfmt.spec.js create mode 100644 tests/immutable_methods/test.js create mode 100644 tests/import_type/ExportCJSDefault_Class.js create mode 100644 tests/import_type/ExportCJSNamed_Class.js create mode 100644 tests/import_type/ExportDefault_Class.js create mode 100644 tests/import_type/ExportNamed_Alias.js create mode 100644 tests/import_type/ExportNamed_Class.js create mode 100644 tests/import_type/ExportsANumber.js create mode 100644 tests/import_type/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/import_type/import_type.js create mode 100644 tests/import_type/issue-359.js create mode 100644 tests/import_type/jsfmt.spec.js create mode 100644 tests/import_typeof/ExportCJSDefault_Class.js create mode 100644 tests/import_typeof/ExportCJSDefault_Number.js create mode 100644 tests/import_typeof/ExportCJSNamed_Class.js create mode 100644 tests/import_typeof/ExportCJSNamed_Number.js create mode 100644 tests/import_typeof/ExportDefault_Class.js create mode 100644 tests/import_typeof/ExportDefault_Number.js create mode 100644 tests/import_typeof/ExportNamed_Alias.js create mode 100644 tests/import_typeof/ExportNamed_Class.js create mode 100644 tests/import_typeof/ExportNamed_Multi.js create mode 100644 tests/import_typeof/ExportNamed_Number.js create mode 100644 tests/import_typeof/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/import_typeof/import_typeof.js create mode 100644 tests/import_typeof/jsfmt.spec.js create mode 100644 tests/include/foo/batman/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/include/foo/batman/baz.js create mode 100644 tests/include/foo/batman/jsfmt.spec.js create mode 100644 tests/include/included/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/include/included/jsfmt.spec.js create mode 100644 tests/include/included/test.js create mode 100644 tests/incremental/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental/a.js create mode 100644 tests/incremental/b.js create mode 100644 tests/incremental/dup_a.js create mode 100644 tests/incremental/jsfmt.spec.js create mode 100644 tests/incremental_basic/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_basic/a.js create mode 100644 tests/incremental_basic/b.js create mode 100644 tests/incremental_basic/c.js create mode 100644 tests/incremental_basic/jsfmt.spec.js create mode 100644 tests/incremental_basic/tmp1/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_basic/tmp1/b.js create mode 100644 tests/incremental_basic/tmp1/jsfmt.spec.js create mode 100644 tests/incremental_basic/tmp2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_basic/tmp2/a.js create mode 100644 tests/incremental_basic/tmp2/jsfmt.spec.js create mode 100644 tests/incremental_basic/tmp3/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_basic/tmp3/b.js create mode 100644 tests/incremental_basic/tmp3/jsfmt.spec.js create mode 100644 tests/incremental_cycle/A.js create mode 100644 tests/incremental_cycle/B.js create mode 100644 tests/incremental_cycle/C.js create mode 100644 tests/incremental_cycle/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_cycle/jsfmt.spec.js create mode 100644 tests/incremental_cycle/tmp1/B.js create mode 100644 tests/incremental_cycle/tmp1/C.js create mode 100644 tests/incremental_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_cycle/tmp1/jsfmt.spec.js create mode 100644 tests/incremental_cycle/tmp2/B.js create mode 100644 tests/incremental_cycle/tmp2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_cycle/tmp2/jsfmt.spec.js create mode 100644 tests/incremental_cycle/tmp3/B.js create mode 100644 tests/incremental_cycle/tmp3/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_cycle/tmp3/jsfmt.spec.js create mode 100644 tests/incremental_delete/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_delete/a.js create mode 100644 tests/incremental_delete/b.js create mode 100644 tests/incremental_delete/c.js create mode 100644 tests/incremental_delete/dupe1.js create mode 100644 tests/incremental_delete/dupe2.js create mode 100644 tests/incremental_delete/jsfmt.spec.js create mode 100644 tests/incremental_delete/requires_dupe.js create mode 100644 tests/incremental_delete/requires_unchecked.js create mode 100644 tests/incremental_delete/unchecked.js create mode 100644 tests/incremental_duplicate_delete/A.js create mode 100644 tests/incremental_duplicate_delete/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_duplicate_delete/jsfmt.spec.js create mode 100644 tests/incremental_json/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_json/jsfmt.spec.js create mode 100644 tests/incremental_json/test.js create mode 100644 tests/incremental_mixed_naming_cycle/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_mixed_naming_cycle/a.js create mode 100644 tests/incremental_mixed_naming_cycle/b.js create mode 100644 tests/incremental_mixed_naming_cycle/c.js create mode 100644 tests/incremental_mixed_naming_cycle/d.js create mode 100644 tests/incremental_mixed_naming_cycle/jsfmt.spec.js create mode 100644 tests/incremental_mixed_naming_cycle/root.js create mode 100644 tests/incremental_mixed_naming_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_mixed_naming_cycle/tmp1/jsfmt.spec.js create mode 100644 tests/incremental_mixed_naming_cycle/tmp1/root.js create mode 100644 tests/incremental_non_flow_move/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_non_flow_move/foo.js create mode 100644 tests/incremental_non_flow_move/jsfmt.spec.js create mode 100644 tests/incremental_non_flow_move/test.js create mode 100644 tests/incremental_path/dir/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/incremental_path/dir/a.js create mode 100644 tests/incremental_path/dir/jsfmt.spec.js create mode 100644 tests/indexer/A.js create mode 100644 tests/indexer/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/indexer/jsfmt.spec.js create mode 100644 tests/indexer/multiple.js create mode 100644 tests/init/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/init/hoisted.js create mode 100644 tests/init/hoisted2.js create mode 100644 tests/init/jsfmt.spec.js create mode 100644 tests/init/let.js create mode 100644 tests/init/nullable-init.js create mode 100644 tests/instanceof/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/instanceof/instanceof.js create mode 100644 tests/instanceof/jsfmt.spec.js create mode 100644 tests/integration/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/integration/bar.js create mode 100644 tests/integration/foo.js create mode 100644 tests/integration/jsfmt.spec.js create mode 100644 tests/interface/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/interface/import.js create mode 100644 tests/interface/indexer.js create mode 100644 tests/interface/interface.js create mode 100644 tests/interface/jsfmt.spec.js create mode 100644 tests/interface/test.js create mode 100644 tests/interface/test2.js create mode 100644 tests/interface/test3.js create mode 100644 tests/interface/test4.js create mode 100644 tests/intersection/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/intersection/intersection.js create mode 100644 tests/intersection/jsfmt.spec.js create mode 100644 tests/intersection/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/intersection/lib/jsfmt.spec.js create mode 100644 tests/intersection/lib/lib.js create mode 100644 tests/intersection/objassign.js create mode 100644 tests/intersection/pred.js create mode 100644 tests/intersection/test_fun.js create mode 100644 tests/intersection/test_obj.js create mode 100644 tests/issues-11/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/issues-11/export.js create mode 100644 tests/issues-11/import.js create mode 100644 tests/issues-11/jsfmt.spec.js create mode 100644 tests/iter/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/iter/iter.js create mode 100644 tests/iter/jsfmt.spec.js create mode 100644 tests/iterable/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/iterable/array.js create mode 100644 tests/iterable/caching_bug.js create mode 100644 tests/iterable/iter.js create mode 100644 tests/iterable/iterator_result.js create mode 100644 tests/iterable/jsfmt.spec.js create mode 100644 tests/iterable/map.js create mode 100644 tests/iterable/set.js create mode 100644 tests/iterable/string.js create mode 100644 tests/iterable/variance.js create mode 100644 tests/jsx_intrinsics.builtin/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/jsx_intrinsics.builtin/jsfmt.spec.js create mode 100644 tests/jsx_intrinsics.builtin/main.js create mode 100644 tests/jsx_intrinsics.builtin/strings.js create mode 100644 tests/jsx_intrinsics.custom/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/jsx_intrinsics.custom/jsfmt.spec.js create mode 100644 tests/jsx_intrinsics.custom/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/jsx_intrinsics.custom/lib/jsfmt.spec.js create mode 100644 tests/jsx_intrinsics.custom/lib/jsx.js create mode 100644 tests/jsx_intrinsics.custom/main.js create mode 100644 tests/jsx_intrinsics.custom/strings.js create mode 100644 tests/keys/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/keys/jsfmt.spec.js create mode 100644 tests/keys/keys.js create mode 100644 tests/keyvalue/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/keyvalue/jsfmt.spec.js create mode 100644 tests/keyvalue/keyvalue.js create mode 100644 tests/last_duplicate_property_wins/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/last_duplicate_property_wins/jsfmt.spec.js create mode 100644 tests/last_duplicate_property_wins/test.js create mode 100644 tests/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/lib/jsfmt.spec.js create mode 100644 tests/lib/libtest.js create mode 100644 tests/lib_interfaces/declarations/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/lib_interfaces/declarations/jsfmt.spec.js create mode 100644 tests/lib_interfaces/declarations/underscore.js create mode 100644 tests/libconfig/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/libconfig/jsfmt.spec.js create mode 100644 tests/libconfig/libA.js create mode 100644 tests/libconfig/libB.js create mode 100644 tests/libconfig/libtest.js create mode 100644 tests/libdef_ignored_module/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/libdef_ignored_module/jsfmt.spec.js create mode 100644 tests/libdef_ignored_module/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/libdef_ignored_module/lib/foo.js create mode 100644 tests/libdef_ignored_module/lib/jsfmt.spec.js create mode 100644 tests/libdef_ignored_module/test.js create mode 100644 tests/liberr/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/liberr/a.js create mode 100644 tests/liberr/jsfmt.spec.js create mode 100644 tests/liberr/libs/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/liberr/libs/jsfmt.spec.js create mode 100644 tests/liberr/libs/parse_error.js create mode 100644 tests/liberr/libs/type_error.js create mode 100644 tests/libflow-typed/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/libflow-typed/flow-typed/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/libflow-typed/flow-typed/dino.js create mode 100644 tests/libflow-typed/flow-typed/jsfmt.spec.js create mode 100644 tests/libflow-typed/jsfmt.spec.js create mode 100644 tests/libflow-typed/libtest.js create mode 100644 tests/librec/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/librec/jsfmt.spec.js create mode 100644 tests/librec/lib/A/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/librec/lib/A/jsfmt.spec.js create mode 100644 tests/librec/lib/A/libA.js create mode 100644 tests/librec/lib/B/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/librec/lib/B/jsfmt.spec.js create mode 100644 tests/librec/lib/B/libB.js create mode 100644 tests/librec/libtest.js create mode 100644 tests/literal/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/literal/enum.js create mode 100644 tests/literal/enum_client.js create mode 100644 tests/literal/jsfmt.spec.js create mode 100644 tests/literal/number.js create mode 100644 tests/locals/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/locals/jsfmt.spec.js create mode 100644 tests/locals/lex.js create mode 100644 tests/locals/locals.js create mode 100644 tests/logical/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/logical/jsfmt.spec.js create mode 100644 tests/logical/logical.js create mode 100644 tests/loners/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/loners/jsfmt.spec.js create mode 100644 tests/loners/loners.js create mode 100644 tests/method_properties/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/method_properties/exports_optional_prop.js create mode 100644 tests/method_properties/jsfmt.spec.js create mode 100644 tests/method_properties/test.js create mode 100644 tests/misc/A.js create mode 100644 tests/misc/B.js create mode 100644 tests/misc/C.js create mode 100644 tests/misc/D.js create mode 100644 tests/misc/E.js create mode 100644 tests/misc/F.js create mode 100644 tests/misc/G.js create mode 100644 tests/misc/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/misc/jsfmt.spec.js create mode 100644 tests/missing_annotation/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/missing_annotation/array.js create mode 100644 tests/missing_annotation/async_return.js create mode 100644 tests/missing_annotation/infer.js create mode 100644 tests/missing_annotation/jsfmt.spec.js create mode 100644 tests/modified_lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/modified_lib/jsfmt.spec.js create mode 100644 tests/modified_lib/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/modified_lib/lib/jsfmt.spec.js create mode 100644 tests/modified_lib/lib/lib.js create mode 100644 tests/modified_lib/test.js create mode 100644 tests/module_not_found_errors/src/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/module_not_found_errors/src/index.js create mode 100644 tests/module_not_found_errors/src/jsfmt.spec.js create mode 100644 tests/module_redirect/A.js create mode 100644 tests/module_redirect/B.js create mode 100644 tests/module_redirect/C.js create mode 100644 tests/module_redirect/D.js create mode 100644 tests/module_redirect/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/module_redirect/jsfmt.spec.js create mode 100644 tests/module_use_strict/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/module_use_strict/jsfmt.spec.js create mode 100644 tests/module_use_strict/test.js create mode 100644 tests/modules/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/modules/cli.js create mode 100644 tests/modules/cli2.js create mode 100644 tests/modules/jsfmt.spec.js create mode 100644 tests/modules/lib.js create mode 100644 tests/more_annot/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/more_annot/client_object.js create mode 100644 tests/more_annot/jsfmt.spec.js create mode 100644 tests/more_annot/object.js create mode 100644 tests/more_annot/proto.js create mode 100644 tests/more_annot/super.js create mode 100644 tests/more_classes/Bar.js create mode 100644 tests/more_classes/Foo.js create mode 100644 tests/more_classes/Qux.js create mode 100644 tests/more_classes/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/more_classes/jsfmt.spec.js create mode 100644 tests/more_generics/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/more_generics/jsfmt.spec.js create mode 100644 tests/more_generics/poly.js create mode 100644 tests/more_path/Condition.js create mode 100644 tests/more_path/FlowSA.js create mode 100644 tests/more_path/Sigma.js create mode 100644 tests/more_path/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/more_path/jsfmt.spec.js create mode 100644 tests/more_path/test.js create mode 100644 tests/more_react/API.react.js create mode 100644 tests/more_react/App.react.js create mode 100644 tests/more_react/JSX.js create mode 100644 tests/more_react/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/more_react/jsfmt.spec.js create mode 100644 tests/more_react/propTypes.js create mode 100644 tests/more_statics/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/more_statics/class_static.js create mode 100644 tests/more_statics/jsfmt.spec.js create mode 100644 tests/name_prop/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/name_prop/class.js create mode 100644 tests/name_prop/function.js create mode 100644 tests/name_prop/jsfmt.spec.js create mode 100644 tests/namespace/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/namespace/client.js create mode 100644 tests/namespace/jsfmt.spec.js create mode 100644 tests/namespace/namespace.js create mode 100644 tests/new_react/FeedUFI.react.js create mode 100644 tests/new_react/Mixin.js create mode 100644 tests/new_react/UFILikeCount.react.js create mode 100644 tests/new_react/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/new_react/bad_default_props.js create mode 100644 tests/new_react/classes.js create mode 100644 tests/new_react/fakelib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/new_react/fakelib/jsfmt.spec.js create mode 100644 tests/new_react/fakelib/type_aliases.js create mode 100644 tests/new_react/import-react.js create mode 100644 tests/new_react/jsfmt.spec.js create mode 100644 tests/new_react/new_react.js create mode 100644 tests/new_react/propTypes.js create mode 100644 tests/new_react/props.js create mode 100644 tests/new_react/props2.js create mode 100644 tests/new_react/props3.js create mode 100644 tests/new_react/props4.js create mode 100644 tests/new_react/props5.js create mode 100644 tests/new_react/state.js create mode 100644 tests/new_react/state2.js create mode 100644 tests/new_react/state3.js create mode 100644 tests/new_react/state4.js create mode 100644 tests/new_react/state5.js create mode 100644 tests/node_haste/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_haste/client.js create mode 100644 tests/node_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_haste/external/_d3/jsfmt.spec.js create mode 100644 tests/node_haste/external/_d3/min.js create mode 100644 tests/node_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_haste/foo/bar/client.js create mode 100644 tests/node_haste/foo/bar/jsfmt.spec.js create mode 100644 tests/node_haste/jsfmt.spec.js create mode 100644 tests/node_haste/md5.js create mode 100644 tests/node_haste/ws/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_haste/ws/index.js create mode 100644 tests/node_haste/ws/jsfmt.spec.js create mode 100644 tests/node_haste/ws/test/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_haste/ws/test/client.js create mode 100644 tests/node_haste/ws/test/jsfmt.spec.js create mode 100644 tests/node_modules_with_symlinks/root/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_modules_with_symlinks/root/foo.js create mode 100644 tests/node_modules_with_symlinks/root/jsfmt.spec.js create mode 100644 tests/node_modules_with_symlinks/root/symlink_lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_modules_with_symlinks/root/symlink_lib/index.js create mode 100644 tests/node_modules_with_symlinks/root/symlink_lib/jsfmt.spec.js create mode 100644 tests/node_modules_with_symlinks/symlink_lib_outside_root/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_modules_with_symlinks/symlink_lib_outside_root/index.js create mode 100644 tests/node_modules_with_symlinks/symlink_lib_outside_root/jsfmt.spec.js create mode 100644 tests/node_modules_without_json/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_modules_without_json/jsfmt.spec.js create mode 100644 tests/node_modules_without_json/test.js create mode 100644 tests/node_tests/assert/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/assert/assert.js create mode 100644 tests/node_tests/assert/jsfmt.spec.js create mode 100644 tests/node_tests/basic/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/basic/bar.js create mode 100644 tests/node_tests/basic/foo.js create mode 100644 tests/node_tests/basic/jsfmt.spec.js create mode 100644 tests/node_tests/basic_file/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/basic_file/bar.js create mode 100644 tests/node_tests/basic_file/foo.js create mode 100644 tests/node_tests/basic_file/jsfmt.spec.js create mode 100644 tests/node_tests/basic_node_modules/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/basic_node_modules/foo.js create mode 100644 tests/node_tests/basic_node_modules/jsfmt.spec.js create mode 100644 tests/node_tests/basic_node_modules_with_path/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/basic_node_modules_with_path/foo.js create mode 100644 tests/node_tests/basic_node_modules_with_path/jsfmt.spec.js create mode 100644 tests/node_tests/basic_package/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/basic_package/bar_lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/basic_package/bar_lib/bar.js create mode 100644 tests/node_tests/basic_package/bar_lib/jsfmt.spec.js create mode 100644 tests/node_tests/basic_package/foo.js create mode 100644 tests/node_tests/basic_package/jsfmt.spec.js create mode 100644 tests/node_tests/buffer/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/buffer/buffer.js create mode 100644 tests/node_tests/buffer/jsfmt.spec.js create mode 100644 tests/node_tests/child_process/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/child_process/exec.js create mode 100644 tests/node_tests/child_process/execFile.js create mode 100644 tests/node_tests/child_process/execSync.js create mode 100644 tests/node_tests/child_process/jsfmt.spec.js create mode 100644 tests/node_tests/child_process/spawn.js create mode 100644 tests/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/crypto/crypto.js create mode 100644 tests/node_tests/crypto/jsfmt.spec.js create mode 100644 tests/node_tests/fs/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/fs/fs.js create mode 100644 tests/node_tests/fs/jsfmt.spec.js create mode 100644 tests/node_tests/json_file/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/json_file/jsfmt.spec.js create mode 100644 tests/node_tests/json_file/package2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/json_file/package2/index.js create mode 100644 tests/node_tests/json_file/package2/jsfmt.spec.js create mode 100644 tests/node_tests/json_file/test.js create mode 100644 tests/node_tests/os/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/os/jsfmt.spec.js create mode 100644 tests/node_tests/os/userInfo.js create mode 100644 tests/node_tests/package_file/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/package_file/bar_lib.js create mode 100644 tests/node_tests/package_file/bar_lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/package_file/bar_lib/bar.js create mode 100644 tests/node_tests/package_file/bar_lib/jsfmt.spec.js create mode 100644 tests/node_tests/package_file/foo.js create mode 100644 tests/node_tests/package_file/jsfmt.spec.js create mode 100644 tests/node_tests/package_file_node_modules/foo/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/package_file_node_modules/foo/foo.js create mode 100644 tests/node_tests/package_file_node_modules/foo/jsfmt.spec.js create mode 100644 tests/node_tests/path_node_modules/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/path_node_modules/foo.js create mode 100644 tests/node_tests/path_node_modules/jsfmt.spec.js create mode 100644 tests/node_tests/path_node_modules_with_short_main/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/path_node_modules_with_short_main/foo.js create mode 100644 tests/node_tests/path_node_modules_with_short_main/jsfmt.spec.js create mode 100644 tests/node_tests/path_node_modules_without_main/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/path_node_modules_without_main/foo.js create mode 100644 tests/node_tests/path_node_modules_without_main/jsfmt.spec.js create mode 100644 tests/node_tests/path_package/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/path_package/foo.js create mode 100644 tests/node_tests/path_package/jsfmt.spec.js create mode 100644 tests/node_tests/stream/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/stream/jsfmt.spec.js create mode 100644 tests/node_tests/stream/stream.js create mode 100644 tests/node_tests/timers/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/timers/jsfmt.spec.js create mode 100644 tests/node_tests/timers/timers.js create mode 100644 tests/node_tests/url/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/node_tests/url/jsfmt.spec.js create mode 100644 tests/node_tests/url/url.js create mode 100644 tests/nullable/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/nullable/jsfmt.spec.js create mode 100644 tests/nullable/maybe.js create mode 100644 tests/nullable/nullable.js create mode 100644 tests/nullable/simple_nullable.js create mode 100644 tests/number_constants/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/number_constants/jsfmt.spec.js create mode 100644 tests/number_constants/number_constants.js create mode 100644 tests/object-method/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/object-method/id.js create mode 100644 tests/object-method/jsfmt.spec.js create mode 100644 tests/object-method/subtype.js create mode 100644 tests/object-method/test.js create mode 100644 tests/object-method/test2.js create mode 100644 tests/object-method/test3.js create mode 100644 tests/object_annot/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/object_annot/jsfmt.spec.js create mode 100644 tests/object_annot/test.js create mode 100644 tests/object_api/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/object_api/a.js create mode 100644 tests/object_api/b.js create mode 100644 tests/object_api/c.js create mode 100644 tests/object_api/jsfmt.spec.js create mode 100644 tests/object_api/object_assign.js create mode 100644 tests/object_api/object_create.js create mode 100644 tests/object_api/object_getprototypeof.js create mode 100644 tests/object_api/object_keys.js create mode 100644 tests/object_api/object_missing.js create mode 100644 tests/object_api/object_prototype.js create mode 100644 tests/object_assign/A.js create mode 100644 tests/object_assign/B.js create mode 100644 tests/object_assign/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/object_assign/apply.js create mode 100644 tests/object_assign/jsfmt.spec.js create mode 100644 tests/object_assign/non_objects.js create mode 100644 tests/object_assign/undefined.js create mode 100644 tests/object_freeze/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/object_freeze/jsfmt.spec.js create mode 100644 tests/object_freeze/object_freeze.js create mode 100644 tests/object_is/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/object_is/jsfmt.spec.js create mode 100644 tests/object_is/object_is.js create mode 100644 tests/objects/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/objects/conversion.js create mode 100644 tests/objects/jsfmt.spec.js create mode 100644 tests/objects/objects.js create mode 100644 tests/objects/unaliased_assign.js create mode 100644 tests/objmap/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/objmap/jsfmt.spec.js create mode 100644 tests/objmap/objmap.js create mode 100644 tests/optional/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/optional/client_optional.js create mode 100644 tests/optional/default.js create mode 100644 tests/optional/generic.js create mode 100644 tests/optional/jsfmt.spec.js create mode 100644 tests/optional/maybe.js create mode 100644 tests/optional/nullable.js create mode 100644 tests/optional/optional.js create mode 100644 tests/optional/optional_param.js create mode 100644 tests/optional/optional_param2.js create mode 100644 tests/optional/optional_param3.js create mode 100644 tests/optional/optional_param4.js create mode 100644 tests/optional/undefined.js create mode 100644 tests/optional/undefined2.js create mode 100644 tests/optional_props/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/optional_props/jsfmt.spec.js create mode 100644 tests/optional_props/test.js create mode 100644 tests/optional_props/test2.js create mode 100644 tests/optional_props/test3.js create mode 100644 tests/optional_props/test3_failure.js create mode 100644 tests/overload/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/overload/jsfmt.spec.js create mode 100644 tests/overload/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/overload/lib/jsfmt.spec.js create mode 100644 tests/overload/lib/lib.js create mode 100644 tests/overload/overload.js create mode 100644 tests/overload/test.js create mode 100644 tests/overload/test2.js create mode 100644 tests/overload/test3.js create mode 100644 tests/overload/union.js create mode 100644 tests/parse/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/parse/fail-flow-2.js create mode 100644 tests/parse/fail-flow.js create mode 100644 tests/parse/fail.js create mode 100644 tests/parse/jsfmt.spec.js create mode 100644 tests/parse/no_parse_error.js create mode 100644 tests/parse_error_haste/Client.js create mode 100644 tests/parse_error_haste/NoProvides.js create mode 100644 tests/parse_error_haste/ParseError.js create mode 100644 tests/parse_error_haste/Provides.js create mode 100644 tests/parse_error_haste/Unimported.js create mode 100644 tests/parse_error_haste/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/parse_error_haste/jsfmt.spec.js create mode 100644 tests/parse_error_node/Client.js create mode 100644 tests/parse_error_node/Imported.js create mode 100644 tests/parse_error_node/ParseError.js create mode 100644 tests/parse_error_node/Unimported.js create mode 100644 tests/parse_error_node/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/parse_error_node/jsfmt.spec.js create mode 100644 tests/path/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/path/jsfmt.spec.js create mode 100644 tests/path/while.js create mode 100644 tests/plsummit/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/plsummit/arrays.js create mode 100644 tests/plsummit/export_class.js create mode 100644 tests/plsummit/generics.js create mode 100644 tests/plsummit/import_class.js create mode 100644 tests/plsummit/jsfmt.spec.js create mode 100644 tests/plsummit/locals.js create mode 100644 tests/plsummit/objects.js create mode 100644 tests/poly/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/poly/annot.js create mode 100644 tests/poly/implicit_bounded_instantiation.js create mode 100644 tests/poly/issue-1029.js create mode 100644 tests/poly/jsfmt.spec.js create mode 100644 tests/poly/poly.js create mode 100644 tests/poly/test.js create mode 100644 tests/poly_class_export/A.js create mode 100644 tests/poly_class_export/B.js create mode 100644 tests/poly_class_export/C.js create mode 100644 tests/poly_class_export/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/poly_class_export/jsfmt.spec.js create mode 100644 tests/poly_overload/decls/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/poly_overload/decls/jsfmt.spec.js create mode 100644 tests/poly_overload/decls/typescript-deferred.js create mode 100644 tests/predicates-abstract/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/predicates-abstract/filter-union.js create mode 100644 tests/predicates-abstract/filter.js create mode 100644 tests/predicates-abstract/jsfmt.spec.js create mode 100644 tests/predicates-abstract/refine.js create mode 100644 tests/predicates-abstract/sanity-filter-union.js create mode 100644 tests/predicates-abstract/sanity-filter.js create mode 100644 tests/predicates-abstract/sanity-refine.js create mode 100644 tests/predicates-declared/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/predicates-declared/function-bind.js create mode 100644 tests/predicates-declared/function-union.js create mode 100644 tests/predicates-declared/is-string-decl.js create mode 100644 tests/predicates-declared/jsfmt.spec.js create mode 100644 tests/predicates-declared/logical-or.js create mode 100644 tests/predicates-declared/object-invariant.js create mode 100644 tests/predicates-declared/orig-string-tag-check.js create mode 100644 tests/predicates-declared/sanity-conditional.js create mode 100644 tests/predicates-declared/sanity-fall-through.js create mode 100644 tests/predicates-declared/sanity-invalid-calls.js create mode 100644 tests/predicates-declared/sanity-is-string-bug.js create mode 100644 tests/predicates-declared/sanity-parameter-mismatch.js create mode 100644 tests/predicates-declared/sanity-pred-with-body.js create mode 100644 tests/predicates-declared/sanity-return-type.js create mode 100644 tests/predicates-inferred/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/predicates-inferred/jsfmt.spec.js create mode 100644 tests/predicates-inferred/sanity-multi-params.js create mode 100644 tests/predicates-inferred/sanity-ordering.js create mode 100644 tests/predicates-inferred/sanity-unbound-var.js create mode 100644 tests/predicates-inferred/sanity.js create mode 100644 tests/predicates-inferred/simple-predicate-func-post.js create mode 100644 tests/predicates-inferred/simple-predicate-func.js create mode 100644 tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/predicates-parsing/fail-0.js create mode 100644 tests/predicates-parsing/fail-1.js create mode 100644 tests/predicates-parsing/fail-2.js create mode 100644 tests/predicates-parsing/fail-3.js create mode 100644 tests/predicates-parsing/jsfmt.spec.js create mode 100644 tests/predicates-parsing/pass.js create mode 100644 tests/predicates-parsing/unsupported-0.js create mode 100644 tests/predicates-parsing/unsupported-1.js create mode 100644 tests/predicates-parsing/unsupported-2.js create mode 100644 tests/private/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/private/jsfmt.spec.js create mode 100644 tests/private/private.js create mode 100644 tests/promises/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/promises/all.js create mode 100644 tests/promises/covariance.js create mode 100644 tests/promises/jsfmt.spec.js create mode 100644 tests/promises/promise.js create mode 100644 tests/promises/resolve_global.js create mode 100644 tests/promises/resolve_void.js create mode 100644 tests/pure_component/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/pure_component/jsfmt.spec.js create mode 100644 tests/pure_component/test.js create mode 100644 tests/qualified/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/qualified/jsfmt.spec.js create mode 100644 tests/qualified/qualified.js create mode 100644 tests/react/ArityError.react.js create mode 100644 tests/react/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/react/createElementRequiredProp_string.js create mode 100644 tests/react/createElement_string.js create mode 100644 tests/react/import_react.js create mode 100644 tests/react/jsfmt.spec.js create mode 100644 tests/react/jsx_spread.js create mode 100644 tests/react/proptype_arrayOf.js create mode 100644 tests/react/proptype_func.js create mode 100644 tests/react/proptype_missing.js create mode 100644 tests/react/proptype_object.js create mode 100644 tests/react/proptype_objectOf.js create mode 100644 tests/react/proptype_oneOf.js create mode 100644 tests/react/proptype_oneOfType.js create mode 100644 tests/react_functional/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/react_functional/jsfmt.spec.js create mode 100644 tests/react_functional/test.js create mode 100644 tests/react_modules/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/react_modules/createclass-callsite.js create mode 100644 tests/react_modules/createclass-module.js create mode 100644 tests/react_modules/es6class-proptypes-callsite.js create mode 100644 tests/react_modules/es6class-proptypes-module.js create mode 100644 tests/react_modules/es6class-types-callsite.js create mode 100644 tests/react_modules/es6class-types-module.js create mode 100644 tests/react_modules/jsfmt.spec.js create mode 100644 tests/rec/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/rec/issue-1228.js create mode 100644 tests/rec/issue-598.js create mode 100644 tests/rec/jsfmt.spec.js create mode 100644 tests/rec/test.js create mode 100644 tests/rec/test2.js create mode 100644 tests/rec/test3.js create mode 100644 tests/rec/test4.js create mode 100644 tests/rec/test5.js create mode 100644 tests/recheck-haste/A1.js create mode 100644 tests/recheck-haste/A3.js create mode 100644 tests/recheck-haste/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck-haste/jsfmt.spec.js create mode 100644 tests/recheck-haste/tmp1A/A2.js create mode 100644 tests/recheck-haste/tmp1A/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck-haste/tmp1A/jsfmt.spec.js create mode 100644 tests/recheck-haste/tmp2A/A3.js create mode 100644 tests/recheck-haste/tmp2A/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck-haste/tmp2A/jsfmt.spec.js create mode 100644 tests/recheck/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/a1.js create mode 100644 tests/recheck/a2.js create mode 100644 tests/recheck/a3.js create mode 100644 tests/recheck/b0.js create mode 100644 tests/recheck/b1.js create mode 100644 tests/recheck/b2.js create mode 100644 tests/recheck/b3.js create mode 100644 tests/recheck/c1.js create mode 100644 tests/recheck/c2.js create mode 100644 tests/recheck/c3.js create mode 100644 tests/recheck/d1.js create mode 100644 tests/recheck/d2.js create mode 100644 tests/recheck/e1.js create mode 100644 tests/recheck/e2.js create mode 100644 tests/recheck/f1.js create mode 100644 tests/recheck/f2.js create mode 100644 tests/recheck/g1.js create mode 100644 tests/recheck/g2.js create mode 100644 tests/recheck/g3.js create mode 100644 tests/recheck/h1.js create mode 100644 tests/recheck/h2.js create mode 100644 tests/recheck/jsfmt.spec.js create mode 100644 tests/recheck/tmp1a/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1a/a1.js create mode 100644 tests/recheck/tmp1a/jsfmt.spec.js create mode 100644 tests/recheck/tmp1b/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1b/b1.js create mode 100644 tests/recheck/tmp1b/jsfmt.spec.js create mode 100644 tests/recheck/tmp1c/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1c/c2.js create mode 100644 tests/recheck/tmp1c/jsfmt.spec.js create mode 100644 tests/recheck/tmp1d/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1d/d1.js create mode 100644 tests/recheck/tmp1d/jsfmt.spec.js create mode 100644 tests/recheck/tmp1e/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1e/e2.js create mode 100644 tests/recheck/tmp1e/jsfmt.spec.js create mode 100644 tests/recheck/tmp1f/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1f/f1.js create mode 100644 tests/recheck/tmp1f/jsfmt.spec.js create mode 100644 tests/recheck/tmp1g/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1g/g1.js create mode 100644 tests/recheck/tmp1g/jsfmt.spec.js create mode 100644 tests/recheck/tmp1h/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp1h/h1.js create mode 100644 tests/recheck/tmp1h/jsfmt.spec.js create mode 100644 tests/recheck/tmp2a/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp2a/a1.js create mode 100644 tests/recheck/tmp2a/jsfmt.spec.js create mode 100644 tests/recheck/tmp2b/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp2b/b0.js create mode 100644 tests/recheck/tmp2b/jsfmt.spec.js create mode 100644 tests/recheck/tmp2c/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp2c/c1.js create mode 100644 tests/recheck/tmp2c/jsfmt.spec.js create mode 100644 tests/recheck/tmp2e/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp2e/e1.js create mode 100644 tests/recheck/tmp2e/jsfmt.spec.js create mode 100644 tests/recheck/tmp2f/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp2f/f1.js create mode 100644 tests/recheck/tmp2f/jsfmt.spec.js create mode 100644 tests/recheck/tmp3e/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp3e/e1.js create mode 100644 tests/recheck/tmp3e/e2.js create mode 100644 tests/recheck/tmp3e/jsfmt.spec.js create mode 100644 tests/recheck/tmp3f/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp3f/f1.js create mode 100644 tests/recheck/tmp3f/jsfmt.spec.js create mode 100644 tests/recheck/tmp4f/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/recheck/tmp4f/f1.js create mode 100644 tests/recheck/tmp4f/jsfmt.spec.js create mode 100644 tests/record/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/record/jsfmt.spec.js create mode 100644 tests/record/test.js create mode 100644 tests/refi/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/refi/bound.js create mode 100644 tests/refi/heap.js create mode 100644 tests/refi/jsfmt.spec.js create mode 100644 tests/refi/lex.js create mode 100644 tests/refi/local.js create mode 100644 tests/refi/null_tests.js create mode 100644 tests/refi/switch.js create mode 100644 tests/refi/typeof_tests.js create mode 100644 tests/refi/undef_tests.js create mode 100644 tests/refi/void_tests.js create mode 100644 tests/refinements/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/refinements/assignment.js create mode 100644 tests/refinements/ast_node.js create mode 100644 tests/refinements/bool.js create mode 100644 tests/refinements/computed_string_literal.js create mode 100644 tests/refinements/cond_prop.js create mode 100644 tests/refinements/constants.js create mode 100644 tests/refinements/eq.js create mode 100644 tests/refinements/exists.js create mode 100644 tests/refinements/func_call.js create mode 100644 tests/refinements/hasOwnProperty.js create mode 100644 tests/refinements/heap_defassign.js create mode 100644 tests/refinements/jsfmt.spec.js create mode 100644 tests/refinements/lib.js create mode 100644 tests/refinements/missing-property-cond.js create mode 100644 tests/refinements/mixed.js create mode 100644 tests/refinements/node1.js create mode 100644 tests/refinements/not.js create mode 100644 tests/refinements/null.js create mode 100644 tests/refinements/number.js create mode 100644 tests/refinements/property.js create mode 100644 tests/refinements/refinements.js create mode 100644 tests/refinements/string.js create mode 100644 tests/refinements/super_member.js create mode 100644 tests/refinements/switch.js create mode 100644 tests/refinements/tagged_union.js create mode 100644 tests/refinements/tagged_union_import.js create mode 100644 tests/refinements/typeof.js create mode 100644 tests/refinements/undef.js create mode 100644 tests/refinements/union.js create mode 100644 tests/refinements/void.js create mode 100644 tests/reflection/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/reflection/jsfmt.spec.js create mode 100644 tests/reflection/type.js create mode 100644 tests/regexp/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/regexp/jsfmt.spec.js create mode 100644 tests/regexp/regexp.js create mode 100644 tests/replace/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/replace/jsfmt.spec.js create mode 100644 tests/replace/test.js create mode 100644 tests/require/B.js create mode 100644 tests/require/C.js create mode 100644 tests/require/E.js create mode 100644 tests/require/ProvidesModuleA.js create mode 100644 tests/require/ProvidesModuleD.js create mode 100644 tests/require/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/require/jsfmt.spec.js create mode 100644 tests/require/not_builtin_require.js create mode 100644 tests/require/not_builtin_require2.js create mode 100644 tests/require/require.js create mode 100644 tests/requireLazy/A.js create mode 100644 tests/requireLazy/B.js create mode 100644 tests/requireLazy/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/requireLazy/jsfmt.spec.js create mode 100644 tests/requireLazy/requireLazy.js create mode 100644 tests/return/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/return/function_return.js create mode 100644 tests/return/jsfmt.spec.js create mode 100644 tests/return/void.js create mode 100644 tests/return_new/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/return_new/jsfmt.spec.js create mode 100644 tests/return_new/test.js create mode 100644 tests/return_new/test2.js create mode 100644 tests/seal/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/seal/imp.js create mode 100644 tests/seal/jsfmt.spec.js create mode 100644 tests/seal/obj_annot.js create mode 100644 tests/sealed/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/sealed/function.js create mode 100644 tests/sealed/jsfmt.spec.js create mode 100644 tests/sealed/proto.js create mode 100644 tests/sealed/sealed.js create mode 100644 tests/sealed_objects/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/sealed_objects/jsfmt.spec.js create mode 100644 tests/sealed_objects/test.js create mode 100644 tests/shape/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/shape/jsfmt.spec.js create mode 100644 tests/shape/test.js create mode 100644 tests/simple_arrays/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/simple_arrays/array.js create mode 100644 tests/simple_arrays/array2.js create mode 100644 tests/simple_arrays/jsfmt.spec.js create mode 100644 tests/singleton/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/singleton/boolean.js create mode 100644 tests/singleton/jsfmt.spec.js create mode 100644 tests/singleton/number.js create mode 100644 tests/singleton/string.js create mode 100644 tests/spread/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/spread/jsfmt.spec.js create mode 100644 tests/spread/test.js create mode 100644 tests/spread/test2.js create mode 100644 tests/spread/test3.js create mode 100644 tests/spread/test4.js create mode 100644 tests/spread/test5.js create mode 100644 tests/spread/test6.js create mode 100644 tests/spread/test7.js create mode 100644 tests/static_overload/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/static_overload/jsfmt.spec.js create mode 100644 tests/static_overload/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/static_overload/lib/jsfmt.spec.js create mode 100644 tests/static_overload/lib/lib.js create mode 100644 tests/static_overload/test.js create mode 100644 tests/statics/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/statics/class_statics.js create mode 100644 tests/statics/funstatics.js create mode 100644 tests/statics/jsfmt.spec.js create mode 100644 tests/strict/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/strict/annot.js create mode 100644 tests/strict/fun.js create mode 100644 tests/strict/jsfmt.spec.js create mode 100644 tests/strict/obj.js create mode 100644 tests/strict_requires/A.js create mode 100644 tests/strict_requires/B.js create mode 100644 tests/strict_requires/C.js create mode 100644 tests/strict_requires/D.js create mode 100644 tests/strict_requires/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/strict_requires/jsfmt.spec.js create mode 100644 tests/strings/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/strings/jsfmt.spec.js create mode 100644 tests/strings/strings.js create mode 100644 tests/structural_subtyping/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/structural_subtyping/builtin.js create mode 100644 tests/structural_subtyping/class.js create mode 100644 tests/structural_subtyping/jsfmt.spec.js create mode 100644 tests/structural_subtyping/obj.js create mode 100644 tests/structural_subtyping/optional.js create mode 100644 tests/suggest/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/suggest/jsfmt.spec.js create mode 100644 tests/suggest/lib.js create mode 100644 tests/suggest/suggest.js create mode 100644 tests/super/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/super/constructor.js create mode 100644 tests/super/import.js create mode 100644 tests/super/jsfmt.spec.js create mode 100644 tests/super/super.js create mode 100644 tests/super/test.js create mode 100644 tests/suppress/A.js create mode 100644 tests/suppress/B.js create mode 100644 tests/suppress/C.js create mode 100644 tests/suppress/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/suppress/jsfmt.spec.js create mode 100644 tests/suppress/lib.js create mode 100644 tests/suppress_incremental/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/suppress_incremental/jsfmt.spec.js create mode 100644 tests/suppress_incremental/test.js create mode 100644 tests/suppress_traces/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/suppress_traces/jsfmt.spec.js create mode 100644 tests/suppress_traces/traces.js create mode 100644 tests/switch/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/switch/jsfmt.spec.js create mode 100644 tests/switch/more_switch.js create mode 100644 tests/switch/switch.js create mode 100644 tests/switch/switch_default_fallthrough.js create mode 100644 tests/switch/trailing_cases.js create mode 100644 tests/symbol/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/symbol/jsfmt.spec.js create mode 100644 tests/symbol/symbol.js create mode 100644 tests/symlink/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/symlink/bar.js create mode 100644 tests/symlink/foo.js create mode 100644 tests/symlink/jsfmt.spec.js create mode 100644 tests/symlink/qux.js create mode 100644 tests/tagged-unions/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/tagged-unions/classes.js create mode 100644 tests/tagged-unions/interfaces-neg.js create mode 100644 tests/tagged-unions/interfaces-pos.js create mode 100644 tests/tagged-unions/jsfmt.spec.js create mode 100644 tests/tagged-unions/type-decls-neg.js create mode 100644 tests/tagged-unions/type-decls-pos.js create mode 100644 tests/taint/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/taint/adder.js create mode 100644 tests/taint/any_object.js create mode 100644 tests/taint/call-object-property.js create mode 100644 tests/taint/comparator.js create mode 100644 tests/taint/function.js create mode 100644 tests/taint/globals.js create mode 100644 tests/taint/jsfmt.spec.js create mode 100644 tests/taint/lib.js create mode 100644 tests/taint/taint1.js create mode 100644 tests/taint/taint2.js create mode 100644 tests/taint/taint3.js create mode 100644 tests/taint/taint4.js create mode 100644 tests/taint/use-types.js create mode 100644 tests/template/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/template/jsfmt.spec.js create mode 100644 tests/template/template.js create mode 100644 tests/this/This.js create mode 100644 tests/this/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/this/arrows.js create mode 100644 tests/this/jsfmt.spec.js create mode 100644 tests/this_ctor/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/this_ctor/jsfmt.spec.js create mode 100644 tests/this_ctor/test.js create mode 100644 tests/this_type/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/this_type/class_expr.js create mode 100644 tests/this_type/contra.js create mode 100644 tests/this_type/export.js create mode 100644 tests/this_type/generics.js create mode 100644 tests/this_type/import.js create mode 100644 tests/this_type/interface.js create mode 100644 tests/this_type/jsfmt.spec.js create mode 100644 tests/this_type/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/this_type/lib/decl.js create mode 100644 tests/this_type/lib/jsfmt.spec.js create mode 100644 tests/this_type/lib_client.js create mode 100644 tests/this_type/self.js create mode 100644 tests/this_type/statics.js create mode 100644 tests/this_type/test.js create mode 100644 tests/throw/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/throw/jsfmt.spec.js create mode 100644 tests/throw/test.js create mode 100644 tests/traces/Traces.js create mode 100644 tests/traces/Traces2.js create mode 100644 tests/traces/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/traces/jsfmt.spec.js create mode 100644 tests/traits/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/traits/jsfmt.spec.js create mode 100644 tests/traits/test.js create mode 100644 tests/traits/test2.js create mode 100644 tests/try/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/try/abnormals.js create mode 100644 tests/try/init.js create mode 100644 tests/try/jsfmt.spec.js create mode 100644 tests/try/return.js create mode 100644 tests/try/test.js create mode 100644 tests/tuples/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/tuples/array.js create mode 100644 tests/tuples/jsfmt.spec.js create mode 100644 tests/tuples/optional.js create mode 100644 tests/tuples/too-few.js create mode 100644 tests/tuples/tuples.js create mode 100644 tests/type-at-pos/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type-at-pos/destructuring.js create mode 100644 tests/type-at-pos/function_expressions.js create mode 100644 tests/type-at-pos/generics.js create mode 100644 tests/type-at-pos/import.js create mode 100644 tests/type-at-pos/jsfmt.spec.js create mode 100644 tests/type-at-pos/object_special_cases.js create mode 100644 tests/type-at-pos/optional.js create mode 100644 tests/type-at-pos/predicates.js create mode 100644 tests/type-at-pos/react.js create mode 100644 tests/type-at-pos/templates.js create mode 100644 tests/type-at-pos/test.js create mode 100644 tests/type-at-pos/trycatch.js create mode 100644 tests/type-destructors/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type-destructors/jsfmt.spec.js create mode 100644 tests/type-destructors/non_maybe_type.js create mode 100644 tests/type-destructors/property_type.js create mode 100644 tests/type-destructors/union.js create mode 100644 tests/type-printer/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type-printer/jsfmt.spec.js create mode 100644 tests/type-printer/printBinaryExpression.js create mode 100644 tests/type-printer/types.js create mode 100644 tests/type_args_nonstrict/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_args_nonstrict/jsfmt.spec.js create mode 100644 tests/type_args_nonstrict/test.js create mode 100644 tests/type_args_strict/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_args_strict/jsfmt.spec.js create mode 100644 tests/type_args_strict/test.js create mode 100644 tests/type_only_vars/A.js create mode 100644 tests/type_only_vars/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_only_vars/bad_shadowing.js create mode 100644 tests/type_only_vars/good_shadowing.js create mode 100644 tests/type_only_vars/import_type.js create mode 100644 tests/type_only_vars/jsfmt.spec.js create mode 100644 tests/type_only_vars/type_alias.js create mode 100644 tests/type_param_defaults/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_param_defaults/classes.js create mode 100644 tests/type_param_defaults/jsfmt.spec.js create mode 100644 tests/type_param_scope/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_param_scope/class.js create mode 100644 tests/type_param_scope/default_params.js create mode 100644 tests/type_param_scope/jsfmt.spec.js create mode 100644 tests/type_param_scope/method_shadow.js create mode 100644 tests/type_param_variance/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_param_variance/jsfmt.spec.js create mode 100644 tests/type_param_variance/promise.js create mode 100644 tests/type_param_variance2/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_param_variance2/jsfmt.spec.js create mode 100644 tests/type_param_variance2/libs/Promise.js create mode 100644 tests/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/type_param_variance2/libs/jsfmt.spec.js create mode 100644 tests/type_param_variance2/promise.js create mode 100644 tests/typeapp_perf/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/typeapp_perf/jsfmt.spec.js create mode 100644 tests/typeapp_perf/test1.js create mode 100644 tests/typeapp_perf/test2.js create mode 100644 tests/typecast/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/typecast/jsfmt.spec.js create mode 100644 tests/typecast/typecast.js create mode 100644 tests/typeof/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/typeof/jsfmt.spec.js create mode 100644 tests/typeof/typeof.js create mode 100644 tests/unary/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/unary/jsfmt.spec.js create mode 100644 tests/unary/unary.js create mode 100644 tests/unary/update.js create mode 100644 tests/unchecked_haste_module_vs_lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/unchecked_haste_module_vs_lib/buffer.js create mode 100644 tests/unchecked_haste_module_vs_lib/jsfmt.spec.js create mode 100644 tests/unchecked_haste_module_vs_lib/test.js create mode 100644 tests/unchecked_node_module_vs_lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/unchecked_node_module_vs_lib/jsfmt.spec.js create mode 100644 tests/unchecked_node_module_vs_lib/test.js create mode 100644 tests/undefined/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/undefined/issue-518.js create mode 100644 tests/undefined/jsfmt.spec.js create mode 100644 tests/undefined/undefined.js create mode 100644 tests/undefined/undefined2.js create mode 100644 tests/unicode/UnicodeUtils.js create mode 100644 tests/unicode/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/unicode/jsfmt.spec.js create mode 100644 tests/union-intersection/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/union-intersection/gen_big_disjoint_union.js create mode 100644 tests/union-intersection/jsfmt.spec.js create mode 100644 tests/union-intersection/test.js create mode 100644 tests/union/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/union/fields.js create mode 100644 tests/union/fields2.js create mode 100644 tests/union/issue-17.js create mode 100644 tests/union/issue-198.js create mode 100644 tests/union/issue-256.js create mode 100644 tests/union/issue-323-lib.js create mode 100644 tests/union/issue-323.js create mode 100644 tests/union/issue-324.js create mode 100644 tests/union/issue-325.js create mode 100644 tests/union/issue-326.js create mode 100644 tests/union/issue-582.js create mode 100644 tests/union/issue-963.js create mode 100644 tests/union/jsfmt.spec.js create mode 100644 tests/union/test-lib.js create mode 100644 tests/union/test.js create mode 100644 tests/union/type-app.js create mode 100644 tests/union/union.js create mode 100644 tests/union/yuge.js create mode 100644 tests/union_new/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/union_new/issue-1349.js create mode 100644 tests/union_new/issue-1371.js create mode 100644 tests/union_new/issue-1455-helper.js create mode 100644 tests/union_new/issue-1455.js create mode 100644 tests/union_new/issue-1462-i.js create mode 100644 tests/union_new/issue-1462-ii.js create mode 100644 tests/union_new/issue-1664.js create mode 100644 tests/union_new/issue-1759.js create mode 100644 tests/union_new/issue-2232.js create mode 100644 tests/union_new/issue-815.js create mode 100644 tests/union_new/issue-824-helper.js create mode 100644 tests/union_new/issue-824.js create mode 100644 tests/union_new/jsfmt.spec.js create mode 100644 tests/union_new/lib/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/union_new/lib/jsfmt.spec.js create mode 100644 tests/union_new/lib/test23_lib.js create mode 100644 tests/union_new/lib/test25_lib.js create mode 100644 tests/union_new/lib/test32_lib.js create mode 100644 tests/union_new/test1.js create mode 100644 tests/union_new/test10.js create mode 100644 tests/union_new/test11.js create mode 100644 tests/union_new/test12.js create mode 100644 tests/union_new/test13.js create mode 100644 tests/union_new/test14.js create mode 100644 tests/union_new/test15.js create mode 100644 tests/union_new/test16.js create mode 100644 tests/union_new/test17.js create mode 100644 tests/union_new/test18.js create mode 100644 tests/union_new/test19.js create mode 100644 tests/union_new/test2.js create mode 100644 tests/union_new/test20.js create mode 100644 tests/union_new/test21.js create mode 100644 tests/union_new/test22.js create mode 100644 tests/union_new/test23.js create mode 100644 tests/union_new/test24.js create mode 100644 tests/union_new/test25.js create mode 100644 tests/union_new/test26.js create mode 100644 tests/union_new/test27.js create mode 100644 tests/union_new/test29.js create mode 100644 tests/union_new/test3.js create mode 100644 tests/union_new/test30-helper.js create mode 100644 tests/union_new/test30.js create mode 100644 tests/union_new/test31.js create mode 100644 tests/union_new/test32.js create mode 100644 tests/union_new/test4.js create mode 100644 tests/union_new/test5.js create mode 100644 tests/union_new/test6.js create mode 100644 tests/union_new/test7.js create mode 100644 tests/union_new/test8.js create mode 100644 tests/union_new/test9.js create mode 100644 tests/unreachable/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/unreachable/jsfmt.spec.js create mode 100644 tests/unreachable/typecheck.js create mode 100644 tests/unreachable/unreachable.js create mode 100644 tests/value/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/value/jsfmt.spec.js create mode 100644 tests/value/value.js create mode 100644 tests/vim_emacs_errors/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/vim_emacs_errors/jsfmt.spec.js create mode 100644 tests/vim_emacs_errors/test.js create mode 100644 tests/weakmode/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/weakmode/jsfmt.spec.js create mode 100644 tests/weakmode/should_fail_without_weak.js create mode 100644 tests/weakmode/should_pass_with_weak.js create mode 100644 tests/while/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/while/abnormal.js create mode 100644 tests/while/jsfmt.spec.js create mode 100644 tests/while/test.js create mode 100644 tests/window/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/window/jsfmt.spec.js create mode 100644 tests/window/window1.js create mode 100644 tests/window/window2.js create mode 100644 tests/x/XControllerURIBuilder.js create mode 100644 tests/x/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/x/jsfmt.spec.js create mode 100644 tests/yield/__snapshots__/jsfmt.spec.js.snap create mode 100644 tests/yield/jsfmt.spec.js create mode 100644 tests/yield/yield_arrow_error.js create mode 100644 tests/yield/yield_arrow_error2.js create mode 100644 tests_config/run_spec.js diff --git a/package.json b/package.json index 4d840540db75..91b01831c72a 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,19 @@ "recast": "^0.11.18" }, "devDependencies": { - "glob": "^7.1.1" + "glob": "^7.1.1", + "jest": "^18.0.0", + "flow-parser": "^0.37.0" + }, + "scripts": { + "test": "jest" + }, + "jest": { + "setupFiles": [ + "/tests_config/run_spec.js" + ], + "testRegex": [ + "jsfmt\\.spec\\.js$" + ] } } diff --git a/tests/abnormal/__snapshots__/jsfmt.spec.js.snap b/tests/abnormal/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3963bef56d30 --- /dev/null +++ b/tests/abnormal/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,127 @@ +exports[`test break-continue.js 1`] = ` +"function foo() { + while(true) { break; } +} + +function bar() { + L: do { continue L; } while(false) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:925 + if (endsWithBrace(doBody)) + ^ + +ReferenceError: endsWithBrace is not defined + at genericPrintNoParens (/src/printer.js:925:11) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:963:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test return.js 1`] = ` +"function bar(x:number) { } +function foo() { + var x = null; + if (x == null) return; + bar(x); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function bar(x: number) { + +} +function foo() { + var x = null; + if (x == null) + return; + bar(x); +} + +" +`; + +exports[`test toplevel_break.js 1`] = ` +"// @flow + +break; // error, illegal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unsyntactic break (3:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$1.parseBreakContinueStatement (/node_modules/babylon/lib/index.js:1843:44) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1703:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) + at Object.parse (/index.js:34:26) + at Object.parse (/node_modules/recast/lib/parser.js:26:34) +" +`; + +exports[`test toplevel_continue.js 1`] = ` +"// @flow + +continue; // error, illegal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unsyntactic continue (3:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$1.parseBreakContinueStatement (/node_modules/babylon/lib/index.js:1843:44) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1703:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) + at Object.parse (/index.js:34:26) + at Object.parse (/node_modules/recast/lib/parser.js:26:34) +" +`; + +exports[`test toplevel_return.js 1`] = ` +"// @flow + +return; // error, illegal +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: \'return\' outside of function (3:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$1.parseReturnStatement (/node_modules/babylon/lib/index.js:1939:10) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1722:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) + at Object.parse (/index.js:34:26) + at Object.parse (/node_modules/recast/lib/parser.js:26:34) +" +`; + +exports[`test toplevel_throw.js 1`] = ` +"// @flow + +throw new Error(\'foo\'); // no error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +throw new Error(\"foo\");// no error + +" +`; diff --git a/tests/abnormal/break-continue.js b/tests/abnormal/break-continue.js new file mode 100644 index 000000000000..1f10210ca25b --- /dev/null +++ b/tests/abnormal/break-continue.js @@ -0,0 +1,7 @@ +function foo() { + while(true) { break; } +} + +function bar() { + L: do { continue L; } while(false) +} diff --git a/tests/abnormal/jsfmt.spec.js b/tests/abnormal/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/abnormal/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/abnormal/return.js b/tests/abnormal/return.js new file mode 100644 index 000000000000..c2c32814d414 --- /dev/null +++ b/tests/abnormal/return.js @@ -0,0 +1,6 @@ +function bar(x:number) { } +function foo() { + var x = null; + if (x == null) return; + bar(x); +} diff --git a/tests/abnormal/toplevel_break.js b/tests/abnormal/toplevel_break.js new file mode 100644 index 000000000000..15dd4120aefd --- /dev/null +++ b/tests/abnormal/toplevel_break.js @@ -0,0 +1,3 @@ +// @flow + +break; // error, illegal diff --git a/tests/abnormal/toplevel_continue.js b/tests/abnormal/toplevel_continue.js new file mode 100644 index 000000000000..63ecd26c0a9e --- /dev/null +++ b/tests/abnormal/toplevel_continue.js @@ -0,0 +1,3 @@ +// @flow + +continue; // error, illegal diff --git a/tests/abnormal/toplevel_return.js b/tests/abnormal/toplevel_return.js new file mode 100644 index 000000000000..64233d781de2 --- /dev/null +++ b/tests/abnormal/toplevel_return.js @@ -0,0 +1,3 @@ +// @flow + +return; // error, illegal diff --git a/tests/abnormal/toplevel_throw.js b/tests/abnormal/toplevel_throw.js new file mode 100644 index 000000000000..91f0b353915d --- /dev/null +++ b/tests/abnormal/toplevel_throw.js @@ -0,0 +1,3 @@ +// @flow + +throw new Error('foo'); // no error diff --git a/tests/annot/__snapshots__/jsfmt.spec.js.snap b/tests/annot/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b4924ebb8612 --- /dev/null +++ b/tests/annot/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,234 @@ +exports[`test annot.js 1`] = ` +"function foo(str:string, i:number):string { + return str; +} +var bar: (str:number, i:number)=> string = foo; + +var qux = function(str:string, i:number):number { return foo(str,i); } + +var obj: {str:string; i:number; j:boolean} = {str: \"...\", i: \"...\", k: false}; + +var arr: Array = [1,2,\"...\"]; + +// array sugar +var array: number[] = [1,2,\"...\"]; + +var matrix: number[][] = [[1,2],[3,4]]; +var matrix_parens: (number[])[] = matrix; + +var nullable_array: ?number[] = null; +var nullable_array_parens: ?(number[]) = nullable_array; + +var array_of_nullable: (?number)[] = [null, 3]; + +var array_of_tuple: [number, string][] = [[0, \"foo\"], [1, \"bar\"]]; +var array_of_tuple_parens: ([number, string])[] = array_of_tuple; + +type ObjType = { \'bar-foo\': string; \'foo-bar\': number; }; +var test_obj: ObjType = { \'bar-foo\': \'23\' }; + +// param type annos are strict UBs like var type annos +function param_anno(n:number):void { + n = \"hey\"; // error +} + +// another error on param UB, more typical of www (mis)use-cases +// this one cribbed from API.atlas.js +function param_anno2( + batchRequests: Array<{method: string; path: string; params: ?Object}>, + ): void { + + // error below, since we\'re assigning elements to batchRequests + // which lack a path property. + // just assign result to new var instead of reassigning to param. + + // Transform the requests to the format the Graph API expects. + batchRequests = batchRequests.map((request) => { + return { + method: request.method, + params: request.params, + relative_url: request.path, + }; + }); + // ... + } + +var toz : null = 3; + +var zer : null = null; + +function foobar(n : ?number) : number | null | void { return n; } +function barfoo(n : number | null | void) : ?number { return n; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test forward_ref.js 1`] = ` +"let myClassInstance: MyClass = null; // forward ref ok, null ~> class error + +function bar(): MyClass { + return null; // forward ref ok, null ~> class error +} + +class MyClass { } // looked up above + +function foo() { + let myClassInstance: MyClass = mk(); // ok (no confusion across scopes) + function mk() { return new MyClass(); } + + class MyClass { } // looked up above +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +let myClassInstance: MyClass = null;// forward ref ok, null ~> class error +function bar(): MyClass { + return null;// forward ref ok, null ~> class error +} +class MyClass {}// looked up above +function foo() { + let myClassInstance: MyClass = mk();// ok (no confusion across scopes) + function mk() { + return new MyClass(); + } + class MyClass {}// looked up above +} + +" +`; + +exports[`test issue-530.js 1`] = ` +"function foo(...args: any) { } + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(...args) { + +} +module.exports = foo; + +" +`; + +exports[`test leak.js 1`] = ` +"/** @flow */ + +/* This test documents an example we ran into of a type annotation leaking. + * + * When foo() calls bar(), we should make sure the type of x matches the type + * annotation for y and stop. We should type the body of bar() with the type + * annotation of y. + * + * However, the leaky type annotation meant that we were flowing x\'s type to y + * and type checking the body of bar() using the stricter dictionary type, + * leading to an error. + */ + +type MyObj = Object; + +function foo(x: {[key: string]: mixed}) { + bar(x); +} + +function bar(y: MyObj): string { + return y.foo; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** @flow */ +/* This test documents an example we ran into of a type annotation leaking. + * + * When foo() calls bar(), we should make sure the type of x matches the type + * annotation for y and stop. We should type the body of bar() with the type + * annotation of y. + * + * However, the leaky type annotation meant that we were flowing x\'s type to y + * and type checking the body of bar() using the stricter dictionary type, + * leading to an error. + */ +type MyObj = Object; +function foo(x: { [key: string]: mixed }) { + bar(x); +} +function bar(y: MyObj): string { + return y.foo; +} + +" +`; + +exports[`test other.js 1`] = ` +"class C { } +module.exports = (C: any); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C {} +module.exports = (C: any); + +" +`; + +exports[`test scope.js 1`] = ` +"type Merge = (a: T, b: T) => T; + +// hypothetical immutable map +declare class Map { + (): Map; + insertWith(fn: Merge, k: K, v: V): Map; +} + +declare function foldr(fn: (a: A, b: B) => B, b: B, as: A[]): B; + +function insertMany(merge: Merge, vs: [K,V][], m: Map): Map { + function f([k,v]: [K,V], m: Map): Map { + return m.insertWith(merge, k, v) + } + return foldr(f, m, vs) +} + +class Foo { + bar() { + return function(a: A, b: B, c: C): void { + ([a,b,c] : [A,B,C]); + } + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"var C = require(\'./other\'); +((0: C): string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var C = require(\"./other\"); +((0: C): string); + +" +`; diff --git a/tests/annot/annot.js b/tests/annot/annot.js new file mode 100644 index 000000000000..4d1b25a5ad64 --- /dev/null +++ b/tests/annot/annot.js @@ -0,0 +1,60 @@ +function foo(str:string, i:number):string { + return str; +} +var bar: (str:number, i:number)=> string = foo; + +var qux = function(str:string, i:number):number { return foo(str,i); } + +var obj: {str:string; i:number; j:boolean} = {str: "...", i: "...", k: false}; + +var arr: Array = [1,2,"..."]; + +// array sugar +var array: number[] = [1,2,"..."]; + +var matrix: number[][] = [[1,2],[3,4]]; +var matrix_parens: (number[])[] = matrix; + +var nullable_array: ?number[] = null; +var nullable_array_parens: ?(number[]) = nullable_array; + +var array_of_nullable: (?number)[] = [null, 3]; + +var array_of_tuple: [number, string][] = [[0, "foo"], [1, "bar"]]; +var array_of_tuple_parens: ([number, string])[] = array_of_tuple; + +type ObjType = { 'bar-foo': string; 'foo-bar': number; }; +var test_obj: ObjType = { 'bar-foo': '23' }; + +// param type annos are strict UBs like var type annos +function param_anno(n:number):void { + n = "hey"; // error +} + +// another error on param UB, more typical of www (mis)use-cases +// this one cribbed from API.atlas.js +function param_anno2( + batchRequests: Array<{method: string; path: string; params: ?Object}>, + ): void { + + // error below, since we're assigning elements to batchRequests + // which lack a path property. + // just assign result to new var instead of reassigning to param. + + // Transform the requests to the format the Graph API expects. + batchRequests = batchRequests.map((request) => { + return { + method: request.method, + params: request.params, + relative_url: request.path, + }; + }); + // ... + } + +var toz : null = 3; + +var zer : null = null; + +function foobar(n : ?number) : number | null | void { return n; } +function barfoo(n : number | null | void) : ?number { return n; } diff --git a/tests/annot/any/A.js b/tests/annot/any/A.js new file mode 100644 index 000000000000..093d2d63a2ce --- /dev/null +++ b/tests/annot/any/A.js @@ -0,0 +1,9 @@ +type T = any; + +export default class { + p: T; + + constructor() { + this.p = 0; + } +} diff --git a/tests/annot/any/B.js b/tests/annot/any/B.js new file mode 100644 index 000000000000..1e0776d87a61 --- /dev/null +++ b/tests/annot/any/B.js @@ -0,0 +1,5 @@ +import A from "./A" + +class B extends A { + p: string; // OK, string ~> any +} diff --git a/tests/annot/any/__snapshots__/jsfmt.spec.js.snap b/tests/annot/any/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a65f786d3a96 --- /dev/null +++ b/tests/annot/any/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,36 @@ +exports[`test A.js 1`] = ` +"type T = any; + +export default class { + p: T; + + constructor() { + this.p = 0; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +type T = any; +export default class { + p: T; + constructor() { + this.p = 0; + } +} + +" +`; + +exports[`test B.js 1`] = ` +"import A from "./A" + +class B extends A { + p: string; // OK, string ~> any +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import A from "./A"; +class B extends A { + p: string;// OK, string ~> any +} + +" +`; diff --git a/tests/annot/any/jsfmt.spec.js b/tests/annot/any/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/annot/any/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/annot/forward_ref.js b/tests/annot/forward_ref.js new file mode 100644 index 000000000000..8061d65a3aad --- /dev/null +++ b/tests/annot/forward_ref.js @@ -0,0 +1,14 @@ +let myClassInstance: MyClass = null; // forward ref ok, null ~> class error + +function bar(): MyClass { + return null; // forward ref ok, null ~> class error +} + +class MyClass { } // looked up above + +function foo() { + let myClassInstance: MyClass = mk(); // ok (no confusion across scopes) + function mk() { return new MyClass(); } + + class MyClass { } // looked up above +} diff --git a/tests/annot/issue-530.js b/tests/annot/issue-530.js new file mode 100644 index 000000000000..bd8d893e516d --- /dev/null +++ b/tests/annot/issue-530.js @@ -0,0 +1,3 @@ +function foo(...args: any) { } + +module.exports = foo; diff --git a/tests/annot/jsfmt.spec.js b/tests/annot/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/annot/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/annot/leak.js b/tests/annot/leak.js new file mode 100644 index 000000000000..bfc8254c74be --- /dev/null +++ b/tests/annot/leak.js @@ -0,0 +1,22 @@ +/** @flow */ + +/* This test documents an example we ran into of a type annotation leaking. + * + * When foo() calls bar(), we should make sure the type of x matches the type + * annotation for y and stop. We should type the body of bar() with the type + * annotation of y. + * + * However, the leaky type annotation meant that we were flowing x's type to y + * and type checking the body of bar() using the stricter dictionary type, + * leading to an error. + */ + +type MyObj = Object; + +function foo(x: {[key: string]: mixed}) { + bar(x); +} + +function bar(y: MyObj): string { + return y.foo; +} diff --git a/tests/annot/other.js b/tests/annot/other.js new file mode 100644 index 000000000000..0407c8397d80 --- /dev/null +++ b/tests/annot/other.js @@ -0,0 +1,2 @@ +class C { } +module.exports = (C: any); diff --git a/tests/annot/scope.js b/tests/annot/scope.js new file mode 100644 index 000000000000..3f0b7ec6c5c8 --- /dev/null +++ b/tests/annot/scope.js @@ -0,0 +1,24 @@ +type Merge = (a: T, b: T) => T; + +// hypothetical immutable map +declare class Map { + (): Map; + insertWith(fn: Merge, k: K, v: V): Map; +} + +declare function foldr(fn: (a: A, b: B) => B, b: B, as: A[]): B; + +function insertMany(merge: Merge, vs: [K,V][], m: Map): Map { + function f([k,v]: [K,V], m: Map): Map { + return m.insertWith(merge, k, v) + } + return foldr(f, m, vs) +} + +class Foo { + bar() { + return function(a: A, b: B, c: C): void { + ([a,b,c] : [A,B,C]); + } + } +} diff --git a/tests/annot/test.js b/tests/annot/test.js new file mode 100644 index 000000000000..94f65159e8d0 --- /dev/null +++ b/tests/annot/test.js @@ -0,0 +1,2 @@ +var C = require('./other'); +((0: C): string); diff --git a/tests/annot2/A.js b/tests/annot2/A.js new file mode 100644 index 000000000000..06abcbf1ddd4 --- /dev/null +++ b/tests/annot2/A.js @@ -0,0 +1,14 @@ +/** + * @providesModule A + * @flow + */ + +import type T from "T"; + +export default class { + p: T; + + constructor() { + this.p = 0; + } +} diff --git a/tests/annot2/B.js b/tests/annot2/B.js new file mode 100644 index 000000000000..823a7e8935ff --- /dev/null +++ b/tests/annot2/B.js @@ -0,0 +1,9 @@ +/** + * @flow + */ + +import A from "A" + +class B extends A { + p: string; // OK, string ~> any +} diff --git a/tests/annot2/T.js b/tests/annot2/T.js new file mode 100644 index 000000000000..d90bf5a54587 --- /dev/null +++ b/tests/annot2/T.js @@ -0,0 +1,3 @@ +/** + * @providesModule T + */ diff --git a/tests/annot2/__snapshots__/jsfmt.spec.js.snap b/tests/annot2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..dbc3d4a41a3c --- /dev/null +++ b/tests/annot2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,62 @@ +exports[`test A.js 1`] = ` +"/** + * @providesModule A + * @flow + */ + +import type T from "T"; + +export default class { + p: T; + + constructor() { + this.p = 0; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule A + * @flow + */ +import type T from "T"; +export default class { + p: T; + constructor() { + this.p = 0; + } +} + +" +`; + +exports[`test B.js 1`] = ` +"/** + * @flow + */ + +import A from "A" + +class B extends A { + p: string; // OK, string ~> any +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +import A from "A"; +class B extends A { + p: string;// OK, string ~> any +} + +" +`; + +exports[`test T.js 1`] = ` +"/** + * @providesModule T + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/annot2/jsfmt.spec.js b/tests/annot2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/annot2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/any/__snapshots__/jsfmt.spec.js.snap b/tests/any/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c15d72b9755c --- /dev/null +++ b/tests/any/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,202 @@ +exports[`test any.js 1`] = ` +"// @flow + +function foo(x:any):any { return x; } +function bar(x:any):mixed { return x; } +function qux(x:mixed):any { return x; } + +var x:string = foo(0); +var y:string = bar(0); +var z:string = qux(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function foo(x: any): any { + return x; +} +function bar(x: any): mixed { + return x; +} +function qux(x: mixed): any { + return x; +} +var x: string = foo(0); +var y: string = bar(0); +var z: string = qux(0); + +" +`; + +exports[`test anyexportflowfile.js 1`] = ` +"// @flow + +module.exports = ((x: any) => x: any); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +module.exports = ((x: any) => x: any); + +" +`; + +exports[`test flowfixme.js 1`] = ` +"/* + FlowFixMe is a synonym for any, used by the Flow team to + signal a needed mod to JS devs. + + @flow + */ + +// no param +function foo(x:$FlowFixMe):$FlowFixMe { return x; } +function bar(x:$FlowFixMe):mixed { return x; } +// param (info only) +function qux(x:$FlowFixMe):$FlowFixMe { return x; } +// ...params are still checked. unknown type +function baz(x:$FlowFixMe): $FlowFixMe { return x; } + +var x:string = foo(0); +var y:string = bar(0); +var z:string = qux(0); +var w:string = baz(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test flowissue.js 1`] = ` +"/* + $FlowIssue is a synonym for any, used by JS devs to signal + a potential typechecker bug to the Flow team. + + @flow + */ + +// no param +function foo(x:$FlowIssue):$FlowIssue { return x; } +function bar(x:$FlowIssue):mixed { return x; } +// param (info only) +function qux(x:$FlowIssue):$FlowIssue { return x; } +// ...params are still checked. unknown type +function baz(x:$FlowIssue): $FlowIssue { return x; } + +var x:string = foo(0); +var y:string = bar(0); +var z:string = qux(0); +var w:string = baz(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test nonflowfile.js 1`] = ` +"// @noflow + +module.exports = (x) => x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @noflow +module.exports = x => x; + +" +`; + +exports[`test propagate.js 1`] = ` +"// @flow + +declare class C { + bar(n1: number, n2: number): number; + bar(s1: string, s2: string): string; +} + +function foo(c: C, x: any): string { + let y = x.y; + return c.bar(0, y); // should be able to select first case and error +} + +var any_fun1 = require(\'./nonflowfile\'); +function bar1(x: mixed) { + if (any_fun1(x)) { + (x: boolean); + } +} + +var any_fun2 = require(\'./anyexportflowfile\'); +function bar2(x: mixed) { + if (any_fun2(x)) { + (x: boolean); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test reach.js 1`] = ` +"/** + * like class and function values, any-typed values may be used in + * type annotations. Here we test propagation of any through the + * annotation - without it, the body of the if will be unreachable + */ + +type AsyncRequest = any; + +function foo(o: ?AsyncRequest) { + if (o) { + var n: number = o; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * like class and function values, any-typed values may be used in + * type annotations. Here we test propagation of any through the + * annotation - without it, the body of the if will be unreachable + */ +type AsyncRequest = any; +function foo(o: ?AsyncRequest) { + if (o) { + var n: number = o; + } +} + +" +`; diff --git a/tests/any/any.js b/tests/any/any.js new file mode 100644 index 000000000000..6f5bf81494d7 --- /dev/null +++ b/tests/any/any.js @@ -0,0 +1,9 @@ +// @flow + +function foo(x:any):any { return x; } +function bar(x:any):mixed { return x; } +function qux(x:mixed):any { return x; } + +var x:string = foo(0); +var y:string = bar(0); +var z:string = qux(0); diff --git a/tests/any/anyexportflowfile.js b/tests/any/anyexportflowfile.js new file mode 100644 index 000000000000..61671d18a14e --- /dev/null +++ b/tests/any/anyexportflowfile.js @@ -0,0 +1,3 @@ +// @flow + +module.exports = ((x: any) => x: any); diff --git a/tests/any/flowfixme.js b/tests/any/flowfixme.js new file mode 100644 index 000000000000..bb3886027a77 --- /dev/null +++ b/tests/any/flowfixme.js @@ -0,0 +1,19 @@ +/* + FlowFixMe is a synonym for any, used by the Flow team to + signal a needed mod to JS devs. + + @flow + */ + +// no param +function foo(x:$FlowFixMe):$FlowFixMe { return x; } +function bar(x:$FlowFixMe):mixed { return x; } +// param (info only) +function qux(x:$FlowFixMe):$FlowFixMe { return x; } +// ...params are still checked. unknown type +function baz(x:$FlowFixMe): $FlowFixMe { return x; } + +var x:string = foo(0); +var y:string = bar(0); +var z:string = qux(0); +var w:string = baz(0); diff --git a/tests/any/flowissue.js b/tests/any/flowissue.js new file mode 100644 index 000000000000..2fbd2f280369 --- /dev/null +++ b/tests/any/flowissue.js @@ -0,0 +1,19 @@ +/* + $FlowIssue is a synonym for any, used by JS devs to signal + a potential typechecker bug to the Flow team. + + @flow + */ + +// no param +function foo(x:$FlowIssue):$FlowIssue { return x; } +function bar(x:$FlowIssue):mixed { return x; } +// param (info only) +function qux(x:$FlowIssue):$FlowIssue { return x; } +// ...params are still checked. unknown type +function baz(x:$FlowIssue): $FlowIssue { return x; } + +var x:string = foo(0); +var y:string = bar(0); +var z:string = qux(0); +var w:string = baz(0); diff --git a/tests/any/jsfmt.spec.js b/tests/any/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/any/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/any/nonflowfile.js b/tests/any/nonflowfile.js new file mode 100644 index 000000000000..f03c2cd668ba --- /dev/null +++ b/tests/any/nonflowfile.js @@ -0,0 +1,3 @@ +// @noflow + +module.exports = (x) => x; diff --git a/tests/any/propagate.js b/tests/any/propagate.js new file mode 100644 index 000000000000..1e073c54d2cf --- /dev/null +++ b/tests/any/propagate.js @@ -0,0 +1,25 @@ +// @flow + +declare class C { + bar(n1: number, n2: number): number; + bar(s1: string, s2: string): string; +} + +function foo(c: C, x: any): string { + let y = x.y; + return c.bar(0, y); // should be able to select first case and error +} + +var any_fun1 = require('./nonflowfile'); +function bar1(x: mixed) { + if (any_fun1(x)) { + (x: boolean); + } +} + +var any_fun2 = require('./anyexportflowfile'); +function bar2(x: mixed) { + if (any_fun2(x)) { + (x: boolean); + } +} diff --git a/tests/any/reach.js b/tests/any/reach.js new file mode 100644 index 000000000000..ec1232f6b989 --- /dev/null +++ b/tests/any/reach.js @@ -0,0 +1,13 @@ +/** + * like class and function values, any-typed values may be used in + * type annotations. Here we test propagation of any through the + * annotation - without it, the body of the if will be unreachable + */ + +type AsyncRequest = any; + +function foo(o: ?AsyncRequest) { + if (o) { + var n: number = o; + } +} diff --git a/tests/arith/Arith.js b/tests/arith/Arith.js new file mode 100644 index 000000000000..818619d805bd --- /dev/null +++ b/tests/arith/Arith.js @@ -0,0 +1,91 @@ + +/* @providesModule Arith */ + +function num(x:number) { } + +function str(x:string) { } + +function foo() { + var x = 0; + var y = "..."; + var z = {}; + num(x+x); + num(x+y); // error + str(x+y); + str(x+x); // error + str(z+y); // error +} + +// test MaybeT(NumT) +function bar0(x: ?number, y: number) { + num(x + y); +} +function bar1(x: number, y: ?number) { + num(x + y); +} + +// test OptionalT(NumT) +function bar2(x?: number, y: number) { + num(x + y); +} +function bar3(x: number, y?: number) { + num(x + y); +} + +// test OptionalT(MaybeT(NumT)) +function bar4(x?: ?number, y: number) { + num(x + y); +} +function bar5(x: number, y?: ?number) { + num(x + y); +} + +num(null + null); // === 0 +num(undefined + undefined); // === NaN + +num(null + 1); // === 1 +num(1 + null); // === 1 +num(undefined + 1); // === NaN +num(1 + undefined); // === NaN + +num(null + true); // === 1 +num(true + null); // === 1 +num(undefined + true); // === NaN +num(true + undefined); // === NaN + +str("foo" + true); // error +str(true + "foo"); // error +str("foo" + null); // error +str(null + "foo"); // error +str("foo" + undefined); // error +str(undefined + "foo"); // error + +let tests = [ + function(x: mixed, y: mixed) { + (x + y); // error + (x + 0); // error + (0 + x); // error + (x + ""); // error + ("" + x); // error + (x + {}); // error + ({} + x); // error + }, + + // when one side is a string or number and the other is invalid, we + // assume you are expecting a string or number (respectively), rather than + // erroring twice saying number !~> string and obj !~> string. + function() { + ((1 + {}): number); // error: object !~> number + (({} + 1): number); // error: object !~> number + (("1" + {}): string); // error: object !~> string + (({} + "1"): string); // error: object !~> string + }, + + function(x: any, y: number, z: string) { + (x + y: string); // ok + (y + x: string); // ok + + (x + z: empty); // error, string ~> empty + (z + x: empty); // error, string ~> empty + }, +]; diff --git a/tests/arith/__snapshots__/jsfmt.spec.js.snap b/tests/arith/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..22d3fa7b2599 --- /dev/null +++ b/tests/arith/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,318 @@ +exports[`test Arith.js 1`] = ` +" +/* @providesModule Arith */ + +function num(x:number) { } + +function str(x:string) { } + +function foo() { + var x = 0; + var y = \"...\"; + var z = {}; + num(x+x); + num(x+y); // error + str(x+y); + str(x+x); // error + str(z+y); // error +} + +// test MaybeT(NumT) +function bar0(x: ?number, y: number) { + num(x + y); +} +function bar1(x: number, y: ?number) { + num(x + y); +} + +// test OptionalT(NumT) +function bar2(x?: number, y: number) { + num(x + y); +} +function bar3(x: number, y?: number) { + num(x + y); +} + +// test OptionalT(MaybeT(NumT)) +function bar4(x?: ?number, y: number) { + num(x + y); +} +function bar5(x: number, y?: ?number) { + num(x + y); +} + +num(null + null); // === 0 +num(undefined + undefined); // === NaN + +num(null + 1); // === 1 +num(1 + null); // === 1 +num(undefined + 1); // === NaN +num(1 + undefined); // === NaN + +num(null + true); // === 1 +num(true + null); // === 1 +num(undefined + true); // === NaN +num(true + undefined); // === NaN + +str(\"foo\" + true); // error +str(true + \"foo\"); // error +str(\"foo\" + null); // error +str(null + \"foo\"); // error +str(\"foo\" + undefined); // error +str(undefined + \"foo\"); // error + +let tests = [ + function(x: mixed, y: mixed) { + (x + y); // error + (x + 0); // error + (0 + x); // error + (x + \"\"); // error + (\"\" + x); // error + (x + {}); // error + ({} + x); // error + }, + + // when one side is a string or number and the other is invalid, we + // assume you are expecting a string or number (respectively), rather than + // erroring twice saying number !~> string and obj !~> string. + function() { + ((1 + {}): number); // error: object !~> number + (({} + 1): number); // error: object !~> number + ((\"1\" + {}): string); // error: object !~> string + (({} + \"1\"): string); // error: object !~> string + }, + + function(x: any, y: number, z: string) { + (x + y: string); // ok + (y + x: string); // ok + + (x + z: empty); // error, string ~> empty + (z + x: empty); // error, string ~> empty + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Arith */ +function num(x: number) { + +} +function str(x: string) { + +} +function foo() { + var x = 0; + var y = \"...\"; + var z = {}; + num(x + x); + num(x + y);// error + str(x + y); + str(x + x);// error + str(z + y);// error +} +// test MaybeT(NumT) +function bar0(x: ?number, y: number) { + num(x + y); +} +function bar1(x: number, y: ?number) { + num(x + y); +} +// test OptionalT(NumT) +function bar2(x: number, y: number) { + num(x + y); +} +function bar3(x: number, y: number) { + num(x + y); +} +// test OptionalT(MaybeT(NumT)) +function bar4(x: ?number, y: number) { + num(x + y); +} +function bar5(x: number, y: ?number) { + num(x + y); +} +num(null + null);// === 0 +num(undefined + undefined);// === NaN +num(null + 1);// === 1 +num(1 + null);// === 1 +num(undefined + 1);// === NaN +num(1 + undefined);// === NaN +num(null + true);// === 1 +num(true + null);// === 1 +num(undefined + true);// === NaN +num(true + undefined);// === NaN +str(\"foo\" + true);// error +str(true + \"foo\");// error +str(\"foo\" + null);// error +str(null + \"foo\");// error +str(\"foo\" + undefined);// error +str(undefined + \"foo\");// error +let tests = [ + function(x: mixed, y: mixed) { + x + y;// error + x + 0;// error + 0 + x;// error + x + \"\";// error + \"\" + x;// error + x + {};// error + ({}) + x;// error + }, + // when one side is a string or number and the other is invalid, we + // assume you are expecting a string or number (respectively), rather than + // erroring twice saying number !~> string and obj !~> string. + function() { + (1 + {}: number);// error: object !~> number + ({} + 1: number);// error: object !~> number + (\"1\" + {}: string);// error: object !~> string + ({} + \"1\": string);// error: object !~> string + }, + function(x: any, y: number, z: string) { + (x + y: string);// ok + (y + x: string);// ok + (x + z: empty);// error, string ~> empty + (z + x: empty);// error, string ~> empty + } +]; + +" +`; + +exports[`test exponent.js 1`] = ` +"/* @flow */ + +let x: number = 2 ** 3; +x **= 4; + +let y: string = \"123\"; +y **= 2; // error + +1 + 2 ** 3 + 4; +2 ** 2; +(-2) ** 2; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +let x: number = 2 ** 3; +x **= 4; +let y: string = \"123\"; +y **= 2;// error +1 + 2 ** 3 + 4; +2 ** 2; +-2 ** 2; + +" +`; + +exports[`test generic.js 1`] = ` +"/* @flow */ + +function f(a: A): A { return a + a; } // error +function f(a: A, b: B): A {return a + b; } // error +function f(a: A, b: B): A {return b + a; } // error +function f(a: A, b: B): B {return a + b; } // error +function f(a: A, b: B): B {return b + a; } // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test mult.js 1`] = ` +"/* @flow */ + +function num(x:number) { } + +num(null * 1); +num(1 * null); + +let x: number = 2 * 3; +x *= 4; + +let y: string = \"123\"; +y *= 2; // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function num(x: number) { + +} +num(null * 1); +num(1 * null); +let x: number = 2 * 3; +x *= 4; +let y: string = \"123\"; +y *= 2;// error + +" +`; + +exports[`test relational.js 1`] = ` +"/* @flow */ + +(1 < 2); +(1 < \"foo\"); // error +(\"foo\" < 1); // error +(\"foo\" < \"bar\"); +(1 < {foo: 1}); // error +({foo: 1} < 1); // error +({foo: 1} < {foo: 1}); // error +(\"foo\" < {foo: 1}); // error +({foo: 1} < \"foo\"); // error + +var x = (null : ?number); +(1 < x); // 2 errors: null !~> number; undefined !~> number +(x < 1); // 2 errors: null !~> number; undefined !~> number + +(null < null); // error +(undefined < null); // error +(null < undefined); // error +(undefined < undefined); // error +(NaN < 1); +(1 < NaN); +(NaN < NaN); + +let tests = [ + function(x: any, y: number, z: string) { + (x > y); + (x > z); + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +1 < 2; +1 < \"foo\";// error +\"foo\" < 1;// error +\"foo\" < \"bar\"; +1 < { foo: 1 };// error +({ foo: 1 }) < 1;// error +({ foo: 1 }) < { foo: 1 };// error +\"foo\" < { foo: 1 };// error +({ foo: 1 }) < \"foo\";// error +var x = (null: ?number); +1 < x;// 2 errors: null !~> number; undefined !~> number +x < 1;// 2 errors: null !~> number; undefined !~> number +null < null;// error +undefined < null;// error +null < undefined;// error +undefined < undefined;// error +NaN < 1; +1 < NaN; +NaN < NaN; +let tests = [ + function(x: any, y: number, z: string) { + x > y; + x > z; + } +]; + +" +`; diff --git a/tests/arith/exponent.js b/tests/arith/exponent.js new file mode 100644 index 000000000000..2bac6484428a --- /dev/null +++ b/tests/arith/exponent.js @@ -0,0 +1,11 @@ +/* @flow */ + +let x: number = 2 ** 3; +x **= 4; + +let y: string = "123"; +y **= 2; // error + +1 + 2 ** 3 + 4; +2 ** 2; +(-2) ** 2; diff --git a/tests/arith/generic.js b/tests/arith/generic.js new file mode 100644 index 000000000000..217c990ecb2e --- /dev/null +++ b/tests/arith/generic.js @@ -0,0 +1,7 @@ +/* @flow */ + +function f(a: A): A { return a + a; } // error +function f(a: A, b: B): A {return a + b; } // error +function f(a: A, b: B): A {return b + a; } // error +function f(a: A, b: B): B {return a + b; } // error +function f(a: A, b: B): B {return b + a; } // error diff --git a/tests/arith/jsfmt.spec.js b/tests/arith/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/arith/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/arith/mult.js b/tests/arith/mult.js new file mode 100644 index 000000000000..43620ffbc80c --- /dev/null +++ b/tests/arith/mult.js @@ -0,0 +1,12 @@ +/* @flow */ + +function num(x:number) { } + +num(null * 1); +num(1 * null); + +let x: number = 2 * 3; +x *= 4; + +let y: string = "123"; +y *= 2; // error diff --git a/tests/arith/relational.js b/tests/arith/relational.js new file mode 100644 index 000000000000..f86edee6953e --- /dev/null +++ b/tests/arith/relational.js @@ -0,0 +1,30 @@ +/* @flow */ + +(1 < 2); +(1 < "foo"); // error +("foo" < 1); // error +("foo" < "bar"); +(1 < {foo: 1}); // error +({foo: 1} < 1); // error +({foo: 1} < {foo: 1}); // error +("foo" < {foo: 1}); // error +({foo: 1} < "foo"); // error + +var x = (null : ?number); +(1 < x); // 2 errors: null !~> number; undefined !~> number +(x < 1); // 2 errors: null !~> number; undefined !~> number + +(null < null); // error +(undefined < null); // error +(null < undefined); // error +(undefined < undefined); // error +(NaN < 1); +(1 < NaN); +(NaN < NaN); + +let tests = [ + function(x: any, y: number, z: string) { + (x > y); + (x > z); + }, +]; diff --git a/tests/array-filter/__snapshots__/jsfmt.spec.js.snap b/tests/array-filter/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bd957a9257f6 --- /dev/null +++ b/tests/array-filter/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,63 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +function filterOutVoids (arr: Array): Array { + return arr.filter(Boolean) +} + +function filterOutSmall (arr: Array): Array { + return arr.filter(num => num && num > 10) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"/* @flow */ + +function filterItems(items: Array): Array { + return items.map(item => { + if (typeof item === \'string\') { + return item.length > 2 ? item : null; + } else { + return item*10; + } + }).filter(Boolean); +} + +const filteredItems = filterItems([\'foo\', \'b\', 1, 2]); + +console.log(filteredItems); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/array-filter/jsfmt.spec.js b/tests/array-filter/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/array-filter/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/array-filter/test.js b/tests/array-filter/test.js new file mode 100644 index 000000000000..9dc5b1096fd7 --- /dev/null +++ b/tests/array-filter/test.js @@ -0,0 +1,9 @@ +/* @flow */ + +function filterOutVoids (arr: Array): Array { + return arr.filter(Boolean) +} + +function filterOutSmall (arr: Array): Array { + return arr.filter(num => num && num > 10) +} diff --git a/tests/array-filter/test2.js b/tests/array-filter/test2.js new file mode 100644 index 000000000000..a51043419dfd --- /dev/null +++ b/tests/array-filter/test2.js @@ -0,0 +1,15 @@ +/* @flow */ + +function filterItems(items: Array): Array { + return items.map(item => { + if (typeof item === 'string') { + return item.length > 2 ? item : null; + } else { + return item*10; + } + }).filter(Boolean); +} + +const filteredItems = filterItems(['foo', 'b', 1, 2]); + +console.log(filteredItems); diff --git a/tests/array_spread/__snapshots__/jsfmt.spec.js.snap b/tests/array_spread/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d761c1fb2b0e --- /dev/null +++ b/tests/array_spread/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test test.js 1`] = ` +"var A = [1,2,3]; +var B = [...A]; +var C = [1,2,3]; +B.sort((a, b) => a - b); +C.sort((a, b) => a - b); + +var x: Array = [\'1\', \'2\']; +var y: Array = [\'3\', ...x]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/array_spread/jsfmt.spec.js b/tests/array_spread/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/array_spread/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/array_spread/test.js b/tests/array_spread/test.js new file mode 100644 index 000000000000..73789d89ad35 --- /dev/null +++ b/tests/array_spread/test.js @@ -0,0 +1,8 @@ +var A = [1,2,3]; +var B = [...A]; +var C = [1,2,3]; +B.sort((a, b) => a - b); +C.sort((a, b) => a - b); + +var x: Array = ['1', '2']; +var y: Array = ['3', ...x]; diff --git a/tests/arraylib/__snapshots__/jsfmt.spec.js.snap b/tests/arraylib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..22c7fb2420eb --- /dev/null +++ b/tests/arraylib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,76 @@ +exports[`test array_lib.js 1`] = ` +"/* @flow */ +function foo(x:string) { } + +var a = [0]; +var b = a.map(function (x) { foo(x); return \"\" + x; }); + +var c: number = a[0]; +var d: number = b[0]; + +var e:Array = a.reverse(); + +var f = [\"\"]; +var g:number = f.map(function () { return 0; })[0]; + +var h: Array = [1,2,3]; +var i: Array = [\'a\', \'b\', \'c\']; +var j: Array = h.concat(i); +var k: Array = h.concat(h); +var l: Array = h.concat(1,2,3); +var m: Array = h.concat(\'a\', \'b\', \'c\'); +var n: Array = h.concat(\'a\', \'b\', \'c\'); // Error + +function reduce_test() { + /* Adapted from the following source: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce + */ + [0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) { + return previousValue + currentValue + array[index]; + }); + + [0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) { + return previousValue + currentValue + array[index]; + }, 10); + + var total = [0, 1, 2, 3].reduce(function(a, b) { + return a + b; + }); + + var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) { + return a.concat(b); + }); + + /* Added later, because the above is insufficient */ + + // acc is element type of array when no init is provided + [\"\"].reduce((acc, str) => acc * str.length); // error, string ~> number + [\"\"].reduceRight((acc, str) => acc * str.length); // error, string ~> number +} + +function from_test() { + var a: Array = Array.from([1, 2, 3], function(val, index) { + return index % 2 ? \"foo\" : String(val); + }); + var b: Array = Array.from([1, 2, 3], function(val) { + return String(val); + }); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/arraylib/array_lib.js b/tests/arraylib/array_lib.js new file mode 100644 index 000000000000..6db0cbc2d025 --- /dev/null +++ b/tests/arraylib/array_lib.js @@ -0,0 +1,57 @@ +/* @flow */ +function foo(x:string) { } + +var a = [0]; +var b = a.map(function (x) { foo(x); return "" + x; }); + +var c: number = a[0]; +var d: number = b[0]; + +var e:Array = a.reverse(); + +var f = [""]; +var g:number = f.map(function () { return 0; })[0]; + +var h: Array = [1,2,3]; +var i: Array = ['a', 'b', 'c']; +var j: Array = h.concat(i); +var k: Array = h.concat(h); +var l: Array = h.concat(1,2,3); +var m: Array = h.concat('a', 'b', 'c'); +var n: Array = h.concat('a', 'b', 'c'); // Error + +function reduce_test() { + /* Adapted from the following source: + * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce + */ + [0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) { + return previousValue + currentValue + array[index]; + }); + + [0, 1, 2, 3, 4].reduce(function(previousValue, currentValue, index, array) { + return previousValue + currentValue + array[index]; + }, 10); + + var total = [0, 1, 2, 3].reduce(function(a, b) { + return a + b; + }); + + var flattened = [[0, 1], [2, 3], [4, 5]].reduce(function(a, b) { + return a.concat(b); + }); + + /* Added later, because the above is insufficient */ + + // acc is element type of array when no init is provided + [""].reduce((acc, str) => acc * str.length); // error, string ~> number + [""].reduceRight((acc, str) => acc * str.length); // error, string ~> number +} + +function from_test() { + var a: Array = Array.from([1, 2, 3], function(val, index) { + return index % 2 ? "foo" : String(val); + }); + var b: Array = Array.from([1, 2, 3], function(val) { + return String(val); + }); +} diff --git a/tests/arraylib/jsfmt.spec.js b/tests/arraylib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/arraylib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/arrays/Arrays.js b/tests/arrays/Arrays.js new file mode 100644 index 000000000000..cc3cd2f6956d --- /dev/null +++ b/tests/arrays/Arrays.js @@ -0,0 +1,39 @@ + +/* @providesModule Arrays */ + +function foo(x:string) { } + +var a = []; +a[0] = 1; +a[1] = "..."; + +foo(a[1]); +var y; +a.forEach(x => y=x); + +// for literals, composite element type is union of individuals +// note: test both tuple and non-tuple inferred literals +var alittle: Array = [0, 1, 2, 3, null]; +var abig: Array = [0, 1, 2, 3, 4, 5, 6, 8, null]; + +var abig2: Array<{x:number; y:number}> = [ + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0, a:true}, + {x:0, y:0, b:"hey"}, + {x:0, y:0, c:1}, + {x:0, y:0, c:"hey"} +]; + +module.exports = "arrays"; diff --git a/tests/arrays/__snapshots__/jsfmt.spec.js.snap b/tests/arrays/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e2440d0d381c --- /dev/null +++ b/tests/arrays/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,77 @@ +exports[`test Arrays.js 1`] = ` +" +/* @providesModule Arrays */ + +function foo(x:string) { } + +var a = []; +a[0] = 1; +a[1] = \"...\"; + +foo(a[1]); +var y; +a.forEach(x => y=x); + +// for literals, composite element type is union of individuals +// note: test both tuple and non-tuple inferred literals +var alittle: Array = [0, 1, 2, 3, null]; +var abig: Array = [0, 1, 2, 3, 4, 5, 6, 8, null]; + +var abig2: Array<{x:number; y:number}> = [ + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0}, + {x:0, y:0, a:true}, + {x:0, y:0, b:\"hey\"}, + {x:0, y:0, c:1}, + {x:0, y:0, c:\"hey\"} +]; + +module.exports = \"arrays\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test numeric_elem.js 1`] = ` +"var arr = []; +var day = new Date; + +// Date instances are numeric (see Flow_js.numeric) and thus can index into +// arrays. +arr[day] = 0; +(arr[day]: string); // error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var arr = [ ]; +var day = new Date(); +// Date instances are numeric (see Flow_js.numeric) and thus can index into +// arrays. +arr[day] = 0; +(arr[day]: string);// error: number ~> string + +" +`; diff --git a/tests/arrays/jsfmt.spec.js b/tests/arrays/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/arrays/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/arrays/numeric_elem.js b/tests/arrays/numeric_elem.js new file mode 100644 index 000000000000..afdffa392b14 --- /dev/null +++ b/tests/arrays/numeric_elem.js @@ -0,0 +1,7 @@ +var arr = []; +var day = new Date; + +// Date instances are numeric (see Flow_js.numeric) and thus can index into +// arrays. +arr[day] = 0; +(arr[day]: string); // error: number ~> string diff --git a/tests/arrows/__snapshots__/jsfmt.spec.js.snap b/tests/arrows/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c62df90c14c6 --- /dev/null +++ b/tests/arrows/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,60 @@ +exports[`test advanced_arrows.js 1`] = ` +"/** + * @flow + */ + +var add = (x: number, y: number): number => x + y; + +var bad = (x: number): string => x; // Error! + +var ident = (x: T): T => x; +(ident(1): number); +(ident(\"hi\"): number); // Error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:367:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test arrows.js 1`] = ` +"function selectBestEffortImageForWidth( + maxWidth: number, + images: Array +): Image { + var maxPixelWidth = maxWidth; + //images = images.sort(function (a, b) { return a.width - b.width }); + images = images.sort((a, b) => (a.width - b.width) + \"\"); + return images.find(image => image.width >= maxPixelWidth) || + images[images.length - 1]; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/arrows/advanced_arrows.js b/tests/arrows/advanced_arrows.js new file mode 100644 index 000000000000..010ca4c71a77 --- /dev/null +++ b/tests/arrows/advanced_arrows.js @@ -0,0 +1,11 @@ +/** + * @flow + */ + +var add = (x: number, y: number): number => x + y; + +var bad = (x: number): string => x; // Error! + +var ident = (x: T): T => x; +(ident(1): number); +(ident("hi"): number); // Error diff --git a/tests/arrows/arrows.js b/tests/arrows/arrows.js new file mode 100644 index 000000000000..f25cc0fb3c40 --- /dev/null +++ b/tests/arrows/arrows.js @@ -0,0 +1,10 @@ +function selectBestEffortImageForWidth( + maxWidth: number, + images: Array +): Image { + var maxPixelWidth = maxWidth; + //images = images.sort(function (a, b) { return a.width - b.width }); + images = images.sort((a, b) => (a.width - b.width) + ""); + return images.find(image => image.width >= maxPixelWidth) || + images[images.length - 1]; +} diff --git a/tests/arrows/jsfmt.spec.js b/tests/arrows/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/arrows/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/ast_tokens/__snapshots__/jsfmt.spec.js.snap b/tests/ast_tokens/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a4b93d5aafe9 --- /dev/null +++ b/tests/ast_tokens/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,34 @@ +exports[`test foo.js 1`] = ` +"// Regex literals require a lexer mode change +/asdf/g; + +// JSX also requires a lexer mode change +
asdf
; + +// Async arrow functions require backtracking +var a = async () => 42; + +// Type annotations have a special lex mode +var a: number = 42; + +// Token stream should continue even with parse errors +var var +a; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (14:4) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$2.parseBindingAtom (/node_modules/babylon/lib/index.js:2929:12) + at Parser.pp$1.parseVarHead (/node_modules/babylon/lib/index.js:2226:18) + at Parser.parseVarHead (/node_modules/babylon/lib/index.js:5611:13) + at Parser.pp$1.parseVar (/node_modules/babylon/lib/index.js:2209:10) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2042:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) +" +`; diff --git a/tests/ast_tokens/foo.js b/tests/ast_tokens/foo.js new file mode 100644 index 000000000000..cca10855f7a7 --- /dev/null +++ b/tests/ast_tokens/foo.js @@ -0,0 +1,15 @@ +// Regex literals require a lexer mode change +/asdf/g; + +// JSX also requires a lexer mode change +
asdf
; + +// Async arrow functions require backtracking +var a = async () => 42; + +// Type annotations have a special lex mode +var a: number = 42; + +// Token stream should continue even with parse errors +var var +a; diff --git a/tests/ast_tokens/jsfmt.spec.js b/tests/ast_tokens/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/ast_tokens/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/async/__snapshots__/jsfmt.spec.js.snap b/tests/async/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a3c8cadc6de3 --- /dev/null +++ b/tests/async/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,471 @@ +exports[`test async.js 1`] = ` +"// @flow + +// \"For async functions, a Promise is returned, +// and the type of return expressions must be T.\" +// + +async function f0(): Promise { + return 1; +} + +async function f1(): Promise { + return 1; // error, number != bool +} + +// await: (p: Promise | T) => T +// + +async function f2(p: Promise): Promise { + var x: number = await p; + var y: number = await 1; + return x + y; +} + +async function f3(p: Promise): Promise { + return await p; +} + +// TODO: this is one of those bad generic errors, currently: +// \"inconsistent use of library definitions\" with two core.js locs +async function f4(p: Promise): Promise { + return await p; // error, number != bool +} + +// async arrow functions +// + +var f5: () => Promise = async () => await 1; + +// async methods +// + +class C { + async m() { return 1; } + async mt(a: T): Promise { return a; } + static async m(a): void { await a; } // error, void != Promise + static async mt(a: T): Promise { return a; } +} + +// async function props + +var obj = { f: async () => await 1 }; +var objf : () => Promise = obj.f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test async_base_class.js 1`] = ` +"// This is kind of weird, but it should parse. This works in babel without the +// parens around (await promise). From the es6 and async/await specs I (nmote) +// am not clear on whether it should. In any case it\'s a strange corner case +// that is probably not important to support. +class C {}; + +var P: Promise> = new Promise(function (resolve, reject) { + resolve(C); +}); + +async function foo() { + class Bar extends (await P) { } + return Bar; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test async_parse.js 1`] = ` +"async function f() {} +async function ft(a: T) {} + +class C { + async m() {} + async mt(a: T) {} + static async m(a) {} + static async mt(a: T) {} +} + +var e = async function () {}; +var et = async function (a: T) {}; + +var n = new async function() {}; + +var o = { async m() {} }; +var ot = { async m(a: T) {} }; +var oz = { async async() {} }; + +var x = { async : 5 }; +console.log(x.async); + +var async = 3; +var y = { async }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test async_promise.js 1`] = ` +"async function f(): Promise { + return Promise.resolve(1); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test async_return_void.js 1`] = ` +"// @flow + +async function foo1(): Promise { + return; +} + +async function foo2(): Promise { + return undefined; +} + +async function foo3(): Promise { + function bar() { } + return bar(); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test async2.js 1`] = ` +"// @flow + +// misc basic + +function test1() { + async function foo() { + return 42; + } + + async function bar() { + var a = await foo(); + var b: number = a; // valid + var c: string = a; // Error: number ~> string + } +} + +// +// void returns: +// + +// inference should produce return type Promise +// in the absence of an explicit return +// + +function test2() { + async function voidoid1() { + console.log(\"HEY\"); + } + + var voidoid2: () => Promise = voidoid1; // ok + + var voidoid3: () => void = voidoid1; // error, void != Promise +} + +// annotated return type of Promise should work +// + +function test3() { + async function voidoid4(): Promise { // ok + console.log(\"HEY\"); + } +} + +// other annotated return types should fail +// (note: misannotated return types with explicit +// return statements are covered in async.js) +// + +function test4() { + async function voidoid5(): void { // error, void != Promise + console.log(\"HEY\"); + } +} + +function test5() { + async function voidoid6() + : Promise { // error, number != void + console.log(\"HEY\"); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test async3.js 1`] = ` +"// @flow + +/** + * test nested-promise unwrapping. + * Note: currently we don\'t do this properly in the underlying + * type of the Promise class, which causes spurious errors to + * be raised here. Once that\'s fixed, the errors here will go + * away. + */ + +async function foo() { + return 42; +} + +async function bar() { + return foo(); +} + +async function baz() { + + // a should now be typed as number, but is in fact + // Promise until nested-promise unwrap is fixed + var a = await bar(); + + // TODO this is valid code, but currently gives Promise ~> number error + // due to lack of transitive Promise unwrap. + var b: number = a; + + // should be number ~> string error, but currently gives + // Promise ~> string error for the same reason + var c: string = a; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +/** + * test nested-promise unwrapping. + * Note: currently we don\'t do this properly in the underlying + * type of the Promise class, which causes spurious errors to + * be raised here. Once that\'s fixed, the errors here will go + * away. + */ +async function foo() { + return 42; +} +async function bar() { + return foo(); +} +async function baz() { + // a should now be typed as number, but is in fact + // Promise until nested-promise unwrap is fixed + var a = await bar(); + // TODO this is valid code, but currently gives Promise ~> number error + // due to lack of transitive Promise unwrap. + var b: number = a; + // should be number ~> string error, but currently gives + // Promise ~> string error for the same reason + var c: string = a; +} + +" +`; + +exports[`test await_not_in_async.js 1`] = ` +"// note: currently, await-within-async enforcement is a +// done by the parser, which bails after a single error. + +function f() { + await 1; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: await is a reserved word (5:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$3.checkReservedWord (/node_modules/babylon/lib/index.js:4143:10) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4121:12) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3490:21) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) +" +`; + +exports[`test await_not_in_async2.js 1`] = ` +"// note: currently, await-within-async enforcement is a +// done by the parser, which bails after a single error. + +function f(x) { return x; } + +f(await 1); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: await is a reserved word (6:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$3.checkReservedWord (/node_modules/babylon/lib/index.js:4143:10) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4121:12) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3490:21) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) +" +`; + +exports[`test await_not_in_async3.js 1`] = ` +"// note: currently, await-within-async enforcement is a +// done by the parser, which bails after a single error. + +async function f(x) { return x; } + +f(await 1); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: await is a reserved word (6:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$3.checkReservedWord (/node_modules/babylon/lib/index.js:4143:10) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4121:12) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3490:21) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) +" +`; + +exports[`test await_parse.js 1`] = ` +"async function f() { await 1; } +async function ft(a: T) { await 1; } + +class C { + async m() { await 1; } + async mt(a: T) { await 1; } + static async m(a) { await 1; } + static async mt(a: T) { await 1; } +} + +var e = async function () { await 1; }; +var et = async function (a: T) { await 1; }; + +var n = new async function() { await 1; }; + +var o = { async m() { await 1; } }; +var ot = { async m(a: T) { await 1; } }; +var oz = { async async(async) { await async; } }; + +var x = { await : 5 }; +console.log(x.await); + +var await = 3; +var y = { await }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: await is a reserved word (23:4) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$3.checkReservedWord (/node_modules/babylon/lib/index.js:4143:10) + at Parser.pp$2.checkLVal (/node_modules/babylon/lib/index.js:2990:12) + at Parser.checkLVal (/node_modules/babylon/lib/index.js:5446:22) + at Parser.pp$1.parseVarHead (/node_modules/babylon/lib/index.js:2227:8) + at Parser.parseVarHead (/node_modules/babylon/lib/index.js:5611:13) + at Parser.pp$1.parseVar (/node_modules/babylon/lib/index.js:2209:10) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2042:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) +" +`; diff --git a/tests/async/async.js b/tests/async/async.js new file mode 100644 index 000000000000..85d27b27b3a9 --- /dev/null +++ b/tests/async/async.js @@ -0,0 +1,52 @@ +// @flow + +// "For async functions, a Promise is returned, +// and the type of return expressions must be T." +// + +async function f0(): Promise { + return 1; +} + +async function f1(): Promise { + return 1; // error, number != bool +} + +// await: (p: Promise | T) => T +// + +async function f2(p: Promise): Promise { + var x: number = await p; + var y: number = await 1; + return x + y; +} + +async function f3(p: Promise): Promise { + return await p; +} + +// TODO: this is one of those bad generic errors, currently: +// "inconsistent use of library definitions" with two core.js locs +async function f4(p: Promise): Promise { + return await p; // error, number != bool +} + +// async arrow functions +// + +var f5: () => Promise = async () => await 1; + +// async methods +// + +class C { + async m() { return 1; } + async mt(a: T): Promise { return a; } + static async m(a): void { await a; } // error, void != Promise + static async mt(a: T): Promise { return a; } +} + +// async function props + +var obj = { f: async () => await 1 }; +var objf : () => Promise = obj.f; diff --git a/tests/async/async2.js b/tests/async/async2.js new file mode 100644 index 000000000000..79e69a7c1070 --- /dev/null +++ b/tests/async/async2.js @@ -0,0 +1,60 @@ +// @flow + +// misc basic + +function test1() { + async function foo() { + return 42; + } + + async function bar() { + var a = await foo(); + var b: number = a; // valid + var c: string = a; // Error: number ~> string + } +} + +// +// void returns: +// + +// inference should produce return type Promise +// in the absence of an explicit return +// + +function test2() { + async function voidoid1() { + console.log("HEY"); + } + + var voidoid2: () => Promise = voidoid1; // ok + + var voidoid3: () => void = voidoid1; // error, void != Promise +} + +// annotated return type of Promise should work +// + +function test3() { + async function voidoid4(): Promise { // ok + console.log("HEY"); + } +} + +// other annotated return types should fail +// (note: misannotated return types with explicit +// return statements are covered in async.js) +// + +function test4() { + async function voidoid5(): void { // error, void != Promise + console.log("HEY"); + } +} + +function test5() { + async function voidoid6() + : Promise { // error, number != void + console.log("HEY"); + } +} diff --git a/tests/async/async3.js b/tests/async/async3.js new file mode 100644 index 000000000000..d0062d5f21a7 --- /dev/null +++ b/tests/async/async3.js @@ -0,0 +1,32 @@ +// @flow + +/** + * test nested-promise unwrapping. + * Note: currently we don't do this properly in the underlying + * type of the Promise class, which causes spurious errors to + * be raised here. Once that's fixed, the errors here will go + * away. + */ + +async function foo() { + return 42; +} + +async function bar() { + return foo(); +} + +async function baz() { + + // a should now be typed as number, but is in fact + // Promise until nested-promise unwrap is fixed + var a = await bar(); + + // TODO this is valid code, but currently gives Promise ~> number error + // due to lack of transitive Promise unwrap. + var b: number = a; + + // should be number ~> string error, but currently gives + // Promise ~> string error for the same reason + var c: string = a; +} diff --git a/tests/async/async_base_class.js b/tests/async/async_base_class.js new file mode 100644 index 000000000000..de7afc58ec61 --- /dev/null +++ b/tests/async/async_base_class.js @@ -0,0 +1,14 @@ +// This is kind of weird, but it should parse. This works in babel without the +// parens around (await promise). From the es6 and async/await specs I (nmote) +// am not clear on whether it should. In any case it's a strange corner case +// that is probably not important to support. +class C {}; + +var P: Promise> = new Promise(function (resolve, reject) { + resolve(C); +}); + +async function foo() { + class Bar extends (await P) { } + return Bar; +} diff --git a/tests/async/async_parse.js b/tests/async/async_parse.js new file mode 100644 index 000000000000..e633ae4efc65 --- /dev/null +++ b/tests/async/async_parse.js @@ -0,0 +1,24 @@ +async function f() {} +async function ft(a: T) {} + +class C { + async m() {} + async mt(a: T) {} + static async m(a) {} + static async mt(a: T) {} +} + +var e = async function () {}; +var et = async function (a: T) {}; + +var n = new async function() {}; + +var o = { async m() {} }; +var ot = { async m(a: T) {} }; +var oz = { async async() {} }; + +var x = { async : 5 }; +console.log(x.async); + +var async = 3; +var y = { async }; diff --git a/tests/async/async_promise.js b/tests/async/async_promise.js new file mode 100644 index 000000000000..8c2ce87dbd42 --- /dev/null +++ b/tests/async/async_promise.js @@ -0,0 +1,3 @@ +async function f(): Promise { + return Promise.resolve(1); +} diff --git a/tests/async/async_return_void.js b/tests/async/async_return_void.js new file mode 100644 index 000000000000..1e312f63386e --- /dev/null +++ b/tests/async/async_return_void.js @@ -0,0 +1,14 @@ +// @flow + +async function foo1(): Promise { + return; +} + +async function foo2(): Promise { + return undefined; +} + +async function foo3(): Promise { + function bar() { } + return bar(); +} diff --git a/tests/async/await_not_in_async.js b/tests/async/await_not_in_async.js new file mode 100644 index 000000000000..cbcc4191ac41 --- /dev/null +++ b/tests/async/await_not_in_async.js @@ -0,0 +1,6 @@ +// note: currently, await-within-async enforcement is a +// done by the parser, which bails after a single error. + +function f() { + await 1; +} diff --git a/tests/async/await_not_in_async2.js b/tests/async/await_not_in_async2.js new file mode 100644 index 000000000000..0037d0905eb3 --- /dev/null +++ b/tests/async/await_not_in_async2.js @@ -0,0 +1,6 @@ +// note: currently, await-within-async enforcement is a +// done by the parser, which bails after a single error. + +function f(x) { return x; } + +f(await 1); diff --git a/tests/async/await_not_in_async3.js b/tests/async/await_not_in_async3.js new file mode 100644 index 000000000000..cacb5dc6749a --- /dev/null +++ b/tests/async/await_not_in_async3.js @@ -0,0 +1,6 @@ +// note: currently, await-within-async enforcement is a +// done by the parser, which bails after a single error. + +async function f(x) { return x; } + +f(await 1); diff --git a/tests/async/await_parse.js b/tests/async/await_parse.js new file mode 100644 index 000000000000..10149204ecd7 --- /dev/null +++ b/tests/async/await_parse.js @@ -0,0 +1,24 @@ +async function f() { await 1; } +async function ft(a: T) { await 1; } + +class C { + async m() { await 1; } + async mt(a: T) { await 1; } + static async m(a) { await 1; } + static async mt(a: T) { await 1; } +} + +var e = async function () { await 1; }; +var et = async function (a: T) { await 1; }; + +var n = new async function() { await 1; }; + +var o = { async m() { await 1; } }; +var ot = { async m(a: T) { await 1; } }; +var oz = { async async(async) { await async; } }; + +var x = { await : 5 }; +console.log(x.await); + +var await = 3; +var y = { await }; diff --git a/tests/async/jsfmt.spec.js b/tests/async/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/async/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap b/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a9bab4ede39d --- /dev/null +++ b/tests/async_iteration/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,213 @@ +exports[`test delegate_yield.js 1`] = ` +"async function *delegate_next() { + async function *inner() { + var x: void = yield; // error: number ~> void + } + yield *inner(); +} +delegate_next().next(0); + +async function *delegate_yield() { + async function *inner() { + yield 0; + } + yield *inner(); +} +(async () => { + for await (const x of delegate_yield()) { + (x: void); // error: number ~> void + } +}); + +async function *delegate_return() { + async function *inner() { + return 0; + } + var x: void = yield *inner(); // error: number ~> void +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +async function* delegate_next() { + async function* inner() { + var x: void = yield;// error: number ~> void + } + yield* inner(); +} +delegate_next().next(0); +async function* delegate_yield() { + async function* inner() { + yield 0; + } + yield* inner(); +} +async () => { + for await (const x of delegate_yield()) { + (x: void);// error: number ~> void + } +}; +async function* delegate_return() { + async function* inner() { + return 0; + } + var x: void = yield* inner();// error: number ~> void +} + +" +`; + +exports[`test generator.js 1`] = ` +"declare interface File { + readLine(): Promise; + close(): void; + EOF: boolean; +} + +declare function fileOpen(path: string): Promise; + +async function* readLines(path) { + let file: File = await fileOpen(path); + + try { + while (!file.EOF) { + yield await file.readLine(); + } + } finally { + file.close(); + } +} + +async function f() { + for await (const line of readLines(\"/path/to/file\")) { + (line: void); // error: string ~> void + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test return.js 1`] = ` +"declare var gen: AsyncGenerator; + +// You can pass whatever you like to return, it doesn\'t need to be related to +// the AsyncGenerator\'s return type +gen.return(0).then(result => { + (result.value: void); // error: string | number ~> void +}); + +// However, a generator can \"refuse\" the return by catching an exception and +// yielding or returning internally. +async function *refuse_return() { + try { + yield 1; + } finally { + return 0; + } +} +refuse_return().return(\"string\").then(result => { + if (result.done) { + (result.value: string); // error: number | void ~> string + } +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test throw.js 1`] = ` +"async function *catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} + +(async () => { + catch_return().throw(\"\").then(({value}) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}); + +async function *yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} + +(async () => { + yield_return().throw(\"\").then(({value}) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +async function* catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} +async () => { + catch_return().throw(\"\").then( + ({ value }) => { + if (value !== undefined) { + (value: void);// error: number ~> void + } + } + ); +}; +async function* yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} +async () => { + yield_return().throw(\"\").then( + ({ value }) => { + if (value !== undefined) { + (value: void);// error: number ~> void + } + } + ); +}; + +" +`; diff --git a/tests/async_iteration/delegate_yield.js b/tests/async_iteration/delegate_yield.js new file mode 100644 index 000000000000..965cfadfaea7 --- /dev/null +++ b/tests/async_iteration/delegate_yield.js @@ -0,0 +1,26 @@ +async function *delegate_next() { + async function *inner() { + var x: void = yield; // error: number ~> void + } + yield *inner(); +} +delegate_next().next(0); + +async function *delegate_yield() { + async function *inner() { + yield 0; + } + yield *inner(); +} +(async () => { + for await (const x of delegate_yield()) { + (x: void); // error: number ~> void + } +}); + +async function *delegate_return() { + async function *inner() { + return 0; + } + var x: void = yield *inner(); // error: number ~> void +} diff --git a/tests/async_iteration/generator.js b/tests/async_iteration/generator.js new file mode 100644 index 000000000000..76213a59f63d --- /dev/null +++ b/tests/async_iteration/generator.js @@ -0,0 +1,25 @@ +declare interface File { + readLine(): Promise; + close(): void; + EOF: boolean; +} + +declare function fileOpen(path: string): Promise; + +async function* readLines(path) { + let file: File = await fileOpen(path); + + try { + while (!file.EOF) { + yield await file.readLine(); + } + } finally { + file.close(); + } +} + +async function f() { + for await (const line of readLines("/path/to/file")) { + (line: void); // error: string ~> void + } +} diff --git a/tests/async_iteration/jsfmt.spec.js b/tests/async_iteration/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/async_iteration/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/async_iteration/return.js b/tests/async_iteration/return.js new file mode 100644 index 000000000000..28cbc3deb4c1 --- /dev/null +++ b/tests/async_iteration/return.js @@ -0,0 +1,22 @@ +declare var gen: AsyncGenerator; + +// You can pass whatever you like to return, it doesn't need to be related to +// the AsyncGenerator's return type +gen.return(0).then(result => { + (result.value: void); // error: string | number ~> void +}); + +// However, a generator can "refuse" the return by catching an exception and +// yielding or returning internally. +async function *refuse_return() { + try { + yield 1; + } finally { + return 0; + } +} +refuse_return().return("string").then(result => { + if (result.done) { + (result.value: string); // error: number | void ~> string + } +}); diff --git a/tests/async_iteration/throw.js b/tests/async_iteration/throw.js new file mode 100644 index 000000000000..ae6c629bbfa5 --- /dev/null +++ b/tests/async_iteration/throw.js @@ -0,0 +1,32 @@ +async function *catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} + +(async () => { + catch_return().throw("").then(({value}) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}); + +async function *yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} + +(async () => { + yield_return().throw("").then(({value}) => { + if (value !== undefined) { + (value: void); // error: number ~> void + } + }); +}); diff --git a/tests/autocomplete/__snapshots__/jsfmt.spec.js.snap b/tests/autocomplete/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8c4dbb8e1566 --- /dev/null +++ b/tests/autocomplete/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,582 @@ +exports[`test bar.js 1`] = ` +"// @flow + +var o = require(\'./unknown\'); +o.x. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test bool.js 1`] = ` +"// @flow + +true. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (4:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test customfun.js 1`] = ` +"// @flow + +declare var idx: $Facebookism$Idx; +declare var merge: $Facebookism$Merge; +declare var mergeDeepInto: $Facebookism$MergeDeepInto; +declare var mergeInto: $Facebookism$MergeInto; +declare var mixin: $Facebookism$Mixin; +declare var objectGetPrototypeOf: Object$GetPrototypeOf +declare var objectAssign: Object$Assign + +m +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +declare var idx: $Facebookism$Idx; +declare var merge: $Facebookism$Merge; +declare var mergeDeepInto: $Facebookism$MergeDeepInto; +declare var mergeInto: $Facebookism$MergeInto; +declare var mixin: $Facebookism$Mixin; +declare var objectGetPrototypeOf: Object$GetPrototypeOf; +declare var objectAssign: Object$Assign; +m; + +" +`; + +exports[`test foo.js 1`] = ` +"/** + * @flow + */ + +var obj = { + num: 123, + str: \'hello\', +}; + +obj. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (11:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test foo_parse_fail.js 1`] = ` +"/** + * @flow + */ + +var obj = { + num: 123, + str: \'hello\', +}; + +console.log(obj. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (11:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test fun.js 1`] = ` +"/* @flow */ + +function foo(f: () => number) { + f. +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test function_builtins.js 1`] = ` +"/* @flow */ + +function foo(f: Function) { + f. +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test generics.js 1`] = ` +"// @flow + +class C { } + +function foo(o: { cn: C }) { + o. +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (7:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test if.js 1`] = ` +"// @flow +const x = \'\'; +if (x.) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (3:6) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test issue-1368.js 1`] = ` +"/* @flow */ +class Test { + prop: number; + + constructor(prop: number) { + this.prop = prop; + } +} + +class ExtendTest extends Test { + extended: string; + + constructor(extended: string) { + super(10); + this.extended = extended; + } + + method() { + this.prop = 12; + this./* here */ + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (21:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test jsx1.js 1`] = ` +"// @flow + +var React = require(\'react\'); + +class C extends React.Component { + props: { x: number }; +} + void, o: { x?: string } }) { + return obj. +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test override.js 1`] = ` +"// @flow + +class C { + override(): number | string { return 0; } +} + +class D extends C { + foo() { return this.override() } + override(): string { return \"\"; } + bar() { this. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (11:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test qux.js 1`] = ` +"// @flow + +class C { x: number; } + +var c: C = new C; +c. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (7:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test str.js 1`] = ` +"// @flow + +\"hello\". +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (4:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test this.js 1`] = ` +"/* @flow */ + +// issue #1197 +class Foo { + baz: string; + bar() {} + hello() { + this. + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (9:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test typeparams.js 1`] = ` +"// @flow + +class Bounds N> { + foo: F; + bar() { + this.foo(). + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (7:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test union.js 1`] = ` +"/* @flow */ + +function foo(a: boolean, x: { bar: string }, y: Object) { + var z; + if (a) { + z = x; + } else { + z = y; + } + z. +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (11:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseSubscripts (/node_modules/babylon/lib/index.js:3360:30) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3347:15) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test unknown.js 1`] = ` +"// @noflow +module.exports = { x: { y: \"\" } }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @noflow +module.exports = { x: { y: \"\" } }; + +" +`; diff --git a/tests/autocomplete/bar.js b/tests/autocomplete/bar.js new file mode 100644 index 000000000000..00c2758f28f5 --- /dev/null +++ b/tests/autocomplete/bar.js @@ -0,0 +1,4 @@ +// @flow + +var o = require('./unknown'); +o.x. diff --git a/tests/autocomplete/bool.js b/tests/autocomplete/bool.js new file mode 100644 index 000000000000..31e0aa0530b1 --- /dev/null +++ b/tests/autocomplete/bool.js @@ -0,0 +1,3 @@ +// @flow + +true. diff --git a/tests/autocomplete/customfun.js b/tests/autocomplete/customfun.js new file mode 100644 index 000000000000..17a57049c5d4 --- /dev/null +++ b/tests/autocomplete/customfun.js @@ -0,0 +1,11 @@ +// @flow + +declare var idx: $Facebookism$Idx; +declare var merge: $Facebookism$Merge; +declare var mergeDeepInto: $Facebookism$MergeDeepInto; +declare var mergeInto: $Facebookism$MergeInto; +declare var mixin: $Facebookism$Mixin; +declare var objectGetPrototypeOf: Object$GetPrototypeOf +declare var objectAssign: Object$Assign + +m diff --git a/tests/autocomplete/foo.js b/tests/autocomplete/foo.js new file mode 100644 index 000000000000..fb47a498b239 --- /dev/null +++ b/tests/autocomplete/foo.js @@ -0,0 +1,10 @@ +/** + * @flow + */ + +var obj = { + num: 123, + str: 'hello', +}; + +obj. diff --git a/tests/autocomplete/foo_parse_fail.js b/tests/autocomplete/foo_parse_fail.js new file mode 100644 index 000000000000..ad60a989911a --- /dev/null +++ b/tests/autocomplete/foo_parse_fail.js @@ -0,0 +1,10 @@ +/** + * @flow + */ + +var obj = { + num: 123, + str: 'hello', +}; + +console.log(obj. diff --git a/tests/autocomplete/fun.js b/tests/autocomplete/fun.js new file mode 100644 index 000000000000..dda5e9788c36 --- /dev/null +++ b/tests/autocomplete/fun.js @@ -0,0 +1,5 @@ +/* @flow */ + +function foo(f: () => number) { + f. +} diff --git a/tests/autocomplete/function_builtins.js b/tests/autocomplete/function_builtins.js new file mode 100644 index 000000000000..9ab9ee978fd2 --- /dev/null +++ b/tests/autocomplete/function_builtins.js @@ -0,0 +1,5 @@ +/* @flow */ + +function foo(f: Function) { + f. +} diff --git a/tests/autocomplete/generics.js b/tests/autocomplete/generics.js new file mode 100644 index 000000000000..284ca1a8bed5 --- /dev/null +++ b/tests/autocomplete/generics.js @@ -0,0 +1,7 @@ +// @flow + +class C { } + +function foo(o: { cn: C }) { + o. +} diff --git a/tests/autocomplete/if.js b/tests/autocomplete/if.js new file mode 100644 index 000000000000..78fb463ed9cd --- /dev/null +++ b/tests/autocomplete/if.js @@ -0,0 +1,3 @@ +// @flow +const x = ''; +if (x.) diff --git a/tests/autocomplete/issue-1368.js b/tests/autocomplete/issue-1368.js new file mode 100644 index 000000000000..fc346f45a1d8 --- /dev/null +++ b/tests/autocomplete/issue-1368.js @@ -0,0 +1,22 @@ +/* @flow */ +class Test { + prop: number; + + constructor(prop: number) { + this.prop = prop; + } +} + +class ExtendTest extends Test { + extended: string; + + constructor(extended: string) { + super(10); + this.extended = extended; + } + + method() { + this.prop = 12; + this./* here */ + } +} diff --git a/tests/autocomplete/jsfmt.spec.js b/tests/autocomplete/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/autocomplete/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/autocomplete/jsx1.js b/tests/autocomplete/jsx1.js new file mode 100644 index 000000000000..4552fc4f0173 --- /dev/null +++ b/tests/autocomplete/jsx1.js @@ -0,0 +1,8 @@ +// @flow + +var React = require('react'); + +class C extends React.Component { + props: { x: number }; +} + void, o: { x?: string } }) { + return obj. +} diff --git a/tests/autocomplete/override.js b/tests/autocomplete/override.js new file mode 100644 index 000000000000..6b2e3dae5f46 --- /dev/null +++ b/tests/autocomplete/override.js @@ -0,0 +1,10 @@ +// @flow + +class C { + override(): number | string { return 0; } +} + +class D extends C { + foo() { return this.override() } + override(): string { return ""; } + bar() { this. diff --git a/tests/autocomplete/qux.js b/tests/autocomplete/qux.js new file mode 100644 index 000000000000..e25242a8acfb --- /dev/null +++ b/tests/autocomplete/qux.js @@ -0,0 +1,6 @@ +// @flow + +class C { x: number; } + +var c: C = new C; +c. diff --git a/tests/autocomplete/str.js b/tests/autocomplete/str.js new file mode 100644 index 000000000000..66e25873dc3c --- /dev/null +++ b/tests/autocomplete/str.js @@ -0,0 +1,3 @@ +// @flow + +"hello". diff --git a/tests/autocomplete/this.js b/tests/autocomplete/this.js new file mode 100644 index 000000000000..8fb80158b295 --- /dev/null +++ b/tests/autocomplete/this.js @@ -0,0 +1,10 @@ +/* @flow */ + +// issue #1197 +class Foo { + baz: string; + bar() {} + hello() { + this. + } +} diff --git a/tests/autocomplete/typeparams.js b/tests/autocomplete/typeparams.js new file mode 100644 index 000000000000..7231f4c719bb --- /dev/null +++ b/tests/autocomplete/typeparams.js @@ -0,0 +1,8 @@ +// @flow + +class Bounds N> { + foo: F; + bar() { + this.foo(). + } +} diff --git a/tests/autocomplete/union.js b/tests/autocomplete/union.js new file mode 100644 index 000000000000..ddf493f96c32 --- /dev/null +++ b/tests/autocomplete/union.js @@ -0,0 +1,11 @@ +/* @flow */ + +function foo(a: boolean, x: { bar: string }, y: Object) { + var z; + if (a) { + z = x; + } else { + z = y; + } + z. +} diff --git a/tests/autocomplete/unknown.js b/tests/autocomplete/unknown.js new file mode 100644 index 000000000000..22090345cfd7 --- /dev/null +++ b/tests/autocomplete/unknown.js @@ -0,0 +1,2 @@ +// @noflow +module.exports = { x: { y: "" } }; diff --git a/tests/auxiliary/__snapshots__/jsfmt.spec.js.snap b/tests/auxiliary/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1aed9affa598 --- /dev/null +++ b/tests/auxiliary/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test client.js 1`] = ` +"var y:number = x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var y: number = x; + +" +`; diff --git a/tests/auxiliary/client.js b/tests/auxiliary/client.js new file mode 100644 index 000000000000..e3540c1251b2 --- /dev/null +++ b/tests/auxiliary/client.js @@ -0,0 +1 @@ +var y:number = x; diff --git a/tests/auxiliary/jsfmt.spec.js b/tests/auxiliary/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/auxiliary/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/auxiliary/lib/__snapshots__/jsfmt.spec.js.snap b/tests/auxiliary/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..15f3efcda83f --- /dev/null +++ b/tests/auxiliary/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test lib.js 1`] = ` +"declare var x: string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare var x: string; + +" +`; diff --git a/tests/auxiliary/lib/jsfmt.spec.js b/tests/auxiliary/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/auxiliary/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/auxiliary/lib/lib.js b/tests/auxiliary/lib/lib.js new file mode 100644 index 000000000000..e7640e569efc --- /dev/null +++ b/tests/auxiliary/lib/lib.js @@ -0,0 +1 @@ +declare var x: string; diff --git a/tests/binary/__snapshots__/jsfmt.spec.js.snap b/tests/binary/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d53527910e3c --- /dev/null +++ b/tests/binary/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,112 @@ +exports[`test in.js 1`] = ` +"// @flow + +let tests = [ + // objects on RHS + function() { + ('foo' in {}); + ('foo' in { foo: null }); + (0 in {}); + (0 in { "0": null }); + }, + + // arrays on RHS + function() { + ('foo' in []); + (0 in []); + ('length' in []); + }, + + // primitive classes on RHS + function() { + ('foo' in new String('bar')); + ('foo' in new Number(123)); + }, + + // primitives on RHS + function() { + ('foo' in 123); // error + ('foo' in 'bar'); // error + ('foo' in void 0); // error + ('foo' in null); // error + }, + + // bogus stuff on LHS + function() { + (null in {}); // error + (void 0 in {}); // error + ({} in {}); // error + ([] in {}); // error + (false in []); // error + }, + + // in predicates + function() { + if ('foo' in 123) {} // error + if (!'foo' in {}) {} // error, !'foo' is a boolean + if (!('foo' in {})) {} + }, + + // annotations on RHS + function(x: Object, y: mixed) { + ('foo' in x); // ok + ('foo' in y); // error + }, +] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // objects on RHS + function() { + "foo" in {}; + "foo" in { foo: null }; + 0 in {}; + 0 in { "0": null }; + }, + // arrays on RHS + function() { + "foo" in [ ]; + 0 in [ ]; + "length" in [ ]; + }, + // primitive classes on RHS + function() { + "foo" in new String("bar"); + "foo" in new Number(123); + }, + // primitives on RHS + function() { + "foo" in 123;// error + "foo" in "bar";// error + "foo" in void 0;// error + "foo" in null;// error + }, + // bogus stuff on LHS + function() { + null in {};// error + void 0 in {};// error + ({}) in {};// error + [ ] in {};// error + false in [ ];// error + }, + // in predicates + function() { + if ("foo" in 123) { + + }// error + if (!"foo" in {}) { + + }// error, !'foo' is a boolean + if (!("foo" in {})) { + + } + }, + // annotations on RHS + function(x: Object, y: mixed) { + "foo" in x;// ok + "foo" in y;// error + } +]; + +" +`; diff --git a/tests/binary/in.js b/tests/binary/in.js new file mode 100644 index 000000000000..a66b1d84f69b --- /dev/null +++ b/tests/binary/in.js @@ -0,0 +1,54 @@ +// @flow + +let tests = [ + // objects on RHS + function() { + ('foo' in {}); + ('foo' in { foo: null }); + (0 in {}); + (0 in { "0": null }); + }, + + // arrays on RHS + function() { + ('foo' in []); + (0 in []); + ('length' in []); + }, + + // primitive classes on RHS + function() { + ('foo' in new String('bar')); + ('foo' in new Number(123)); + }, + + // primitives on RHS + function() { + ('foo' in 123); // error + ('foo' in 'bar'); // error + ('foo' in void 0); // error + ('foo' in null); // error + }, + + // bogus stuff on LHS + function() { + (null in {}); // error + (void 0 in {}); // error + ({} in {}); // error + ([] in {}); // error + (false in []); // error + }, + + // in predicates + function() { + if ('foo' in 123) {} // error + if (!'foo' in {}) {} // error, !'foo' is a boolean + if (!('foo' in {})) {} + }, + + // annotations on RHS + function(x: Object, y: mixed) { + ('foo' in x); // ok + ('foo' in y); // error + }, +] diff --git a/tests/binary/jsfmt.spec.js b/tests/binary/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/binary/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/binding/__snapshots__/jsfmt.spec.js.snap b/tests/binding/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ba9f6c6fc639 --- /dev/null +++ b/tests/binding/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,594 @@ +exports[`test const.js 1`] = ` +"const x = 0; + +// errors: const cannot be reassigned +x++; +x--; +x += 0; +x -= 0; +x /= 0; +x %= 0; +x <<= 0 +x >>= 0; +x >>>= 0; +x |= 0; +x ^= 0; +x &= 0; + +// regression tests -- OK to assign consts like this: + +const { foo } = { foo: \"foo\" } +const [ bar ] = [\"bar\"]; +(foo: number); // error: string ~> number +(bar: number); // error: string ~> number + +declare var bazzes: { baz: string }[]; +for (const { baz } of bazzes) { + (baz: number); // error: string ~> number +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const x = 0; +// errors: const cannot be reassigned +x++; +x--; +x += 0; +x -= 0; +x /= 0; +x %= 0; +x <<= 0; +x >>= 0; +x >>>= 0; +x |= 0; +x ^= 0; +x &= 0; +// regression tests -- OK to assign consts like this: +const { foo } = { foo: \"foo\" }; +const [ bar ] = [ \"bar\" ]; +(foo: number);// error: string ~> number +(bar: number);// error: string ~> number +declare var bazzes: { baz: string }[]; +for (const { baz } of bazzes) { + (baz: number);// error: string ~> number +} + +" +`; + +exports[`test rebinding.js 1`] = ` +"/* @flow + * test errors on illegal rebinding/reassignment + * + * type class let const var (reassign) + * type x x x x x x + * class x x x x x + * let x x x x x + * const x x x x x x + * var x x x x + */ + +// type x * + +function type_type() { + type A = number; + type A = number; // error: name already bound +} + +function type_class() { + type A = number; + class A {} // error: name already bound +} + +function type_let() { + type A = number; + let A = 0; // error: name already bound +} + +function type_const() { + type A = number; + const A = 0; // error: name already bound +} + +function type_var() { + type A = number; + var A = 0; // error: name already bound +} + +function type_reassign() { + type A = number; + A = 42; // error: type alias ref\'d from value pos +} + +// class x * + +function class_type() { + class A {} + type A = number; // error: name already bound +} + +function class_class() { + class A {} + class A {} // error: name already bound +} + +function class_let() { + class A {} + let A = 0; // error: name already bound +} + +function class_const() { + class A {} + const A = 0; // error: name already bound +} + +function class_var() { + class A {} + var A = 0; // error: name already bound +} + +// let x * + +function let_type() { + let A = 0; + type A = number; // error: name already bound +} + +function let_class() { + let A = 0; + class A {} // error: name already bound +} + +function let_let() { + let A = 0; + let A = 0; // error: name already bound +} + +function let_const() { + let A = 0; + const A = 0; // error: name already bound +} + +function let_var() { + let A = 0; + var A = 0; // error: name already bound +} + +// const x * + +function const_type() { + const A = 0; + type A = number; // error: name already bound +} + +function const_class() { + const A = 0; + class A {} // error: name already bound +} + +function const_let() { + const A = 0; + let A = 0; // error: name already bound +} + +function const_const() { + const A = 0; + const A = 0; // error: name already bound +} + +function const_var() { + const A = 0; + var A = 0; // error: name already bound +} + +function const_reassign() { + const A = 0; + A = 42; // error: cannot be reassigned +} + +// var x * + +function var_type() { + var A = 0; + type A = number; // error: name already bound +} + +function var_class() { + var A = 0; + class A {} // error: name already bound +} + +function var_let() { + var A = 0; + let A = 0; // error: name already bound +} + +function var_const() { + var A = 0; + const A = 0; // error: name already bound +} + +function var_var() { + var A = 0; + var A = 0; // OK +} + +// function x * + +function function_toplevel() { + function a() {}; + function a() {}; // OK +} + +function function_block() { + { + function a() {}; + function a() {}; // error: name already bound + } +} + +// corner cases + +function var_shadow_nested_scope() { + { + let x = 0; + { + var x = 0; // error: name already bound + } + } +} + +function type_shadow_nested_scope() { + { + let x = 0; + { + type x = string; // error: name already bound + } + } +} + +// fn params name clash + +function fn_params_name_clash(x, x /* error: x already bound */) {} +function fn_params_clash_fn_binding(x,y) { + let x = 0; // error: x already bound + var y = 0; // OK +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Argument name clash in strict mode (193:33) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$2.checkLVal (/node_modules/babylon/lib/index.js:3007:16) + at Parser.checkLVal (/node_modules/babylon/lib/index.js:5446:22) + at Parser.pp$3.parseFunctionBody (/node_modules/babylon/lib/index.js:4072:12) + at Parser.parseFunctionBody (/node_modules/babylon/lib/index.js:5211:20) + at Parser.pp$1.parseFunction (/node_modules/babylon/lib/index.js:2257:8) + at Parser.pp$1.parseFunctionStatement (/node_modules/babylon/lib/index.js:1926:15) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1712:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) +" +`; + +exports[`test scope.js 1`] = ` +"function block_scope() { + let a: number = 0; + var b: number = 0; + { + let a = \"\"; // ok: local to block + var b = \"\"; // error: string ~> number + } +} + +function switch_scope(x: string) { + let a: number = 0; + var b: number = 0; + switch (x) { + case \"foo\": + let a = \"\"; // ok: local to switch + var b = \"\"; // error: string ~> number + break; + case \"bar\": + let a = \"\"; // error: a already bound in switch + break; + } +} + +// a switch is a single lexical scope, so lets and non-disjoint +// cases can mix in odd ways. our support for edge cases is not +// yet perfect. +function switch_scope2(x: number) { + switch (x) { + case 0: + a = \"\"; // error: assign before declaration + break; + case 1: + var b = a; // error: use before declaration + break; + case 2: + let a = \"\"; + break; + case 3: + a = \"\"; // error: skipped initializer + break; + case 4: + var c:string = a; // error: skipped initializer + break; + } + a = \"\"; // error: a no longer in scope +} + +function try_scope() { + let a: number = 0; + try { + let a = \"\"; // ok + } catch (e) { + let a = \"\"; // ok + } finally { + let a = \"\"; // ok + } +} + +function for_scope_let() { + let a: number = 0; + for (let a = \"\" /* ok: local to init */;;) {} +} + +function for_scope_var() { + var a: number = 0; + for (var a = \"\" /* error: string ~> number */;;) {} +} + +function for_in_scope_let(o: Object) { + let a: number = 0; + for (let a /* ok: local to init */ in o) {} +} + +function for_in_scope_var(o: Object) { + var a: number = 0; + for (var a /* error: string ~> number */ in o) {} +} + +function for_of_scope_let(xs: string[]) { + let a: number = 0; + for (let a /* ok: local to init */ of xs) {} +} + +function for_of_scope_var(xs: string[]) { + var a: number = 0; + for (var a /* error: string ~> number */ of xs) {} +} + +function default_param_1() { + // function binding in scope in default expr + function f( + x: () => string = f // error: number ~> string + ): number { + return 0; + } +} + +function default_param_2() { + // fn body bindings not visible from param scope + let a = \"\"; + function f0(x = () => a): number { + let a = 0; + return x(); // error: string ~> number + } + function f1(x = b /* error: cannot resolve b */): number { + let b = 0; + return x; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test tdz.js 1`] = ` +"/** @flow */ + +// -- types --- + +// type aliases are hoisted and always available + +type T1 = T2; // ok +type T2 = number; + +// --- lets --- + +// to be correct, we would +// - not allow forward refs to lets from value positions, +// while let is in TDZ. +// - allow forward refs to lets from type positions. +// +// currently we\'re too lenient about TDZ in closures - +// from value positions, we currently enforce TDZ only in-scope. +// this is unsound - a let or const may remain uninitialized when +// a lambda runs. But a simple conservative approach would prohibit +// forward references to let/consts from within lambdas entirely, +// which would be annoying. TODO + +function f0() { + var v = x * c; // errors, let + const referenced before decl + let x = 0; + const c = 0; +} + +function f1(b) { + x = 10; // error, attempt to write to let before decl + let x = 0; + if (b) { + y = 10; // error, attempt to write to let before decl + let y = 0; + } +} + +function f2() { + { + var v = x * c; // errors, let + const referenced before decl + } + let x = 0; + const c = 0; +} + +// functions are let-scoped and hoisted +function f3() { + var s: string = foo(); // ok, finds hoisted outer + { + var n: number = foo(); // ok, finds hoisted inner + function foo() { return 0; } + } + var s2: string = foo(); // ok, hoisted outer not clobbered + function foo() { return \"\"; } +} + +// out-of-scope TDZ not enforced. sometimes right... +function f4() { + function g() { return x + c; } // ok, g doesn\'t run in TDZ + let x = 0; + const c = 0; +} + +// ...sometimes wrong +function f5() { + function g() { return x; } + g(); // should error, but doesn\'t currently + let x = 0; + const c = 0; +} + +// - from type positions, we currently error on forward refs to any +// value (i.e., class or function). this is a basic flaw in our +// phasing of AST traversal, and will be fixed. +// + +var x: C; // ok + +var y = new C(); // error: let ref before decl from value position + +class C {} + +var z: C = new C(); // ok + +// --- vars --- + +// it\'s possible to annotate a var with a non-maybe type, +// but leave it uninitialized until later (as long as it\'s +// initialized before use) + +var a: number; // not an error per se - only if used before init + +function f(n: number) { return n; } + +f(a); // error: undefined ~/> number + +a = 10; + +f(a); // ok, a: number (not ?number) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** @flow */ +// -- types --- +// type aliases are hoisted and always available +type T1 = T2;// ok +type T2 = number; +// --- lets --- +// to be correct, we would +// - not allow forward refs to lets from value positions, +// while let is in TDZ. +// - allow forward refs to lets from type positions. +// +// currently we\'re too lenient about TDZ in closures - +// from value positions, we currently enforce TDZ only in-scope. +// this is unsound - a let or const may remain uninitialized when +// a lambda runs. But a simple conservative approach would prohibit +// forward references to let/consts from within lambdas entirely, +// which would be annoying. TODO +function f0() { + var v = x * c;// errors, let + const referenced before decl + let x = 0; + const c = 0; +} +function f1(b) { + x = 10;// error, attempt to write to let before decl + let x = 0; + if (b) { + y = 10;// error, attempt to write to let before decl + let y = 0; + } +} +function f2() { + { + var v = x * c;// errors, let + const referenced before decl + } + let x = 0; + const c = 0; +} +// functions are let-scoped and hoisted +function f3() { + var s: string = foo();// ok, finds hoisted outer + { + var n: number = foo();// ok, finds hoisted inner + function foo() { + return 0; + } + } + var s2: string = foo();// ok, hoisted outer not clobbered + function foo() { + return \"\"; + } +} +// out-of-scope TDZ not enforced. sometimes right... +function f4() { + function g() { + return x + c; + }// ok, g doesn\'t run in TDZ + let x = 0; + const c = 0; +} +// ...sometimes wrong +function f5() { + function g() { + return x; + } + g();// should error, but doesn\'t currently + let x = 0; + const c = 0; +} +// - from type positions, we currently error on forward refs to any +// value (i.e., class or function). this is a basic flaw in our +// phasing of AST traversal, and will be fixed. +// +var x: C;// ok +var y = new C();// error: let ref before decl from value position +class C {} +var z: C = new C();// ok +// --- vars --- +// it\'s possible to annotate a var with a non-maybe type, +// but leave it uninitialized until later (as long as it\'s +// initialized before use) +var a: number;// not an error per se - only if used before init +function f(n: number) { + return n; +} +f(a);// error: undefined ~/> number +a = 10; +f(a);// ok, a: number (not ?number) + +" +`; diff --git a/tests/binding/const.js b/tests/binding/const.js new file mode 100644 index 000000000000..387e96cb0fa2 --- /dev/null +++ b/tests/binding/const.js @@ -0,0 +1,27 @@ +const x = 0; + +// errors: const cannot be reassigned +x++; +x--; +x += 0; +x -= 0; +x /= 0; +x %= 0; +x <<= 0 +x >>= 0; +x >>>= 0; +x |= 0; +x ^= 0; +x &= 0; + +// regression tests -- OK to assign consts like this: + +const { foo } = { foo: "foo" } +const [ bar ] = ["bar"]; +(foo: number); // error: string ~> number +(bar: number); // error: string ~> number + +declare var bazzes: { baz: string }[]; +for (const { baz } of bazzes) { + (baz: number); // error: string ~> number +} diff --git a/tests/binding/jsfmt.spec.js b/tests/binding/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/binding/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/binding/rebinding.js b/tests/binding/rebinding.js new file mode 100644 index 000000000000..195f096b3f54 --- /dev/null +++ b/tests/binding/rebinding.js @@ -0,0 +1,197 @@ +/* @flow + * test errors on illegal rebinding/reassignment + * + * type class let const var (reassign) + * type x x x x x x + * class x x x x x + * let x x x x x + * const x x x x x x + * var x x x x + */ + +// type x * + +function type_type() { + type A = number; + type A = number; // error: name already bound +} + +function type_class() { + type A = number; + class A {} // error: name already bound +} + +function type_let() { + type A = number; + let A = 0; // error: name already bound +} + +function type_const() { + type A = number; + const A = 0; // error: name already bound +} + +function type_var() { + type A = number; + var A = 0; // error: name already bound +} + +function type_reassign() { + type A = number; + A = 42; // error: type alias ref'd from value pos +} + +// class x * + +function class_type() { + class A {} + type A = number; // error: name already bound +} + +function class_class() { + class A {} + class A {} // error: name already bound +} + +function class_let() { + class A {} + let A = 0; // error: name already bound +} + +function class_const() { + class A {} + const A = 0; // error: name already bound +} + +function class_var() { + class A {} + var A = 0; // error: name already bound +} + +// let x * + +function let_type() { + let A = 0; + type A = number; // error: name already bound +} + +function let_class() { + let A = 0; + class A {} // error: name already bound +} + +function let_let() { + let A = 0; + let A = 0; // error: name already bound +} + +function let_const() { + let A = 0; + const A = 0; // error: name already bound +} + +function let_var() { + let A = 0; + var A = 0; // error: name already bound +} + +// const x * + +function const_type() { + const A = 0; + type A = number; // error: name already bound +} + +function const_class() { + const A = 0; + class A {} // error: name already bound +} + +function const_let() { + const A = 0; + let A = 0; // error: name already bound +} + +function const_const() { + const A = 0; + const A = 0; // error: name already bound +} + +function const_var() { + const A = 0; + var A = 0; // error: name already bound +} + +function const_reassign() { + const A = 0; + A = 42; // error: cannot be reassigned +} + +// var x * + +function var_type() { + var A = 0; + type A = number; // error: name already bound +} + +function var_class() { + var A = 0; + class A {} // error: name already bound +} + +function var_let() { + var A = 0; + let A = 0; // error: name already bound +} + +function var_const() { + var A = 0; + const A = 0; // error: name already bound +} + +function var_var() { + var A = 0; + var A = 0; // OK +} + +// function x * + +function function_toplevel() { + function a() {}; + function a() {}; // OK +} + +function function_block() { + { + function a() {}; + function a() {}; // error: name already bound + } +} + +// corner cases + +function var_shadow_nested_scope() { + { + let x = 0; + { + var x = 0; // error: name already bound + } + } +} + +function type_shadow_nested_scope() { + { + let x = 0; + { + type x = string; // error: name already bound + } + } +} + +// fn params name clash + +function fn_params_name_clash(x, x /* error: x already bound */) {} +function fn_params_clash_fn_binding(x,y) { + let x = 0; // error: x already bound + var y = 0; // OK +} diff --git a/tests/binding/scope.js b/tests/binding/scope.js new file mode 100644 index 000000000000..8aa169fad3e8 --- /dev/null +++ b/tests/binding/scope.js @@ -0,0 +1,109 @@ +function block_scope() { + let a: number = 0; + var b: number = 0; + { + let a = ""; // ok: local to block + var b = ""; // error: string ~> number + } +} + +function switch_scope(x: string) { + let a: number = 0; + var b: number = 0; + switch (x) { + case "foo": + let a = ""; // ok: local to switch + var b = ""; // error: string ~> number + break; + case "bar": + let a = ""; // error: a already bound in switch + break; + } +} + +// a switch is a single lexical scope, so lets and non-disjoint +// cases can mix in odd ways. our support for edge cases is not +// yet perfect. +function switch_scope2(x: number) { + switch (x) { + case 0: + a = ""; // error: assign before declaration + break; + case 1: + var b = a; // error: use before declaration + break; + case 2: + let a = ""; + break; + case 3: + a = ""; // error: skipped initializer + break; + case 4: + var c:string = a; // error: skipped initializer + break; + } + a = ""; // error: a no longer in scope +} + +function try_scope() { + let a: number = 0; + try { + let a = ""; // ok + } catch (e) { + let a = ""; // ok + } finally { + let a = ""; // ok + } +} + +function for_scope_let() { + let a: number = 0; + for (let a = "" /* ok: local to init */;;) {} +} + +function for_scope_var() { + var a: number = 0; + for (var a = "" /* error: string ~> number */;;) {} +} + +function for_in_scope_let(o: Object) { + let a: number = 0; + for (let a /* ok: local to init */ in o) {} +} + +function for_in_scope_var(o: Object) { + var a: number = 0; + for (var a /* error: string ~> number */ in o) {} +} + +function for_of_scope_let(xs: string[]) { + let a: number = 0; + for (let a /* ok: local to init */ of xs) {} +} + +function for_of_scope_var(xs: string[]) { + var a: number = 0; + for (var a /* error: string ~> number */ of xs) {} +} + +function default_param_1() { + // function binding in scope in default expr + function f( + x: () => string = f // error: number ~> string + ): number { + return 0; + } +} + +function default_param_2() { + // fn body bindings not visible from param scope + let a = ""; + function f0(x = () => a): number { + let a = 0; + return x(); // error: string ~> number + } + function f1(x = b /* error: cannot resolve b */): number { + let b = 0; + return x; + } +} diff --git a/tests/binding/tdz.js b/tests/binding/tdz.js new file mode 100644 index 000000000000..da081b0999c1 --- /dev/null +++ b/tests/binding/tdz.js @@ -0,0 +1,100 @@ +/** @flow */ + +// -- types --- + +// type aliases are hoisted and always available + +type T1 = T2; // ok +type T2 = number; + +// --- lets --- + +// to be correct, we would +// - not allow forward refs to lets from value positions, +// while let is in TDZ. +// - allow forward refs to lets from type positions. +// +// currently we're too lenient about TDZ in closures - +// from value positions, we currently enforce TDZ only in-scope. +// this is unsound - a let or const may remain uninitialized when +// a lambda runs. But a simple conservative approach would prohibit +// forward references to let/consts from within lambdas entirely, +// which would be annoying. TODO + +function f0() { + var v = x * c; // errors, let + const referenced before decl + let x = 0; + const c = 0; +} + +function f1(b) { + x = 10; // error, attempt to write to let before decl + let x = 0; + if (b) { + y = 10; // error, attempt to write to let before decl + let y = 0; + } +} + +function f2() { + { + var v = x * c; // errors, let + const referenced before decl + } + let x = 0; + const c = 0; +} + +// functions are let-scoped and hoisted +function f3() { + var s: string = foo(); // ok, finds hoisted outer + { + var n: number = foo(); // ok, finds hoisted inner + function foo() { return 0; } + } + var s2: string = foo(); // ok, hoisted outer not clobbered + function foo() { return ""; } +} + +// out-of-scope TDZ not enforced. sometimes right... +function f4() { + function g() { return x + c; } // ok, g doesn't run in TDZ + let x = 0; + const c = 0; +} + +// ...sometimes wrong +function f5() { + function g() { return x; } + g(); // should error, but doesn't currently + let x = 0; + const c = 0; +} + +// - from type positions, we currently error on forward refs to any +// value (i.e., class or function). this is a basic flaw in our +// phasing of AST traversal, and will be fixed. +// + +var x: C; // ok + +var y = new C(); // error: let ref before decl from value position + +class C {} + +var z: C = new C(); // ok + +// --- vars --- + +// it's possible to annotate a var with a non-maybe type, +// but leave it uninitialized until later (as long as it's +// initialized before use) + +var a: number; // not an error per se - only if used before init + +function f(n: number) { return n; } + +f(a); // error: undefined ~/> number + +a = 10; + +f(a); // ok, a: number (not ?number) diff --git a/tests/bom/FormData.js b/tests/bom/FormData.js new file mode 100644 index 000000000000..79db76483ad1 --- /dev/null +++ b/tests/bom/FormData.js @@ -0,0 +1,67 @@ +/* @flow */ + +// constructor +const a: FormData = new FormData(); // correct +new FormData(''); // incorrect +new FormData(document.createElement('input')); // incorrect +new FormData(document.createElement('form')); // correct + +// has +const b: boolean = a.has('foo'); // correct + +// get +const c: ?(string | File) = a.get('foo'); // correct +const d: string = a.get('foo'); // incorrect +const e: Blob = a.get('foo'); // incorrect +const f: ?(string | File | Blob) = a.get('foo'); // incorrect +a.get(2); // incorrect + +// getAll +const a1: Array = a.getAll('foo'); // correct +const a2: Array = a.getAll('foo'); // incorrect +const a3: Array = a.getAll('foo'); // incorrect +a.getAll(23); // incorrect + +// set +a.set('foo', 'bar'); // correct +a.set('foo', {}); // incorrect +a.set(2, 'bar'); // incorrect +a.set('foo', 'bar', 'baz'); // incorrect +a.set('bar', new File([], 'q')) // correct +a.set('bar', new File([], 'q'), 'x') // correct +a.set('bar', new File([], 'q'), 2) // incorrect +a.set('bar', new Blob) // correct +a.set('bar', new Blob, 'x') // correct +a.set('bar', new Blob, 2) // incorrect + +// append +a.append('foo', 'bar'); // correct +a.append('foo', {}); // incorrect +a.append(2, 'bar'); // incorrect +a.append('foo', 'bar', 'baz'); // incorrect +a.append('foo', 'bar'); // incorrect +a.append('bar', new File([], 'q')) // correct +a.append('bar', new File([], 'q'), 'x') // correct +a.append('bar', new File([], 'q'), 2) // incorrect +a.append('bar', new Blob) // correct +a.append('bar', new Blob, 'x') // correct +a.append('bar', new Blob, 2) // incorrect + +// delete +a.delete('xx'); // correct +a.delete(3); // incorrect + +// keys +for (let x: string of a.keys()) {} // correct +for (let x: number of a.keys()) {} // incorrect + +// values +for (let x: string | File of a.values()) {} // correct +for (let x: string | File | Blob of a.values()) {} // incorrect + +// entries +for (let [x, y]: [string, string | File] of a.entries()) {} // correct +for (let [x, y]: [string, string | File | Blob] of a.entries()) {} // incorrect +for (let [x, y]: [number, string] of a.entries()) {} // incorrect +for (let [x, y]: [string, number] of a.entries()) {} // incorrect +for (let [x, y]: [number, number] of a.entries()) {} // incorrect diff --git a/tests/bom/MutationObserver.js b/tests/bom/MutationObserver.js new file mode 100644 index 000000000000..e1d588b5f7a8 --- /dev/null +++ b/tests/bom/MutationObserver.js @@ -0,0 +1,29 @@ +/* @flow */ + +// constructor +function callback(arr: Array, observer: MutationObserver): void { + return; +} +const o: MutationObserver = new MutationObserver(callback); // correct +new MutationObserver((arr: Array) => true); // correct +new MutationObserver(() => {}); // correct +new MutationObserver(); // incorrect +new MutationObserver(42); // incorrect +new MutationObserver((n: number) => {}); // incorrect + +// observe +const div = document.createElement('div'); +o.observe(div, { attributes: true, attributeFilter: ['style'] }); // correct +o.observe(div, { characterData: true, invalid: true }); // correct +o.observe(); // incorrect +o.observe('invalid'); // incorrect +o.observe(div); // incorrect +o.observe(div, {}); // incorrect +o.observe(div, { subtree: true }); // incorrect +o.observe(div, { attributes: true, attributeFilter: true }); // incorrect + +// takeRecords +o.takeRecords(); // correct + +// disconnect +o.disconnect(); // correct diff --git a/tests/bom/__snapshots__/jsfmt.spec.js.snap b/tests/bom/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6483f642c78d --- /dev/null +++ b/tests/bom/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,135 @@ +exports[`test FormData.js 1`] = ` +"/* @flow */ + +// constructor +const a: FormData = new FormData(); // correct +new FormData(\'\'); // incorrect +new FormData(document.createElement(\'input\')); // incorrect +new FormData(document.createElement(\'form\')); // correct + +// has +const b: boolean = a.has(\'foo\'); // correct + +// get +const c: ?(string | File) = a.get(\'foo\'); // correct +const d: string = a.get(\'foo\'); // incorrect +const e: Blob = a.get(\'foo\'); // incorrect +const f: ?(string | File | Blob) = a.get(\'foo\'); // incorrect +a.get(2); // incorrect + +// getAll +const a1: Array = a.getAll(\'foo\'); // correct +const a2: Array = a.getAll(\'foo\'); // incorrect +const a3: Array = a.getAll(\'foo\'); // incorrect +a.getAll(23); // incorrect + +// set +a.set(\'foo\', \'bar\'); // correct +a.set(\'foo\', {}); // incorrect +a.set(2, \'bar\'); // incorrect +a.set(\'foo\', \'bar\', \'baz\'); // incorrect +a.set(\'bar\', new File([], \'q\')) // correct +a.set(\'bar\', new File([], \'q\'), \'x\') // correct +a.set(\'bar\', new File([], \'q\'), 2) // incorrect +a.set(\'bar\', new Blob) // correct +a.set(\'bar\', new Blob, \'x\') // correct +a.set(\'bar\', new Blob, 2) // incorrect + +// append +a.append(\'foo\', \'bar\'); // correct +a.append(\'foo\', {}); // incorrect +a.append(2, \'bar\'); // incorrect +a.append(\'foo\', \'bar\', \'baz\'); // incorrect +a.append(\'foo\', \'bar\'); // incorrect +a.append(\'bar\', new File([], \'q\')) // correct +a.append(\'bar\', new File([], \'q\'), \'x\') // correct +a.append(\'bar\', new File([], \'q\'), 2) // incorrect +a.append(\'bar\', new Blob) // correct +a.append(\'bar\', new Blob, \'x\') // correct +a.append(\'bar\', new Blob, 2) // incorrect + +// delete +a.delete(\'xx\'); // correct +a.delete(3); // incorrect + +// keys +for (let x: string of a.keys()) {} // correct +for (let x: number of a.keys()) {} // incorrect + +// values +for (let x: string | File of a.values()) {} // correct +for (let x: string | File | Blob of a.values()) {} // incorrect + +// entries +for (let [x, y]: [string, string | File] of a.entries()) {} // correct +for (let [x, y]: [string, string | File | Blob] of a.entries()) {} // incorrect +for (let [x, y]: [number, string] of a.entries()) {} // incorrect +for (let [x, y]: [string, number] of a.entries()) {} // incorrect +for (let [x, y]: [number, number] of a.entries()) {} // incorrect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1412:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test MutationObserver.js 1`] = ` +"/* @flow */ + +// constructor +function callback(arr: Array, observer: MutationObserver): void { + return; +} +const o: MutationObserver = new MutationObserver(callback); // correct +new MutationObserver((arr: Array) => true); // correct +new MutationObserver(() => {}); // correct +new MutationObserver(); // incorrect +new MutationObserver(42); // incorrect +new MutationObserver((n: number) => {}); // incorrect + +// observe +const div = document.createElement(\'div\'); +o.observe(div, { attributes: true, attributeFilter: [\'style\'] }); // correct +o.observe(div, { characterData: true, invalid: true }); // correct +o.observe(); // incorrect +o.observe(\'invalid\'); // incorrect +o.observe(div); // incorrect +o.observe(div, {}); // incorrect +o.observe(div, { subtree: true }); // incorrect +o.observe(div, { attributes: true, attributeFilter: true }); // incorrect + +// takeRecords +o.takeRecords(); // correct + +// disconnect +o.disconnect(); // correct +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/bom/jsfmt.spec.js b/tests/bom/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/bom/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/bounded_poly/__snapshots__/jsfmt.spec.js.snap b/tests/bounded_poly/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..609f1e49a3b5 --- /dev/null +++ b/tests/bounded_poly/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,68 @@ +exports[`test scope.js 1`] = ` +"function foo(x:X, y:Y):void { } +foo(0, \"\"); + +function bar(x:X, y:Y): number { return y*0; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"function foo(x: T): T { + var _ = x * 1; // OK + var y: string = x; // error + return x; // OK +} + +class C { + bar(x: U): T { + return x; // error, since T: number and U: number does not imply U: T + } + qux(x: U): T { + var _ = x * 1; // OK, since T: number and U: T implies U: number + var y: string = x; // error + return x; // OK, since U: T + } +} + +function example(o: T): T { o.x = 0; return o; } +var obj1: {x: number; y: string} = example({x: 0, y: \"\"}); +var obj2: {x: number} = example({x: 0}); + +var c: C = new C; // error, since T = string is incompatible with number +var q: number = c.qux(0); +/* 2 more errors, since argument U = number is incompatible with T = string, and + * result T = string is incompatible with number */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/bounded_poly/jsfmt.spec.js b/tests/bounded_poly/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/bounded_poly/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/bounded_poly/scope.js b/tests/bounded_poly/scope.js new file mode 100644 index 000000000000..0bade54aae3c --- /dev/null +++ b/tests/bounded_poly/scope.js @@ -0,0 +1,4 @@ +function foo(x:X, y:Y):void { } +foo(0, ""); + +function bar(x:X, y:Y): number { return y*0; } diff --git a/tests/bounded_poly/test.js b/tests/bounded_poly/test.js new file mode 100644 index 000000000000..cddb17861a72 --- /dev/null +++ b/tests/bounded_poly/test.js @@ -0,0 +1,25 @@ +function foo(x: T): T { + var _ = x * 1; // OK + var y: string = x; // error + return x; // OK +} + +class C { + bar(x: U): T { + return x; // error, since T: number and U: number does not imply U: T + } + qux(x: U): T { + var _ = x * 1; // OK, since T: number and U: T implies U: number + var y: string = x; // error + return x; // OK, since U: T + } +} + +function example(o: T): T { o.x = 0; return o; } +var obj1: {x: number; y: string} = example({x: 0, y: ""}); +var obj2: {x: number} = example({x: 0}); + +var c: C = new C; // error, since T = string is incompatible with number +var q: number = c.qux(0); +/* 2 more errors, since argument U = number is incompatible with T = string, and + * result T = string is incompatible with number */ diff --git a/tests/break/__snapshots__/jsfmt.spec.js.snap b/tests/break/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..03752e1fb8e3 --- /dev/null +++ b/tests/break/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,87 @@ +exports[`test break.js 1`] = ` +"function foo(b) { + var x = b ? null: false; + var z; + while(b) { + if (x == null) { z = \"\"; break; } + var y:number = x; // error: boolean !~> number + } + var w:number = z; // 2 errors: ?string !~> number +} + +function bar(b) { + var x = b ? null: false; + if (x == null) return; + switch (\"\") { + case 0: + var y:number = x; // error: boolean !~> number + x = \"\"; + case 1: + var z:number = x; // 2 errors: (boolean | string) !~> number + break; + case 2: + } + var w:number = x; // 2 errors: (boolean | string) !~> number +} + +function bar2(b) { + var x = b ? null: false; + if (x == null) return; + switch (\"\") { + case 0: { + let y:number = x; // error: boolean !~> number + x = \"\"; + } + case 1: { + let z:number = x; // 2 errors: (boolean | string) !~> number + break; + } + case 2: + } + var w:number = x; // 2 errors: (boolean | string) !~> number +} + +function qux(b) { + var z = 0; + while(b) { + var y:number = z; + if (b) { z = \"\"; continue; } // error: string !~> number + z = 0; + } + var w:number = z; // error: string !~> number +} + +// same basic test as foo(), but with const. probes the +// logic that still uses havoc to do env resets. +function test_const() { + let st: string = \'abc\'; + + for (let i = 1; i < 100; i++) { + const fooRes: ?string = \"HEY\"; + if (!fooRes) { + break; + } + + st = fooRes; // no error + } + + return st; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/break/break.js b/tests/break/break.js new file mode 100644 index 000000000000..67986714a41d --- /dev/null +++ b/tests/break/break.js @@ -0,0 +1,68 @@ +function foo(b) { + var x = b ? null: false; + var z; + while(b) { + if (x == null) { z = ""; break; } + var y:number = x; // error: boolean !~> number + } + var w:number = z; // 2 errors: ?string !~> number +} + +function bar(b) { + var x = b ? null: false; + if (x == null) return; + switch ("") { + case 0: + var y:number = x; // error: boolean !~> number + x = ""; + case 1: + var z:number = x; // 2 errors: (boolean | string) !~> number + break; + case 2: + } + var w:number = x; // 2 errors: (boolean | string) !~> number +} + +function bar2(b) { + var x = b ? null: false; + if (x == null) return; + switch ("") { + case 0: { + let y:number = x; // error: boolean !~> number + x = ""; + } + case 1: { + let z:number = x; // 2 errors: (boolean | string) !~> number + break; + } + case 2: + } + var w:number = x; // 2 errors: (boolean | string) !~> number +} + +function qux(b) { + var z = 0; + while(b) { + var y:number = z; + if (b) { z = ""; continue; } // error: string !~> number + z = 0; + } + var w:number = z; // error: string !~> number +} + +// same basic test as foo(), but with const. probes the +// logic that still uses havoc to do env resets. +function test_const() { + let st: string = 'abc'; + + for (let i = 1; i < 100; i++) { + const fooRes: ?string = "HEY"; + if (!fooRes) { + break; + } + + st = fooRes; // no error + } + + return st; +} diff --git a/tests/break/jsfmt.spec.js b/tests/break/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/break/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/builtin_uses/__snapshots__/jsfmt.spec.js.snap b/tests/builtin_uses/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a833f9c2987d --- /dev/null +++ b/tests/builtin_uses/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,21 @@ +exports[`test test.js 1`] = ` +"var o = Object.freeze({ foo: 0 }); +(o.foo: string); +module.exports = o; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = Object.freeze({ foo: 0 }); +(o.foo: string); +module.exports = o; + +" +`; + +exports[`test test2.js 1`] = ` +"var o = require('./test'); +(o.foo: string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = require("./test"); +(o.foo: string); + +" +`; diff --git a/tests/builtin_uses/jsfmt.spec.js b/tests/builtin_uses/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/builtin_uses/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/builtin_uses/test.js b/tests/builtin_uses/test.js new file mode 100644 index 000000000000..3adc7cba9b8b --- /dev/null +++ b/tests/builtin_uses/test.js @@ -0,0 +1,3 @@ +var o = Object.freeze({ foo: 0 }); +(o.foo: string); +module.exports = o; diff --git a/tests/builtin_uses/test2.js b/tests/builtin_uses/test2.js new file mode 100644 index 000000000000..678f4c9af730 --- /dev/null +++ b/tests/builtin_uses/test2.js @@ -0,0 +1,2 @@ +var o = require('./test'); +(o.foo: string); diff --git a/tests/builtins/__snapshots__/jsfmt.spec.js.snap b/tests/builtins/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3be55c8e21da --- /dev/null +++ b/tests/builtins/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,78 @@ +exports[`test array.js 1`] = ` +"var a = [\"...\"]; +var b = a.map (function (x) { return 0; }); +var c: string = b[0]; // error: number !~> string + +var array = []; +function f() { + array = array.map (function () { return \"...\"; }); + var x:number = array[0]; // error: string !~> number +} + +var Foo = require(\'./genericfoo\'); +var foo = new Foo(); +function g() { + var foo1 = foo.map (function() { return \"...\"; }); + var x:number = foo1.get(); // error: string !~> number + foo = foo1; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a = [ \"...\" ]; +var b = a.map( + function(x) { + return 0; + } +); +var c: string = b[0];// error: number !~> string +var array = [ ]; +function f() { + array = array.map( + function() { + return \"...\"; + } + ); + var x: number = array[0];// error: string !~> number +} +var Foo = require(\"./genericfoo\"); +var foo = new Foo(); +function g() { + var foo1 = foo.map( + function() { + return \"...\"; + } + ); + var x: number = foo1.get();// error: string !~> number + foo = foo1; +} + +" +`; + +exports[`test genericfoo.js 1`] = ` +"class Foo { + x:T; + self():Foo { return this; } + map(callbackfn: () => U): Foo { return new Foo(); } + set(x:T): void { } + get(): T { return this.x; } +} + +module.exports = Foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/builtins/array.js b/tests/builtins/array.js new file mode 100644 index 000000000000..c84ddcb02bee --- /dev/null +++ b/tests/builtins/array.js @@ -0,0 +1,17 @@ +var a = ["..."]; +var b = a.map (function (x) { return 0; }); +var c: string = b[0]; // error: number !~> string + +var array = []; +function f() { + array = array.map (function () { return "..."; }); + var x:number = array[0]; // error: string !~> number +} + +var Foo = require('./genericfoo'); +var foo = new Foo(); +function g() { + var foo1 = foo.map (function() { return "..."; }); + var x:number = foo1.get(); // error: string !~> number + foo = foo1; +} diff --git a/tests/builtins/genericfoo.js b/tests/builtins/genericfoo.js new file mode 100644 index 000000000000..53d5feb2438f --- /dev/null +++ b/tests/builtins/genericfoo.js @@ -0,0 +1,9 @@ +class Foo { + x:T; + self():Foo { return this; } + map(callbackfn: () => U): Foo { return new Foo(); } + set(x:T): void { } + get(): T { return this.x; } +} + +module.exports = Foo; diff --git a/tests/builtins/jsfmt.spec.js b/tests/builtins/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/builtins/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/call_properties/A.js b/tests/call_properties/A.js new file mode 100644 index 000000000000..8f5e02ce82a0 --- /dev/null +++ b/tests/call_properties/A.js @@ -0,0 +1,30 @@ +// You should be able to call objects with call properties +function a(f: { (): string }, g: { (x: number): string } ): string { + return f() + g(123); +} + +// ...and get an error if the return type is wrong +function b(f: { (): string }): number { + return f(); +} + +// ...or if the param type is wrong +function c(f: { (x: number): number }): number { + return f("hello"); +} + +// ...or if the arity is wrong +function d(f: { (x: number): number }): number { + return f(); +} + +// ...or if there is no call property +function e(f: {}): number { + return f(); +} + +// Make sure we complain even if the object literal is unsealed. +function f(): number { + var x = {}; + return x(); +} diff --git a/tests/call_properties/B.js b/tests/call_properties/B.js new file mode 100644 index 000000000000..5441f2f7e235 --- /dev/null +++ b/tests/call_properties/B.js @@ -0,0 +1,20 @@ +// You should be able to use a function as an object with a call property +var a: { (x: number): string } = function (x: number): string { return "hi"; }; + +// ...and it should notice when the return type is wrong +var b: { (x: number): number } = function (x: number): string { return "hi"; }; + +// ...or if the param type is wrong +var c: { (x: string): string } = function (x: number): string { return "hi"; }; + +// ...or if the arity is wrong +var d: { (): string } = function (x: number): string { return "hi"; }; + +// ...but subtyping rules still apply +var e: { (x: any): void } = function() { } // arity +var f: { (): mixed } = function(): string { return "hi" } // return type +var g: { (x: string): void } = function(x: mixed) { } // param type + +// A function can be an object +var y : {} = function (x: number): string { return "hi"; }; +var z : Object = function (x: number): string { return "hi"; }; diff --git a/tests/call_properties/C.js b/tests/call_properties/C.js new file mode 100644 index 000000000000..75576e3a16b0 --- /dev/null +++ b/tests/call_properties/C.js @@ -0,0 +1,34 @@ +// You should be able to use an object as a function +function a(x: { (z: number): string }): (z: number) => string { + return x; +} + +// ...and it should notice when the return type is wrong +function b(x: { (z: number): string }): (z: number) => number { + return x; +} + +// ...or if the param type is wrong +function c(x: { (z: number): string }): (z: string) => string { + return x; +} + +// ...or if the arity is wrong +function d(x: { (z: number): string }): () => string { + return x; +} + +// ...or if it doesn't have a call property +function e(x: {}): () => string { + return x; +} + +// AnyFunT should also be allowed +function f(x: { (z: number): string }): Function { + return x; +} + +// ... but only if the object is callable +function g(x: {}): Function { + return x; // error +} diff --git a/tests/call_properties/D.js b/tests/call_properties/D.js new file mode 100644 index 000000000000..38a1874289e5 --- /dev/null +++ b/tests/call_properties/D.js @@ -0,0 +1,22 @@ +// Multiple call properties should also be supported +function a(f: { (): string; (x: number): string }): string { + return f() + f(123); +} + +// It should be fine when a function satisfies them all +var b: { (): string; (x: number): string } = + function (x?: number): string { return "hi"; }; + +// ...but should notice when a function doesn't satisfy them all +var c: { (): string; (x: number): string } = + function (x: number): string { return "hi"; }; + +// Only one call property needs to match the function +function d(x: { (): string; (x: number): string }): () => string { + return x; +} + +// ...but you need at least one +function e(x: { (): string; (x: number): string }): () => number { + return x; +} diff --git a/tests/call_properties/E.js b/tests/call_properties/E.js new file mode 100644 index 000000000000..873d9eccc4cb --- /dev/null +++ b/tests/call_properties/E.js @@ -0,0 +1,10 @@ +// Expecting properties that don't exist should be an error +var a : { someProp: number } = function () {}; + +// Expecting properties that do exist should be fine +var b : { apply: Function } = function () {}; + +// Expecting properties in the functions statics should be fine +var f = function () {}; +f.myProp = 123; +var c : { myProp: number } = f; diff --git a/tests/call_properties/F.js b/tests/call_properties/F.js new file mode 100644 index 000000000000..c3e37bfd3f68 --- /dev/null +++ b/tests/call_properties/F.js @@ -0,0 +1,21 @@ +// You should be able to use an arrow function as an object with a call property + +var a: { (x: number): string } = (x) => x.toString() + +// ...and it should notice when the return type is wrong +var b: { (x: number): number } = (x) => "hi" + +// ...or if the param type is wrong +var c: { (x: string): string } = (x) => x.toFixed() + +// ...or if the arity is wrong +var d: { (): string } = (x) => "hi" + +// ...but subtyping rules still apply +var e: { (x: any): void } = () => { } // arity +var f: { (): mixed } = () => "hi" // return type +var g: { (x: Date): void } = (x) => { x * 2 } // param type (date < number) + +// A function can be an object +var y : {} = (x) => "hi" +var z : Object = (x) => "hi" diff --git a/tests/call_properties/__snapshots__/jsfmt.spec.js.snap b/tests/call_properties/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e18cbd0809a3 --- /dev/null +++ b/tests/call_properties/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,256 @@ +exports[`test A.js 1`] = ` +"// You should be able to call objects with call properties +function a(f: { (): string }, g: { (x: number): string } ): string { + return f() + g(123); +} + +// ...and get an error if the return type is wrong +function b(f: { (): string }): number { + return f(); +} + +// ...or if the param type is wrong +function c(f: { (x: number): number }): number { + return f(\"hello\"); +} + +// ...or if the arity is wrong +function d(f: { (x: number): number }): number { + return f(); +} + +// ...or if there is no call property +function e(f: {}): number { + return f(); +} + +// Make sure we complain even if the object literal is unsealed. +function f(): number { + var x = {}; + return x(); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1425:19) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test B.js 1`] = ` +"// You should be able to use a function as an object with a call property +var a: { (x: number): string } = function (x: number): string { return \"hi\"; }; + +// ...and it should notice when the return type is wrong +var b: { (x: number): number } = function (x: number): string { return \"hi\"; }; + +// ...or if the param type is wrong +var c: { (x: string): string } = function (x: number): string { return \"hi\"; }; + +// ...or if the arity is wrong +var d: { (): string } = function (x: number): string { return \"hi\"; }; + +// ...but subtyping rules still apply +var e: { (x: any): void } = function() { } // arity +var f: { (): mixed } = function(): string { return \"hi\" } // return type +var g: { (x: string): void } = function(x: mixed) { } // param type + +// A function can be an object +var y : {} = function (x: number): string { return \"hi\"; }; +var z : Object = function (x: number): string { return \"hi\"; }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1425:19) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test C.js 1`] = ` +"// You should be able to use an object as a function +function a(x: { (z: number): string }): (z: number) => string { + return x; +} + +// ...and it should notice when the return type is wrong +function b(x: { (z: number): string }): (z: number) => number { + return x; +} + +// ...or if the param type is wrong +function c(x: { (z: number): string }): (z: string) => string { + return x; +} + +// ...or if the arity is wrong +function d(x: { (z: number): string }): () => string { + return x; +} + +// ...or if it doesn\'t have a call property +function e(x: {}): () => string { + return x; +} + +// AnyFunT should also be allowed +function f(x: { (z: number): string }): Function { + return x; +} + +// ... but only if the object is callable +function g(x: {}): Function { + return x; // error +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1425:19) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test D.js 1`] = ` +"// Multiple call properties should also be supported +function a(f: { (): string; (x: number): string }): string { + return f() + f(123); +} + +// It should be fine when a function satisfies them all +var b: { (): string; (x: number): string } = + function (x?: number): string { return \"hi\"; }; + +// ...but should notice when a function doesn\'t satisfy them all +var c: { (): string; (x: number): string } = + function (x: number): string { return \"hi\"; }; + +// Only one call property needs to match the function +function d(x: { (): string; (x: number): string }): () => string { + return x; +} + +// ...but you need at least one +function e(x: { (): string; (x: number): string }): () => number { + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1425:19) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test E.js 1`] = ` +"// Expecting properties that don\'t exist should be an error +var a : { someProp: number } = function () {}; + +// Expecting properties that do exist should be fine +var b : { apply: Function } = function () {}; + +// Expecting properties in the functions statics should be fine +var f = function () {}; +f.myProp = 123; +var c : { myProp: number } = f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Expecting properties that don\'t exist should be an error +var a: { someProp: number } = function() { + +}; +// Expecting properties that do exist should be fine +var b: { apply: Function } = function() { + +}; +// Expecting properties in the functions statics should be fine +var f = function() { + +}; +f.myProp = 123; +var c: { myProp: number } = f; + +" +`; + +exports[`test F.js 1`] = ` +"// You should be able to use an arrow function as an object with a call property + +var a: { (x: number): string } = (x) => x.toString() + +// ...and it should notice when the return type is wrong +var b: { (x: number): number } = (x) => \"hi\" + +// ...or if the param type is wrong +var c: { (x: string): string } = (x) => x.toFixed() + +// ...or if the arity is wrong +var d: { (): string } = (x) => \"hi\" + +// ...but subtyping rules still apply +var e: { (x: any): void } = () => { } // arity +var f: { (): mixed } = () => \"hi\" // return type +var g: { (x: Date): void } = (x) => { x * 2 } // param type (date < number) + +// A function can be an object +var y : {} = (x) => \"hi\" +var z : Object = (x) => \"hi\" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1425:19) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/call_properties/jsfmt.spec.js b/tests/call_properties/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/call_properties/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/callable/__snapshots__/jsfmt.spec.js.snap b/tests/callable/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f699cf940cc0 --- /dev/null +++ b/tests/callable/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,70 @@ +exports[`test optional.js 1`] = ` +"type F = { + (x: string): number; + p?: string; +} + +function f(x) { + return x.length; +} + +(f: F); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1425:19) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test primitives.js 1`] = ` +"var x = Boolean(4); +function foo(fn:(value:any)=>boolean) { } +foo(Boolean); + +var dict: { [k: string]: any } = {}; +dict(); // error, callable signature not found + +interface ICall { + (x: string): void; +} +declare var icall: ICall; +icall(0); // error, number ~> string +icall.call(null, 0); // error, number ~> string + +type Callable = { + (x: string): void; +} + +declare var callable: Callable; +callable(0); // error, number ~> string +callable.call(null, 0); // error, number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/callable/jsfmt.spec.js b/tests/callable/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/callable/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/callable/optional.js b/tests/callable/optional.js new file mode 100644 index 000000000000..6d16aeec66c7 --- /dev/null +++ b/tests/callable/optional.js @@ -0,0 +1,10 @@ +type F = { + (x: string): number; + p?: string; +} + +function f(x) { + return x.length; +} + +(f: F); diff --git a/tests/callable/primitives.js b/tests/callable/primitives.js new file mode 100644 index 000000000000..2fa4c16f0ea5 --- /dev/null +++ b/tests/callable/primitives.js @@ -0,0 +1,21 @@ +var x = Boolean(4); +function foo(fn:(value:any)=>boolean) { } +foo(Boolean); + +var dict: { [k: string]: any } = {}; +dict(); // error, callable signature not found + +interface ICall { + (x: string): void; +} +declare var icall: ICall; +icall(0); // error, number ~> string +icall.call(null, 0); // error, number ~> string + +type Callable = { + (x: string): void; +} + +declare var callable: Callable; +callable(0); // error, number ~> string +callable.call(null, 0); // error, number ~> string diff --git a/tests/check-contents/__snapshots__/jsfmt.spec.js.snap b/tests/check-contents/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..202940e64222 --- /dev/null +++ b/tests/check-contents/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,30 @@ +exports[`test not_flow.js 1`] = ` +"1 * \'foo\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1 * \"foo\"; + +" +`; + +exports[`test syntax_error.js 1`] = ` +"/* @flow */ + +( +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (4:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3592:12) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; diff --git a/tests/check-contents/jsfmt.spec.js b/tests/check-contents/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/check-contents/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/check-contents/not_flow.js b/tests/check-contents/not_flow.js new file mode 100644 index 000000000000..f2562df539af --- /dev/null +++ b/tests/check-contents/not_flow.js @@ -0,0 +1 @@ +1 * 'foo'; diff --git a/tests/check-contents/syntax_error.js b/tests/check-contents/syntax_error.js new file mode 100644 index 000000000000..6ac6aff468a8 --- /dev/null +++ b/tests/check-contents/syntax_error.js @@ -0,0 +1,3 @@ +/* @flow */ + +( diff --git a/tests/class_fields/__snapshots__/jsfmt.spec.js.snap b/tests/class_fields/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ec8cdbd64a47 --- /dev/null +++ b/tests/class_fields/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,523 @@ +exports[`test base_class.js 1`] = ` +"// @flow + +class Base { + unannotatedField; + annotatedField: number; + initializedField = 42; + initializedFieldWithThis = this.initializedField; + annotatedInitializedFieldValid: ?number = 42; + annotatedInitializedFieldInvalid: number = \'asdf\'; // Error: string ~> number + + static unannotatedField; + static annotatedField: number; + static initializedField = \'asdf\'; + static initializedFieldWithThis = this.initializedField; + static annotatedInitializedFieldValid: ?number = 42; + static annotatedInitializedFieldInvalid: number = \'asdf\'; // Error: string ~> number +} + +var o = new Base(); + +/** + * Unannotated fields are open. + */ +(o.unannotatedField: string); +(o.unannotatedField: number); +(Base.unannotatedField: string); +(Base.unannotatedField: number); + +/** + * Annotated (but uninitialized) fields still have a type. + */ +(o.annotatedField: number); +(o.annotatedField: string); // Error: number ~> string +(Base.annotatedField: number); +(Base.annotatedField: string); // Error: number ~> string + +/** + * Initialized (but unannotated) fields assume the type of their initializer. + */ +(o.initializedField: number); +(o.initializedField: string); // Error: number ~> string +(Base.initializedField: string); +(Base.initializedField: number); // Error: string ~> number + +/** + * Initialized fields can reference \`this\`. + */ +(o.initializedFieldWithThis: number); +(o.initializedFieldWithThis: string); // Error: number ~> string +(Base.initializedFieldWithThis: string); +(Base.initializedFieldWithThis: number); // Error: string ~> number + +/** + * Initialized + annotated fields take the type of the annotation. + * (Note that this matters when the annotation is more general than the type of + * the initializer) + */ +(o.annotatedInitializedFieldValid: ?number); +(o.annotatedInitializedFieldValid: number); // Error: ?number ~> number +(Base.annotatedInitializedFieldValid: ?number); +(Base.annotatedInitializedFieldValid: number); // Error: ?number ~> number + +/** + * Initialized + annotated fields where the init/annot combo is a mismatch + * should assume the type of the annotation. + * + * (This happens in addition to erroring at the site of initialization) + */ +(o.annotatedInitializedFieldInvalid: number); +(o.annotatedInitializedFieldInvalid: string); // Error: number ~> string +(Base.annotatedInitializedFieldInvalid: number); +(Base.annotatedInitializedFieldInvalid: string); // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class Base { + unannotatedField; + annotatedField: number; + initializedField = 42; + initializedFieldWithThis = this.initializedField; + annotatedInitializedFieldValid: ?number = 42; + annotatedInitializedFieldInvalid: number = \"asdf\";// Error: string ~> number + static unannotatedField; + static annotatedField: number; + static initializedField = \"asdf\"; + static initializedFieldWithThis = this.initializedField; + static annotatedInitializedFieldValid: ?number = 42; + static annotatedInitializedFieldInvalid: number = \"asdf\";// Error: string ~> number +} +var o = new Base(); +/** + * Unannotated fields are open. + */ +(o.unannotatedField: string); +(o.unannotatedField: number); +(Base.unannotatedField: string); +(Base.unannotatedField: number); +/** + * Annotated (but uninitialized) fields still have a type. + */ +(o.annotatedField: number); +(o.annotatedField: string);// Error: number ~> string +(Base.annotatedField: number); +(Base.annotatedField: string);// Error: number ~> string +/** + * Initialized (but unannotated) fields assume the type of their initializer. + */ +(o.initializedField: number); +(o.initializedField: string);// Error: number ~> string +(Base.initializedField: string); +(Base.initializedField: number);// Error: string ~> number +/** + * Initialized fields can reference \`this\`. + */ +(o.initializedFieldWithThis: number); +(o.initializedFieldWithThis: string);// Error: number ~> string +(Base.initializedFieldWithThis: string); +(Base.initializedFieldWithThis: number);// Error: string ~> number +/** + * Initialized + annotated fields take the type of the annotation. + * (Note that this matters when the annotation is more general than the type of + * the initializer) + */ +(o.annotatedInitializedFieldValid: ?number); +(o.annotatedInitializedFieldValid: number);// Error: ?number ~> number +(Base.annotatedInitializedFieldValid: ?number); +(Base.annotatedInitializedFieldValid: number);// Error: ?number ~> number +/** + * Initialized + annotated fields where the init/annot combo is a mismatch + * should assume the type of the annotation. + * + * (This happens in addition to erroring at the site of initialization) + */ +(o.annotatedInitializedFieldInvalid: number); +(o.annotatedInitializedFieldInvalid: string);// Error: number ~> string +(Base.annotatedInitializedFieldInvalid: number); +(Base.annotatedInitializedFieldInvalid: string);// Error: number ~> string + +" +`; + +exports[`test derived_class.js 1`] = ` +"// @flow + +class Base { + base_unannotatedField; + base_annotatedField: number; + base_initializedField = 42; + base_initializedFieldWithThis = this.base_initializedField; + base_annotatedInitializedFieldValid: ?number = 42; + base_annotatedInitializedFieldInvalid: number = \'asdf\'; // Error: string ~> number + + static base_unannotatedField; + static base_annotatedField: number; + static base_initializedField = \'asdf\'; + static base_initializedFieldWithThis = this.base_initializedField; + static base_annotatedInitializedFieldValid: ?number = 42; + static base_annotatedInitializedFieldInvalid: number = \'asdf\'; // Error: string ~> number + + inherited_initializer = 42; + static inherited_initializer = 42; +} + +class Child extends Base { + child_unannotatedField; + child_annotatedField: number; + child_initializedField = 42; + child_initializedFieldWithThis = this.child_initializedField; + child_annotatedInitializedFieldValid: ?number = 42; + child_annotatedInitializedFieldInvalid: number = \'asdf\'; // Error: string ~> number + + static child_unannotatedField; + static child_annotatedField: number; + static child_initializedField = \'asdf\'; + static child_initializedFieldWithThis = this.child_initializedField; + static child_annotatedInitializedFieldValid: ?number = 42; + static child_annotatedInitializedFieldInvalid: number = \'asdf\'; // Error: string ~> number + + inherited_initializer; + static inherited_initializer; +} + +var o = new Child(); + +/** + * Unannotated fields are open. + */ +(o.base_unannotatedField: string); +(o.base_unannotatedField: number); +(Child.base_unannotatedField: string); +(Child.base_unannotatedField: number); + +(o.child_unannotatedField: string); +(o.child_unannotatedField: number); +(Child.child_unannotatedField: string); +(Child.child_unannotatedField: number); + + +/** + * Annotated (but uninitialized) fields still have a type. + */ +(o.base_annotatedField: number); +(o.base_annotatedField: string); // Error: number ~> string +(Child.base_annotatedField: number); +(Child.base_annotatedField: string); // Error: number ~> string + +(o.child_annotatedField: number); +(o.child_annotatedField: string); // Error: number ~> string +(Child.child_annotatedField: number); +(Child.child_annotatedField: string); // Error: number ~> string + +/** + * Initialized (but unannotated) fields assume the type of their initializer. + */ +(o.base_initializedField: number); +(o.base_initializedField: string); // Error: number ~> string +(Child.base_initializedField: string); +(Child.base_initializedField: number); // Error: string ~> number + +(o.child_initializedField: number); +(o.child_initializedField: string); // Error: number ~> string +(Child.child_initializedField: string); +(Child.child_initializedField: number); // Error: string ~> number + +/** + * Initialized fields can reference \`this\`. + */ +(o.base_initializedFieldWithThis: number); +(o.base_initializedFieldWithThis: string); // Error: number ~> string +(Child.base_initializedFieldWithThis: string); +(Child.base_initializedFieldWithThis: number); // Error: string ~> number + +(o.child_initializedFieldWithThis: number); +(o.child_initializedFieldWithThis: string); // Error: number ~> string +(Child.child_initializedFieldWithThis: string); +(Child.child_initializedFieldWithThis: number); // Error: string ~> number + +/** + * Initialized + annotated fields take the type of the annotation. + * (Note that this matters when the annotation is more general than the type of + * the initializer) + */ +(o.base_annotatedInitializedFieldValid: ?number); +(o.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number +(Child.base_annotatedInitializedFieldValid: ?number); +(Child.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number + +(o.child_annotatedInitializedFieldValid: ?number); +(o.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number +(Child.child_annotatedInitializedFieldValid: ?number); +(Child.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number + +/** + * Initialized + annotated fields where the init/annot combo is a mismatch + * should assume the type of the annotation. + * + * (This happens in addition to erroring at the site of initialization) + */ +(o.base_annotatedInitializedFieldInvalid: number); +(o.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string +(Child.base_annotatedInitializedFieldInvalid: number); +(Child.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string + +(o.child_annotatedInitializedFieldInvalid: number); +(o.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string +(Child.child_annotatedInitializedFieldInvalid: number); +(Child.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string + +/** + * Derived fields without an initializer that shadow base fields *with* an + * initializer should have the type of the base field. + */ +(o.inherited_initializer: number); +(o.inherited_initializer: string); // Error: number ~> string +(Child.inherited_initializer: number); +(Child.inherited_initializer: string); // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class Base { + base_unannotatedField; + base_annotatedField: number; + base_initializedField = 42; + base_initializedFieldWithThis = this.base_initializedField; + base_annotatedInitializedFieldValid: ?number = 42; + base_annotatedInitializedFieldInvalid: number = \"asdf\";// Error: string ~> number + static base_unannotatedField; + static base_annotatedField: number; + static base_initializedField = \"asdf\"; + static base_initializedFieldWithThis = this.base_initializedField; + static base_annotatedInitializedFieldValid: ?number = 42; + static base_annotatedInitializedFieldInvalid: number = \"asdf\";// Error: string ~> number + inherited_initializer = 42; + static inherited_initializer = 42; +} +class Child extends Base { + child_unannotatedField; + child_annotatedField: number; + child_initializedField = 42; + child_initializedFieldWithThis = this.child_initializedField; + child_annotatedInitializedFieldValid: ?number = 42; + child_annotatedInitializedFieldInvalid: number = \"asdf\";// Error: string ~> number + static child_unannotatedField; + static child_annotatedField: number; + static child_initializedField = \"asdf\"; + static child_initializedFieldWithThis = this.child_initializedField; + static child_annotatedInitializedFieldValid: ?number = 42; + static child_annotatedInitializedFieldInvalid: number = \"asdf\";// Error: string ~> number + inherited_initializer; + static inherited_initializer; +} +var o = new Child(); +/** + * Unannotated fields are open. + */ +(o.base_unannotatedField: string); +(o.base_unannotatedField: number); +(Child.base_unannotatedField: string); +(Child.base_unannotatedField: number); +(o.child_unannotatedField: string); +(o.child_unannotatedField: number); +(Child.child_unannotatedField: string); +(Child.child_unannotatedField: number); +/** + * Annotated (but uninitialized) fields still have a type. + */ +(o.base_annotatedField: number); +(o.base_annotatedField: string);// Error: number ~> string +(Child.base_annotatedField: number); +(Child.base_annotatedField: string);// Error: number ~> string +(o.child_annotatedField: number); +(o.child_annotatedField: string);// Error: number ~> string +(Child.child_annotatedField: number); +(Child.child_annotatedField: string);// Error: number ~> string +/** + * Initialized (but unannotated) fields assume the type of their initializer. + */ +(o.base_initializedField: number); +(o.base_initializedField: string);// Error: number ~> string +(Child.base_initializedField: string); +(Child.base_initializedField: number);// Error: string ~> number +(o.child_initializedField: number); +(o.child_initializedField: string);// Error: number ~> string +(Child.child_initializedField: string); +(Child.child_initializedField: number);// Error: string ~> number +/** + * Initialized fields can reference \`this\`. + */ +(o.base_initializedFieldWithThis: number); +(o.base_initializedFieldWithThis: string);// Error: number ~> string +(Child.base_initializedFieldWithThis: string); +(Child.base_initializedFieldWithThis: number);// Error: string ~> number +(o.child_initializedFieldWithThis: number); +(o.child_initializedFieldWithThis: string);// Error: number ~> string +(Child.child_initializedFieldWithThis: string); +(Child.child_initializedFieldWithThis: number);// Error: string ~> number +/** + * Initialized + annotated fields take the type of the annotation. + * (Note that this matters when the annotation is more general than the type of + * the initializer) + */ +(o.base_annotatedInitializedFieldValid: ?number); +(o.base_annotatedInitializedFieldValid: number);// Error: ?number ~> number +(Child.base_annotatedInitializedFieldValid: ?number); +(Child.base_annotatedInitializedFieldValid: number);// Error: ?number ~> number +(o.child_annotatedInitializedFieldValid: ?number); +(o.child_annotatedInitializedFieldValid: number);// Error: ?number ~> number +(Child.child_annotatedInitializedFieldValid: ?number); +(Child.child_annotatedInitializedFieldValid: number);// Error: ?number ~> number +/** + * Initialized + annotated fields where the init/annot combo is a mismatch + * should assume the type of the annotation. + * + * (This happens in addition to erroring at the site of initialization) + */ +(o.base_annotatedInitializedFieldInvalid: number); +(o.base_annotatedInitializedFieldInvalid: string);// Error: number ~> string +(Child.base_annotatedInitializedFieldInvalid: number); +(Child.base_annotatedInitializedFieldInvalid: string);// Error: number ~> string +(o.child_annotatedInitializedFieldInvalid: number); +(o.child_annotatedInitializedFieldInvalid: string);// Error: number ~> string +(Child.child_annotatedInitializedFieldInvalid: number); +(Child.child_annotatedInitializedFieldInvalid: string);// Error: number ~> string +/** + * Derived fields without an initializer that shadow base fields *with* an + * initializer should have the type of the base field. + */ +(o.inherited_initializer: number); +(o.inherited_initializer: string);// Error: number ~> string +(Child.inherited_initializer: number); +(Child.inherited_initializer: string);// Error: number ~> string + +" +`; + +exports[`test generic_class.js 1`] = ` +"// @flow + +/** + * Fields annotated with a generic should assume a type once the type param + * is instantiated. + */ +class ClassAnnotated { + p: T; + static p: T; +} + +var o1 = new ClassAnnotated(); +o1.p = 42; +(o1.p: number); +(o1.p: string); // Error: number ~> string +ClassAnnotated.p = 42; +(ClassAnnotated.p: number); +(ClassAnnotated.p: string); // Error: number ~> string + + +/** + * It\'s always an error to initialized a generically-typed field with an + * expression of any type other than the generic itself. + */ +class ClassGenericInitialized { + invalid: T = 42; // Error: number ~> Generic + valid: T = ((42:any):T); + + static invalid: T = 42; // Error: number ~> Generic + static valid: T = ((42:any):T); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test scoping.js 1`] = ` +"// @flow + +var someVar = 42; + +class Foo { + outer = someVar; + selfTyped: Foo; + selfTypedInit = new Foo(); + + static outer = someVar; + static selfTyped: Foo; + static selfTypedInit = new Foo(); + + constructor() { + var someVar = \'asdf\'; + } +} + +/** + * Field initializers execute in a scope immediately under the scope outside the + * class definition. + */ +(new Foo().outer: number); +(new Foo().outer: string); // Error: number ~> string +(Foo.outer: number); +(Foo.outer: string); // Error: number ~> string + +/** + * Field initializers should be able to refer to the class type in their type + * annotations. + */ +(new Foo().selfTyped: Foo); +(new Foo().selfTyped: number); // Error: Foo ~> number +(Foo.selfTyped: Foo); +(Foo.selfTyped: number); // Error: Foo ~> number + +(new Foo().selfTypedInit: Foo); +(new Foo().selfTypedInit: number); // Error: Foo ~> number +(Foo.selfTypedInit: Foo); +(Foo.selfTypedInit: number); // Error: Foo ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var someVar = 42; +class Foo { + outer = someVar; + selfTyped: Foo; + selfTypedInit = new Foo(); + static outer = someVar; + static selfTyped: Foo; + static selfTypedInit = new Foo(); + constructor() { + var someVar = \"asdf\"; + } +} +/** + * Field initializers execute in a scope immediately under the scope outside the + * class definition. + */ +(new Foo().outer: number); +(new Foo().outer: string);// Error: number ~> string +(Foo.outer: number); +(Foo.outer: string);// Error: number ~> string +/** + * Field initializers should be able to refer to the class type in their type + * annotations. + */ +(new Foo().selfTyped: Foo); +(new Foo().selfTyped: number);// Error: Foo ~> number +(Foo.selfTyped: Foo); +(Foo.selfTyped: number);// Error: Foo ~> number +(new Foo().selfTypedInit: Foo); +(new Foo().selfTypedInit: number);// Error: Foo ~> number +(Foo.selfTypedInit: Foo); +(Foo.selfTypedInit: number);// Error: Foo ~> number + +" +`; diff --git a/tests/class_fields/base_class.js b/tests/class_fields/base_class.js new file mode 100644 index 000000000000..b5ad46bcca31 --- /dev/null +++ b/tests/class_fields/base_class.js @@ -0,0 +1,72 @@ +// @flow + +class Base { + unannotatedField; + annotatedField: number; + initializedField = 42; + initializedFieldWithThis = this.initializedField; + annotatedInitializedFieldValid: ?number = 42; + annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number + + static unannotatedField; + static annotatedField: number; + static initializedField = 'asdf'; + static initializedFieldWithThis = this.initializedField; + static annotatedInitializedFieldValid: ?number = 42; + static annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number +} + +var o = new Base(); + +/** + * Unannotated fields are open. + */ +(o.unannotatedField: string); +(o.unannotatedField: number); +(Base.unannotatedField: string); +(Base.unannotatedField: number); + +/** + * Annotated (but uninitialized) fields still have a type. + */ +(o.annotatedField: number); +(o.annotatedField: string); // Error: number ~> string +(Base.annotatedField: number); +(Base.annotatedField: string); // Error: number ~> string + +/** + * Initialized (but unannotated) fields assume the type of their initializer. + */ +(o.initializedField: number); +(o.initializedField: string); // Error: number ~> string +(Base.initializedField: string); +(Base.initializedField: number); // Error: string ~> number + +/** + * Initialized fields can reference `this`. + */ +(o.initializedFieldWithThis: number); +(o.initializedFieldWithThis: string); // Error: number ~> string +(Base.initializedFieldWithThis: string); +(Base.initializedFieldWithThis: number); // Error: string ~> number + +/** + * Initialized + annotated fields take the type of the annotation. + * (Note that this matters when the annotation is more general than the type of + * the initializer) + */ +(o.annotatedInitializedFieldValid: ?number); +(o.annotatedInitializedFieldValid: number); // Error: ?number ~> number +(Base.annotatedInitializedFieldValid: ?number); +(Base.annotatedInitializedFieldValid: number); // Error: ?number ~> number + +/** + * Initialized + annotated fields where the init/annot combo is a mismatch + * should assume the type of the annotation. + * + * (This happens in addition to erroring at the site of initialization) + */ +(o.annotatedInitializedFieldInvalid: number); +(o.annotatedInitializedFieldInvalid: string); // Error: number ~> string +(Base.annotatedInitializedFieldInvalid: number); +(Base.annotatedInitializedFieldInvalid: string); // Error: number ~> string diff --git a/tests/class_fields/derived_class.js b/tests/class_fields/derived_class.js new file mode 100644 index 000000000000..89b40c1664fd --- /dev/null +++ b/tests/class_fields/derived_class.js @@ -0,0 +1,134 @@ +// @flow + +class Base { + base_unannotatedField; + base_annotatedField: number; + base_initializedField = 42; + base_initializedFieldWithThis = this.base_initializedField; + base_annotatedInitializedFieldValid: ?number = 42; + base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number + + static base_unannotatedField; + static base_annotatedField: number; + static base_initializedField = 'asdf'; + static base_initializedFieldWithThis = this.base_initializedField; + static base_annotatedInitializedFieldValid: ?number = 42; + static base_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number + + inherited_initializer = 42; + static inherited_initializer = 42; +} + +class Child extends Base { + child_unannotatedField; + child_annotatedField: number; + child_initializedField = 42; + child_initializedFieldWithThis = this.child_initializedField; + child_annotatedInitializedFieldValid: ?number = 42; + child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number + + static child_unannotatedField; + static child_annotatedField: number; + static child_initializedField = 'asdf'; + static child_initializedFieldWithThis = this.child_initializedField; + static child_annotatedInitializedFieldValid: ?number = 42; + static child_annotatedInitializedFieldInvalid: number = 'asdf'; // Error: string ~> number + + inherited_initializer; + static inherited_initializer; +} + +var o = new Child(); + +/** + * Unannotated fields are open. + */ +(o.base_unannotatedField: string); +(o.base_unannotatedField: number); +(Child.base_unannotatedField: string); +(Child.base_unannotatedField: number); + +(o.child_unannotatedField: string); +(o.child_unannotatedField: number); +(Child.child_unannotatedField: string); +(Child.child_unannotatedField: number); + + +/** + * Annotated (but uninitialized) fields still have a type. + */ +(o.base_annotatedField: number); +(o.base_annotatedField: string); // Error: number ~> string +(Child.base_annotatedField: number); +(Child.base_annotatedField: string); // Error: number ~> string + +(o.child_annotatedField: number); +(o.child_annotatedField: string); // Error: number ~> string +(Child.child_annotatedField: number); +(Child.child_annotatedField: string); // Error: number ~> string + +/** + * Initialized (but unannotated) fields assume the type of their initializer. + */ +(o.base_initializedField: number); +(o.base_initializedField: string); // Error: number ~> string +(Child.base_initializedField: string); +(Child.base_initializedField: number); // Error: string ~> number + +(o.child_initializedField: number); +(o.child_initializedField: string); // Error: number ~> string +(Child.child_initializedField: string); +(Child.child_initializedField: number); // Error: string ~> number + +/** + * Initialized fields can reference `this`. + */ +(o.base_initializedFieldWithThis: number); +(o.base_initializedFieldWithThis: string); // Error: number ~> string +(Child.base_initializedFieldWithThis: string); +(Child.base_initializedFieldWithThis: number); // Error: string ~> number + +(o.child_initializedFieldWithThis: number); +(o.child_initializedFieldWithThis: string); // Error: number ~> string +(Child.child_initializedFieldWithThis: string); +(Child.child_initializedFieldWithThis: number); // Error: string ~> number + +/** + * Initialized + annotated fields take the type of the annotation. + * (Note that this matters when the annotation is more general than the type of + * the initializer) + */ +(o.base_annotatedInitializedFieldValid: ?number); +(o.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number +(Child.base_annotatedInitializedFieldValid: ?number); +(Child.base_annotatedInitializedFieldValid: number); // Error: ?number ~> number + +(o.child_annotatedInitializedFieldValid: ?number); +(o.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number +(Child.child_annotatedInitializedFieldValid: ?number); +(Child.child_annotatedInitializedFieldValid: number); // Error: ?number ~> number + +/** + * Initialized + annotated fields where the init/annot combo is a mismatch + * should assume the type of the annotation. + * + * (This happens in addition to erroring at the site of initialization) + */ +(o.base_annotatedInitializedFieldInvalid: number); +(o.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string +(Child.base_annotatedInitializedFieldInvalid: number); +(Child.base_annotatedInitializedFieldInvalid: string); // Error: number ~> string + +(o.child_annotatedInitializedFieldInvalid: number); +(o.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string +(Child.child_annotatedInitializedFieldInvalid: number); +(Child.child_annotatedInitializedFieldInvalid: string); // Error: number ~> string + +/** + * Derived fields without an initializer that shadow base fields *with* an + * initializer should have the type of the base field. + */ +(o.inherited_initializer: number); +(o.inherited_initializer: string); // Error: number ~> string +(Child.inherited_initializer: number); +(Child.inherited_initializer: string); // Error: number ~> string diff --git a/tests/class_fields/generic_class.js b/tests/class_fields/generic_class.js new file mode 100644 index 000000000000..d214ff6ceee7 --- /dev/null +++ b/tests/class_fields/generic_class.js @@ -0,0 +1,31 @@ +// @flow + +/** + * Fields annotated with a generic should assume a type once the type param + * is instantiated. + */ +class ClassAnnotated { + p: T; + static p: T; +} + +var o1 = new ClassAnnotated(); +o1.p = 42; +(o1.p: number); +(o1.p: string); // Error: number ~> string +ClassAnnotated.p = 42; +(ClassAnnotated.p: number); +(ClassAnnotated.p: string); // Error: number ~> string + + +/** + * It's always an error to initialized a generically-typed field with an + * expression of any type other than the generic itself. + */ +class ClassGenericInitialized { + invalid: T = 42; // Error: number ~> Generic + valid: T = ((42:any):T); + + static invalid: T = 42; // Error: number ~> Generic + static valid: T = ((42:any):T); +} diff --git a/tests/class_fields/jsfmt.spec.js b/tests/class_fields/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/class_fields/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/class_fields/scoping.js b/tests/class_fields/scoping.js new file mode 100644 index 000000000000..462b51293237 --- /dev/null +++ b/tests/class_fields/scoping.js @@ -0,0 +1,40 @@ +// @flow + +var someVar = 42; + +class Foo { + outer = someVar; + selfTyped: Foo; + selfTypedInit = new Foo(); + + static outer = someVar; + static selfTyped: Foo; + static selfTypedInit = new Foo(); + + constructor() { + var someVar = 'asdf'; + } +} + +/** + * Field initializers execute in a scope immediately under the scope outside the + * class definition. + */ +(new Foo().outer: number); +(new Foo().outer: string); // Error: number ~> string +(Foo.outer: number); +(Foo.outer: string); // Error: number ~> string + +/** + * Field initializers should be able to refer to the class type in their type + * annotations. + */ +(new Foo().selfTyped: Foo); +(new Foo().selfTyped: number); // Error: Foo ~> number +(Foo.selfTyped: Foo); +(Foo.selfTyped: number); // Error: Foo ~> number + +(new Foo().selfTypedInit: Foo); +(new Foo().selfTypedInit: number); // Error: Foo ~> number +(Foo.selfTypedInit: Foo); +(Foo.selfTypedInit: number); // Error: Foo ~> number diff --git a/tests/class_munging/__snapshots__/jsfmt.spec.js.snap b/tests/class_munging/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7e538f3c192d --- /dev/null +++ b/tests/class_munging/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,69 @@ +exports[`test with_munging.js 1`] = ` +"/** + * @flow + */ + +class Foo { + _method(): string { + return 'this is private'; + } +} + +class Bar extends Foo { + test() { + (this._method(): string); // error + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class Foo { + _method(): string { + return "this is private"; + } +} +class Bar extends Foo { + test() { + (this._method(): string);// error + } +} + +" +`; + +exports[`test without_munging.js 1`] = ` +"/** + * @flow + * @preventMunge + */ + +class Foo { + _method(): string { + return 'this is not private'; + } +} + +class Bar extends Foo { + test() { + (this._method(): string); // ok + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + * @preventMunge + */ +class Foo { + _method(): string { + return "this is not private"; + } +} +class Bar extends Foo { + test() { + (this._method(): string);// ok + } +} + +" +`; diff --git a/tests/class_munging/jsfmt.spec.js b/tests/class_munging/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/class_munging/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/class_munging/with_munging.js b/tests/class_munging/with_munging.js new file mode 100644 index 000000000000..ead68e9fbaba --- /dev/null +++ b/tests/class_munging/with_munging.js @@ -0,0 +1,15 @@ +/** + * @flow + */ + +class Foo { + _method(): string { + return 'this is private'; + } +} + +class Bar extends Foo { + test() { + (this._method(): string); // error + } +} diff --git a/tests/class_munging/without_munging.js b/tests/class_munging/without_munging.js new file mode 100644 index 000000000000..400dcc84a81a --- /dev/null +++ b/tests/class_munging/without_munging.js @@ -0,0 +1,16 @@ +/** + * @flow + * @preventMunge + */ + +class Foo { + _method(): string { + return 'this is not private'; + } +} + +class Bar extends Foo { + test() { + (this._method(): string); // ok + } +} diff --git a/tests/class_statics/__snapshots__/jsfmt.spec.js.snap b/tests/class_statics/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9b81d21be6d0 --- /dev/null +++ b/tests/class_statics/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,80 @@ +exports[`test test.js 1`] = ` +"class A { + static x: number; + static y: string; + static foo(x: number) { } + static bar(y: string) { } +} +A.qux = function(x: string) { } // error? + +class B extends A { + static x: string; // error? + static foo(x: string) { } // error? + static main() { + B.x = 0; // error + B.x = \"\"; + B.foo(0); // error + B.foo(\"\"); + B.y = 0; // error + B.bar(0); // error + B.qux(0); // error + } + static create(): A { + return new this(); + } + + static badCreate(): number { + return new this(); // error B ~> number + } +} + +class C { + static x: X; + static bar(x: X) { } + static create(): C<*> { + return new this(); + } +} + +class D extends C { + static main() { + D.foo(0); // error? + + D.bar(0); + } +} + +var d: C<*> = D.create(); +(new A: typeof A); +(B: typeof A); + +class E { + static x: number; + static foo(): string { + this.bar(); // error + return this.x; // error + } +} + +// note: above classdefs are sufficiently annotated to export +module.exports = { + A: A, B: B, C: C, D: D, E: E +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/class_statics/jsfmt.spec.js b/tests/class_statics/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/class_statics/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/class_statics/test.js b/tests/class_statics/test.js new file mode 100644 index 000000000000..4fea29a3ed5b --- /dev/null +++ b/tests/class_statics/test.js @@ -0,0 +1,61 @@ +class A { + static x: number; + static y: string; + static foo(x: number) { } + static bar(y: string) { } +} +A.qux = function(x: string) { } // error? + +class B extends A { + static x: string; // error? + static foo(x: string) { } // error? + static main() { + B.x = 0; // error + B.x = ""; + B.foo(0); // error + B.foo(""); + B.y = 0; // error + B.bar(0); // error + B.qux(0); // error + } + static create(): A { + return new this(); + } + + static badCreate(): number { + return new this(); // error B ~> number + } +} + +class C { + static x: X; + static bar(x: X) { } + static create(): C<*> { + return new this(); + } +} + +class D extends C { + static main() { + D.foo(0); // error? + + D.bar(0); + } +} + +var d: C<*> = D.create(); +(new A: typeof A); +(B: typeof A); + +class E { + static x: number; + static foo(): string { + this.bar(); // error + return this.x; // error + } +} + +// note: above classdefs are sufficiently annotated to export +module.exports = { + A: A, B: B, C: C, D: D, E: E +} diff --git a/tests/class_subtyping/__snapshots__/jsfmt.spec.js.snap b/tests/class_subtyping/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7d3266513137 --- /dev/null +++ b/tests/class_subtyping/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,91 @@ +exports[`test test.js 1`] = ` +"/* @flow */ +class A {} +class B {} + +module.exports = { A, B }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class A {} +class B {} +module.exports = { A, B }; + +" +`; + +exports[`test test2.js 1`] = ` +"/* @flow */ +var I = require(\"./test.js\"); + +class C extends I.A {} + +var x: I.A = new C(); +var y: I.B = new C(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var I = require(\"./test.js\"); +class C extends I.A {} +var x: I.A = new C(); +var y: I.B = new C(); + +" +`; + +exports[`test test3.js 1`] = ` +"class A {} +class B extends A {} +class C extends B {} + +var c: C> = new C; // none of the type args matter +var a: A> = c; // the third type arg is incorrect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test4.js 1`] = ` +"class C { x: X; } + +function foo(c: C, x: X) { } + +type O = { f: number }; + +foo((new C: C), { f_: 0 }); + +class D extends C { + bar() { this.x; } +} + +foo(new D, { f_: 0 }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/class_subtyping/jsfmt.spec.js b/tests/class_subtyping/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/class_subtyping/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/class_subtyping/test.js b/tests/class_subtyping/test.js new file mode 100644 index 000000000000..68aa0c6e71ae --- /dev/null +++ b/tests/class_subtyping/test.js @@ -0,0 +1,5 @@ +/* @flow */ +class A {} +class B {} + +module.exports = { A, B }; diff --git a/tests/class_subtyping/test2.js b/tests/class_subtyping/test2.js new file mode 100644 index 000000000000..0601a3576687 --- /dev/null +++ b/tests/class_subtyping/test2.js @@ -0,0 +1,7 @@ +/* @flow */ +var I = require("./test.js"); + +class C extends I.A {} + +var x: I.A = new C(); +var y: I.B = new C(); diff --git a/tests/class_subtyping/test3.js b/tests/class_subtyping/test3.js new file mode 100644 index 000000000000..4f76d86d500f --- /dev/null +++ b/tests/class_subtyping/test3.js @@ -0,0 +1,6 @@ +class A {} +class B extends A {} +class C extends B {} + +var c: C> = new C; // none of the type args matter +var a: A> = c; // the third type arg is incorrect diff --git a/tests/class_subtyping/test4.js b/tests/class_subtyping/test4.js new file mode 100644 index 000000000000..9cd7abb32b4e --- /dev/null +++ b/tests/class_subtyping/test4.js @@ -0,0 +1,13 @@ +class C { x: X; } + +function foo(c: C, x: X) { } + +type O = { f: number }; + +foo((new C: C), { f_: 0 }); + +class D extends C { + bar() { this.x; } +} + +foo(new D, { f_: 0 }); diff --git a/tests/class_type/__snapshots__/jsfmt.spec.js.snap b/tests/class_type/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..915e603e6b78 --- /dev/null +++ b/tests/class_type/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,64 @@ +exports[`test test.js 1`] = ` +"class A { } +function foo(x: Class
): A { + return new x(); // OK +} + +class B { + constructor(_: any) { } +} +function bar(x: Class): B { + return new x(); // error (too few args) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"// A function to typecheck values against their types. Covariance of Class<.> +// makes it useless in such a function (when limited to classes and instances), +// since everything can be trivially satisfied by going to \`mixed\`. +declare function check(cls: $Type, inst: X): void; + +class A { } +class B extends A { } +class C { } + +check(B, new A); +check(A, new B); +check(C, new A); +check(C, new B); +check(B, new C); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/class_type/jsfmt.spec.js b/tests/class_type/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/class_type/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/class_type/test.js b/tests/class_type/test.js new file mode 100644 index 000000000000..a72a3903bee0 --- /dev/null +++ b/tests/class_type/test.js @@ -0,0 +1,11 @@ +class A { } +function foo(x: Class): A { + return new x(); // OK +} + +class B { + constructor(_: any) { } +} +function bar(x: Class): B { + return new x(); // error (too few args) +} diff --git a/tests/class_type/test2.js b/tests/class_type/test2.js new file mode 100644 index 000000000000..071653cd3db7 --- /dev/null +++ b/tests/class_type/test2.js @@ -0,0 +1,14 @@ +// A function to typecheck values against their types. Covariance of Class<.> +// makes it useless in such a function (when limited to classes and instances), +// since everything can be trivially satisfied by going to `mixed`. +declare function check(cls: $Type, inst: X): void; + +class A { } +class B extends A { } +class C { } + +check(B, new A); +check(A, new B); +check(C, new A); +check(C, new B); +check(B, new C); diff --git a/tests/classes/A.js b/tests/classes/A.js new file mode 100644 index 000000000000..37bfb2d47616 --- /dev/null +++ b/tests/classes/A.js @@ -0,0 +1,5 @@ +class A { + foo(x:number):void { } +} + +module.exports = A; diff --git a/tests/classes/B.js b/tests/classes/B.js new file mode 100644 index 000000000000..84a52066d088 --- /dev/null +++ b/tests/classes/B.js @@ -0,0 +1,8 @@ +var A = require('./A'); + +class B extends A { } + +let b = new B(); +(b.foo: number); // error, number !~> function + +module.exports = B; diff --git a/tests/classes/C.js b/tests/classes/C.js new file mode 100644 index 000000000000..1837b2616d9b --- /dev/null +++ b/tests/classes/C.js @@ -0,0 +1,10 @@ +var B = require('./B'); + +class C extends B { + foo(x:string):void { } +} + +let c = new C(); +(c.foo: number); // error, number !~> function + +module.exports = C; diff --git a/tests/classes/D.js b/tests/classes/D.js new file mode 100644 index 000000000000..5f4cae464ab3 --- /dev/null +++ b/tests/classes/D.js @@ -0,0 +1,3 @@ +class D { } +class E { } +new E().x diff --git a/tests/classes/__snapshots__/jsfmt.spec.js.snap b/tests/classes/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1f1021805669 --- /dev/null +++ b/tests/classes/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,249 @@ +exports[`test A.js 1`] = ` +"class A { + foo(x:number):void { } +} + +module.exports = A; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A { + foo(x: number): void { + + } +} +module.exports = A; + +" +`; + +exports[`test B.js 1`] = ` +"var A = require(\'./A\'); + +class B extends A { } + +let b = new B(); +(b.foo: number); // error, number !~> function + +module.exports = B; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var A = require(\"./A\"); +class B extends A {} +let b = new B(); +(b.foo: number);// error, number !~> function +module.exports = B; + +" +`; + +exports[`test C.js 1`] = ` +"var B = require(\'./B\'); + +class C extends B { + foo(x:string):void { } +} + +let c = new C(); +(c.foo: number); // error, number !~> function + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var B = require(\"./B\"); +class C extends B { + foo(x: string): void { + + } +} +let c = new C(); +(c.foo: number);// error, number !~> function +module.exports = C; + +" +`; + +exports[`test D.js 1`] = ` +"class D { } +class E { } +new E().x +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class D {} +class E {} +new E().x; + +" +`; + +exports[`test class_shapes.js 1`] = ` +"/* @flow */ + +type Foo = { + a: string; // exists in TestClass + b: string; // doesn\'t exist + c?: ?string; // exists in TestClass, optional + d?: number; // doesn\'t exist +} + +class TestClass { + a: string; + c: ?string; +} + +var x = new TestClass(); + +x.a; // ok +x.b; // error, TestClass has no b +x.c; // ok +x.d; // error, TestClass has no d + +var y : Foo = x; +y.b; // error, doesn\'t exist in TestClass +y.d; // ok, it\'s optional + +class Test2Superclass { + a: number; // conflicts with cast to Foo + c: ?number; // conflicts with cast to Foo +} +class Test2Class extends Test2Superclass { + b: number; // conflicts with cast to Foo +} + +var z = new Test2Class(); +var w : Foo = z; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +type Foo = { + // exists in TestClass a: string, + // doesn\'t exist b: string, + // exists in TestClass, optional c?: ?string, + // doesn\'t exist d?: number +}; +class TestClass { + a: string; + c: ?string; +} +var x = new TestClass(); +x.a;// ok +x.b;// error, TestClass has no b +x.c;// ok +x.d;// error, TestClass has no d +var y: Foo = x; +y.b;// error, doesn\'t exist in TestClass +y.d;// ok, it\'s optional +class Test2Superclass { + a: number;// conflicts with cast to Foo + c: ?number;// conflicts with cast to Foo +} +class Test2Class extends Test2Superclass { + b: number;// conflicts with cast to Foo +} +var z = new Test2Class(); +var w: Foo = z; + +" +`; + +exports[`test expr.js 1`] = ` +"var Bar = class Foo { + static factory(): Foo { // OK: Foo is a type in this scope + return new Foo() // OK: Foo is a runtime binding in this scope + } +}; + +var bar1: Bar = new Bar() // OK +var bar2: Bar = Bar.factory() // OK + +// NB: Don\'t write expected errors using Foo to avoid error collapse hiding an +// unexpected failure in the above code. + +var B = class Baz { } +var b = new Baz(); // error: Baz is not a runtime binding in this scope + +var C = class Qux { } +var c: Qux = new C(); // error: Qux is not a type in this scope + +// OK: anon classes create no binding, but can be bound manually +var Anon = class { } +var anon: Anon = new Anon(); + +class Alias { } +var _Alias = class Alias { + static factory(): Alias { + return new Alias(); + } +} +var alias1: Alias = new _Alias(); // error: bad pun +var alias2: Alias = _Alias.factory(); // error: bad pun +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var Bar = class Foo { + factory(): Foo { + // OK: Foo is a type in this scope + return new Foo();// OK: Foo is a runtime binding in this scope + } +}; +var bar1: Bar = new Bar();// OK +var bar2: Bar = Bar.factory();// OK +// NB: Don\'t write expected errors using Foo to avoid error collapse hiding an +// unexpected failure in the above code. +var B = class Baz {}; +var b = new Baz();// error: Baz is not a runtime binding in this scope +var C = class Qux {}; +var c: Qux = new C();// error: Qux is not a type in this scope +// OK: anon classes create no binding, but can be bound manually +var Anon = class {}; +var anon: Anon = new Anon(); +class Alias {} +var _Alias = class Alias { + factory(): Alias { + return new Alias(); + } +}; +var alias1: Alias = new _Alias();// error: bad pun +var alias2: Alias = _Alias.factory();// error: bad pun + +" +`; + +exports[`test loc.js 1`] = ` +"/* @flow */ + +type Foo = number + +class Foo {} // error, shadows type Foo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +type Foo = number; +class Foo {}// error, shadows type Foo + +" +`; + +exports[`test statics.js 1`] = ` +"/* @flow */ + +class C { + static p: string; +} +C.p = \"hi\"; + +// Class static fields are compatible with object types +(C: {p:string}); // ok +(C: {p:number}); // errors, string ~> number & vice versa (unify) + +declare var o: {p:number}; +(o: Class); // error, object type incompatible with class type +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/classes/class_shapes.js b/tests/classes/class_shapes.js new file mode 100644 index 000000000000..d35b273d6be5 --- /dev/null +++ b/tests/classes/class_shapes.js @@ -0,0 +1,35 @@ +/* @flow */ + +type Foo = { + a: string; // exists in TestClass + b: string; // doesn't exist + c?: ?string; // exists in TestClass, optional + d?: number; // doesn't exist +} + +class TestClass { + a: string; + c: ?string; +} + +var x = new TestClass(); + +x.a; // ok +x.b; // error, TestClass has no b +x.c; // ok +x.d; // error, TestClass has no d + +var y : Foo = x; +y.b; // error, doesn't exist in TestClass +y.d; // ok, it's optional + +class Test2Superclass { + a: number; // conflicts with cast to Foo + c: ?number; // conflicts with cast to Foo +} +class Test2Class extends Test2Superclass { + b: number; // conflicts with cast to Foo +} + +var z = new Test2Class(); +var w : Foo = z; diff --git a/tests/classes/expr.js b/tests/classes/expr.js new file mode 100644 index 000000000000..7fcca75c1f8f --- /dev/null +++ b/tests/classes/expr.js @@ -0,0 +1,30 @@ +var Bar = class Foo { + static factory(): Foo { // OK: Foo is a type in this scope + return new Foo() // OK: Foo is a runtime binding in this scope + } +}; + +var bar1: Bar = new Bar() // OK +var bar2: Bar = Bar.factory() // OK + +// NB: Don't write expected errors using Foo to avoid error collapse hiding an +// unexpected failure in the above code. + +var B = class Baz { } +var b = new Baz(); // error: Baz is not a runtime binding in this scope + +var C = class Qux { } +var c: Qux = new C(); // error: Qux is not a type in this scope + +// OK: anon classes create no binding, but can be bound manually +var Anon = class { } +var anon: Anon = new Anon(); + +class Alias { } +var _Alias = class Alias { + static factory(): Alias { + return new Alias(); + } +} +var alias1: Alias = new _Alias(); // error: bad pun +var alias2: Alias = _Alias.factory(); // error: bad pun diff --git a/tests/classes/jsfmt.spec.js b/tests/classes/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/classes/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/classes/loc.js b/tests/classes/loc.js new file mode 100644 index 000000000000..8f6066465e8f --- /dev/null +++ b/tests/classes/loc.js @@ -0,0 +1,5 @@ +/* @flow */ + +type Foo = number + +class Foo {} // error, shadows type Foo diff --git a/tests/classes/statics.js b/tests/classes/statics.js new file mode 100644 index 000000000000..75c9d5e7bdef --- /dev/null +++ b/tests/classes/statics.js @@ -0,0 +1,13 @@ +/* @flow */ + +class C { + static p: string; +} +C.p = "hi"; + +// Class static fields are compatible with object types +(C: {p:string}); // ok +(C: {p:number}); // errors, string ~> number & vice versa (unify) + +declare var o: {p:number}; +(o: Class); // error, object type incompatible with class type diff --git a/tests/closure/Closure.js b/tests/closure/Closure.js new file mode 100644 index 000000000000..baeae7811a1f --- /dev/null +++ b/tests/closure/Closure.js @@ -0,0 +1,80 @@ +/*** + * Test tracking of variable types across closure calls. + * @flow + */ + +function takes_string(_:string) { } + +// global write from function +// + +var global_x = "hello"; + +function global_f() { } +function global_g() { global_x = 42; } + +global_f(); +takes_string(global_x); // ok + +global_g(); +takes_string(global_x); // error + +global_x = 42; // shouldn't pollute linear refinement + +// local write from function +// + +function local_func() { + + var local_x = "hello"; + + function local_f() { } + function local_g() { local_x = 42; } + + local_f(); + takes_string(local_x); // ok + + local_g(); + takes_string(local_x); // error + + local_x = 42; // shouldn't pollute linear refinement +} + +// global write from method +// + +var global_y = "hello"; + +var global_o = { + f: function() { }, + g: function() { global_y = 42; } +} + +global_o.f(); +takes_string(global_y); // ok + +global_o.g(); +takes_string(global_y); // error + +global_y = 42; // shouldn't pollute linear refinement + +// local write from method +// + +function local_meth() { + + var local_y = "hello"; + + var local_o = { + f: function() { }, + g: function() { local_y = 42; } + } + + local_o.f(); + takes_string(local_y); // ok + + local_o.g(); + takes_string(local_y); // error + + local_y = 42; // shouldn't pollute linear refinement +} diff --git a/tests/closure/__snapshots__/jsfmt.spec.js.snap b/tests/closure/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e0f87eb8caa1 --- /dev/null +++ b/tests/closure/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,256 @@ +exports[`test Closure.js 1`] = ` +"/*** + * Test tracking of variable types across closure calls. + * @flow + */ + +function takes_string(_:string) { } + +// global write from function +// + +var global_x = \"hello\"; + +function global_f() { } +function global_g() { global_x = 42; } + +global_f(); +takes_string(global_x); // ok + +global_g(); +takes_string(global_x); // error + +global_x = 42; // shouldn\'t pollute linear refinement + +// local write from function +// + +function local_func() { + + var local_x = \"hello\"; + + function local_f() { } + function local_g() { local_x = 42; } + + local_f(); + takes_string(local_x); // ok + + local_g(); + takes_string(local_x); // error + + local_x = 42; // shouldn\'t pollute linear refinement +} + +// global write from method +// + +var global_y = \"hello\"; + +var global_o = { + f: function() { }, + g: function() { global_y = 42; } +} + +global_o.f(); +takes_string(global_y); // ok + +global_o.g(); +takes_string(global_y); // error + +global_y = 42; // shouldn\'t pollute linear refinement + +// local write from method +// + +function local_meth() { + + var local_y = \"hello\"; + + var local_o = { + f: function() { }, + g: function() { local_y = 42; } + } + + local_o.f(); + takes_string(local_y); // ok + + local_o.g(); + takes_string(local_y); // error + + local_y = 42; // shouldn\'t pollute linear refinement +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/*** + * Test tracking of variable types across closure calls. + * @flow + */ +function takes_string(_: string) { + +} +// global write from function +// +var global_x = \"hello\"; +function global_f() { + +} +function global_g() { + global_x = 42; +} +global_f(); +takes_string(global_x);// ok +global_g(); +takes_string(global_x);// error +global_x = 42;// shouldn\'t pollute linear refinement +// local write from function +// +function local_func() { + var local_x = \"hello\"; + function local_f() { + + } + function local_g() { + local_x = 42; + } + local_f(); + takes_string(local_x);// ok + local_g(); + takes_string(local_x);// error + local_x = 42;// shouldn\'t pollute linear refinement +} +// global write from method +// +var global_y = \"hello\"; +var global_o = { + f: function() { + + }, + g: function() { + global_y = 42; + } +}; +global_o.f(); +takes_string(global_y);// ok +global_o.g(); +takes_string(global_y);// error +global_y = 42;// shouldn\'t pollute linear refinement +// local write from method +// +function local_meth() { + var local_y = \"hello\"; + var local_o = { + f: function() { + + }, + g: function() { + local_y = 42; + } + }; + local_o.f(); + takes_string(local_y);// ok + local_o.g(); + takes_string(local_y);// error + local_y = 42;// shouldn\'t pollute linear refinement +} + +" +`; + +exports[`test cond_havoc.js 1`] = ` +"// @flow + +// from sam, https://github.com/facebook/flow/issues/780 +// call to f() within if should properly havoc x. +// +function example(b: bool): number { + var x = 0; + function f() { x = \"\" } + if (b) { + f(); + } + return x; // error, string ~/~> number (return type anno) TODO +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// from sam, https://github.com/facebook/flow/issues/780 +// call to f() within if should properly havoc x. +// +function example(b: boolean): number { + var x = 0; + function f() { + x = \"\"; + } + if (b) { + f(); + } + return x;// error, string ~/~> number (return type anno) TODO +} + +" +`; + +exports[`test const.js 1`] = ` +"/*** + * consts retain refinements + * @flow + */ + +// global, anybody can call it at any time +var call_me: () => void = () => {}; + +function g(x: ?number) { + + const const_x = x; + if (const_x) { + // ok: if const_x is truthy here, it\'s truthy everywhere + call_me = () => { var y:number = const_x; }; + } + + var var_x = x; + if (var_x) { + // error: var_x might no longer be truthy when call_me is called + call_me = () => { var y:number = var_x; }; // error + } + var_x = null; +} + +function h(x: number | string | boolean) { + + const const_x = x; + if (typeof(const_x) == \"number\") { + call_me = () => { var y:number = const_x; }; // ok + } else if (typeof(const_x) == \"string\") { + call_me = () => { var y:string = const_x; }; // ok + } else if (typeof(const_x) == \"boolean\") { + call_me = () => { var y:boolean = const_x; }; // ok + } + + var var_x = x; + if (typeof(var_x) == \"number\") { + call_me = () => { var y:number = var_x; }; // error + } else if (typeof(var_x) == \"string\") { + call_me = () => { var y:string = var_x; }; // error + } else if (typeof(var_x) == \"boolean\") { + call_me = () => { var y:boolean = var_x; }; // error + } +} + +// in a galaxy far far away +call_me(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/closure/cond_havoc.js b/tests/closure/cond_havoc.js new file mode 100644 index 000000000000..d4364f3280a2 --- /dev/null +++ b/tests/closure/cond_havoc.js @@ -0,0 +1,13 @@ +// @flow + +// from sam, https://github.com/facebook/flow/issues/780 +// call to f() within if should properly havoc x. +// +function example(b: bool): number { + var x = 0; + function f() { x = "" } + if (b) { + f(); + } + return x; // error, string ~/~> number (return type anno) TODO +} diff --git a/tests/closure/const.js b/tests/closure/const.js new file mode 100644 index 000000000000..e16e12efc5c8 --- /dev/null +++ b/tests/closure/const.js @@ -0,0 +1,47 @@ +/*** + * consts retain refinements + * @flow + */ + +// global, anybody can call it at any time +var call_me: () => void = () => {}; + +function g(x: ?number) { + + const const_x = x; + if (const_x) { + // ok: if const_x is truthy here, it's truthy everywhere + call_me = () => { var y:number = const_x; }; + } + + var var_x = x; + if (var_x) { + // error: var_x might no longer be truthy when call_me is called + call_me = () => { var y:number = var_x; }; // error + } + var_x = null; +} + +function h(x: number | string | boolean) { + + const const_x = x; + if (typeof(const_x) == "number") { + call_me = () => { var y:number = const_x; }; // ok + } else if (typeof(const_x) == "string") { + call_me = () => { var y:string = const_x; }; // ok + } else if (typeof(const_x) == "boolean") { + call_me = () => { var y:boolean = const_x; }; // ok + } + + var var_x = x; + if (typeof(var_x) == "number") { + call_me = () => { var y:number = var_x; }; // error + } else if (typeof(var_x) == "string") { + call_me = () => { var y:string = var_x; }; // error + } else if (typeof(var_x) == "boolean") { + call_me = () => { var y:boolean = var_x; }; // error + } +} + +// in a galaxy far far away +call_me(); diff --git a/tests/closure/jsfmt.spec.js b/tests/closure/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/closure/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/commonjs/Abs.js b/tests/commonjs/Abs.js new file mode 100644 index 000000000000..965e99f9f476 --- /dev/null +++ b/tests/commonjs/Abs.js @@ -0,0 +1,4 @@ + +function f(x:string) { } + +module.exports = f; diff --git a/tests/commonjs/Rel.js b/tests/commonjs/Rel.js new file mode 100644 index 000000000000..f6b1b97972c4 --- /dev/null +++ b/tests/commonjs/Rel.js @@ -0,0 +1,4 @@ + +var f = require('./Abs'); + +f(0); diff --git a/tests/commonjs/__snapshots__/jsfmt.spec.js.snap b/tests/commonjs/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e28e7d3eacff --- /dev/null +++ b/tests/commonjs/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test Abs.js 1`] = ` +" +function f(x:string) { } + +module.exports = f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function f(x: string) { + +} +module.exports = f; + +" +`; + +exports[`test Rel.js 1`] = ` +" +var f = require('./Abs'); + +f(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var f = require("./Abs"); +f(0); + +" +`; diff --git a/tests/commonjs/jsfmt.spec.js b/tests/commonjs/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/commonjs/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/computed_props/__snapshots__/jsfmt.spec.js.snap b/tests/computed_props/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b9d5978c4d68 --- /dev/null +++ b/tests/computed_props/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,133 @@ +exports[`test test.js 1`] = ` +"var ColorId = { + RED: 'R', + GREEN: 'G', + BLUE: 'B', +}; + +var ColorNumber = { + RED: 'ff0000', + GREEN: '00ff00', + BLUE: '0000ff', +}; + +var ColorIdToNumber = { + [ColorId.RED]: ColorNumber.RED, + [ColorId.GREEN]: ColorNumber.GREEN, + [ColorId.BLUE]: ColorNumber.BLUE, +}; + +(ColorIdToNumber[ColorId.RED]: 'ffffff'); // oops + +ColorIdToNumber.XXX; // oops + +module.exports = { ColorId, ColorNumber }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var ColorId = { RED: "R", GREEN: "G", BLUE: "B" }; +var ColorNumber = { RED: "ff0000", GREEN: "00ff00", BLUE: "0000ff" }; +var ColorIdToNumber = { + [ColorId.RED]: ColorNumber.RED, + [ColorId.GREEN]: ColorNumber.GREEN, + [ColorId.BLUE]: ColorNumber.BLUE +}; +(ColorIdToNumber[ColorId.RED]: "ffffff");// oops +ColorIdToNumber.XXX;// oops +module.exports = { ColorId, ColorNumber }; + +" +`; + +exports[`test test2.js 1`] = ` +"var { ColorId, ColorNumber } = require('./test'); +var ColorIdToNumber = { + [ColorId.RED]: ColorNumber.RED, + [ColorId.GREEN]: ColorNumber.GREEN, + [ColorId.BLUE]: ColorNumber.BLUE, +}; + +(ColorIdToNumber[ColorId.GREEN]: 'ffffff'); // oops + +module.exports = ColorIdToNumber; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var { ColorId, ColorNumber } = require("./test"); +var ColorIdToNumber = { + [ColorId.RED]: ColorNumber.RED, + [ColorId.GREEN]: ColorNumber.GREEN, + [ColorId.BLUE]: ColorNumber.BLUE +}; +(ColorIdToNumber[ColorId.GREEN]: "ffffff");// oops +module.exports = ColorIdToNumber; + +" +`; + +exports[`test test3.js 1`] = ` +"var { ColorId } = require('./test'); +var ColorIdToNumber = require('./test2'); + +(ColorIdToNumber[ColorId.BLUE]: 'ffffff'); // oops +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var { ColorId } = require("./test"); +var ColorIdToNumber = require("./test2"); +(ColorIdToNumber[ColorId.BLUE]: "ffffff");// oops + +" +`; + +exports[`test test4.js 1`] = ` +"module.exports = 'hello'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = "hello"; + +" +`; + +exports[`test test5.js 1`] = ` +"var hello = require('./test4'); +var dummy = require('./test'); +module.exports = { + ...dummy, + [hello]: 'world', + ...dummy, +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var hello = require("./test4"); +var dummy = require("./test"); +module.exports = { ...dummy, [hello]: "world", ...dummy }; + +" +`; + +exports[`test test6.js 1`] = ` +"var o = require('./test5'); +(o.hello: 'nothing'); // oops +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = require("./test5"); +(o.hello: "nothing");// oops + +" +`; + +exports[`test test7.js 1`] = ` +"var obj = {x: 0, m() { return this.x }} +var x: string = obj['m'](); // error, number ~> string + +var arr = [function() { return this.length }]; +var y: string = arr[0](); // error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var obj = { + x: 0, + m() { + return this.x; + } +}; +var x: string = obj["m"]();// error, number ~> string +var arr = [ + function() { + return this.length; + } +]; +var y: string = arr[0]();// error: number ~> string + +" +`; diff --git a/tests/computed_props/jsfmt.spec.js b/tests/computed_props/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/computed_props/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/computed_props/test.js b/tests/computed_props/test.js new file mode 100644 index 000000000000..4c65f895474e --- /dev/null +++ b/tests/computed_props/test.js @@ -0,0 +1,23 @@ +var ColorId = { + RED: 'R', + GREEN: 'G', + BLUE: 'B', +}; + +var ColorNumber = { + RED: 'ff0000', + GREEN: '00ff00', + BLUE: '0000ff', +}; + +var ColorIdToNumber = { + [ColorId.RED]: ColorNumber.RED, + [ColorId.GREEN]: ColorNumber.GREEN, + [ColorId.BLUE]: ColorNumber.BLUE, +}; + +(ColorIdToNumber[ColorId.RED]: 'ffffff'); // oops + +ColorIdToNumber.XXX; // oops + +module.exports = { ColorId, ColorNumber }; diff --git a/tests/computed_props/test2.js b/tests/computed_props/test2.js new file mode 100644 index 000000000000..02f05991d5ed --- /dev/null +++ b/tests/computed_props/test2.js @@ -0,0 +1,10 @@ +var { ColorId, ColorNumber } = require('./test'); +var ColorIdToNumber = { + [ColorId.RED]: ColorNumber.RED, + [ColorId.GREEN]: ColorNumber.GREEN, + [ColorId.BLUE]: ColorNumber.BLUE, +}; + +(ColorIdToNumber[ColorId.GREEN]: 'ffffff'); // oops + +module.exports = ColorIdToNumber; diff --git a/tests/computed_props/test3.js b/tests/computed_props/test3.js new file mode 100644 index 000000000000..90bd0ad2a413 --- /dev/null +++ b/tests/computed_props/test3.js @@ -0,0 +1,4 @@ +var { ColorId } = require('./test'); +var ColorIdToNumber = require('./test2'); + +(ColorIdToNumber[ColorId.BLUE]: 'ffffff'); // oops diff --git a/tests/computed_props/test4.js b/tests/computed_props/test4.js new file mode 100644 index 000000000000..76e8a568d58d --- /dev/null +++ b/tests/computed_props/test4.js @@ -0,0 +1 @@ +module.exports = 'hello'; diff --git a/tests/computed_props/test5.js b/tests/computed_props/test5.js new file mode 100644 index 000000000000..4979c54c80bd --- /dev/null +++ b/tests/computed_props/test5.js @@ -0,0 +1,7 @@ +var hello = require('./test4'); +var dummy = require('./test'); +module.exports = { + ...dummy, + [hello]: 'world', + ...dummy, +}; diff --git a/tests/computed_props/test6.js b/tests/computed_props/test6.js new file mode 100644 index 000000000000..89ac05f48a7f --- /dev/null +++ b/tests/computed_props/test6.js @@ -0,0 +1,2 @@ +var o = require('./test5'); +(o.hello: 'nothing'); // oops diff --git a/tests/computed_props/test7.js b/tests/computed_props/test7.js new file mode 100644 index 000000000000..003700429d8d --- /dev/null +++ b/tests/computed_props/test7.js @@ -0,0 +1,5 @@ +var obj = {x: 0, m() { return this.x }} +var x: string = obj['m'](); // error, number ~> string + +var arr = [function() { return this.length }]; +var y: string = arr[0](); // error: number ~> string diff --git a/tests/conditional/__snapshots__/jsfmt.spec.js.snap b/tests/conditional/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a1d029d6c9ed --- /dev/null +++ b/tests/conditional/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,50 @@ +exports[`test conditional.js 1`] = ` +"/* @flow */ + +function a(): number { + var x: ?string = null; + return x ? 1 : 0; +} + +function b(): number { + var x: ?number = null; + return x != null ? x : 0; +} + +function c(): number { + // equivalent to \`return (x && 1) || 0\` + var x = false; + var temp = (x ? 1 : x); + return temp ? temp : 0; +} + +function d(): string { // expected \`: number | boolean\` + // equivalent to \`return x != null && x\` + var x: ?number = null; + return (x != null) ? x : (x != null); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function a(): number { + var x: ?string = null; + return (x ? 1 : 0); +} +function b(): number { + var x: ?number = null; + return (x != null ? x : 0); +} +function c(): number { + // equivalent to \`return (x && 1) || 0\` + var x = false; + var temp = (x ? 1 : x); + return (temp ? temp : 0); +} +function d(): string { + // expected \`: number | boolean\` + // equivalent to \`return x != null && x\` + var x: ?number = null; + return (x != null ? x : x != null); +} + +" +`; diff --git a/tests/conditional/conditional.js b/tests/conditional/conditional.js new file mode 100644 index 000000000000..b66892cfd1a2 --- /dev/null +++ b/tests/conditional/conditional.js @@ -0,0 +1,24 @@ +/* @flow */ + +function a(): number { + var x: ?string = null; + return x ? 1 : 0; +} + +function b(): number { + var x: ?number = null; + return x != null ? x : 0; +} + +function c(): number { + // equivalent to `return (x && 1) || 0` + var x = false; + var temp = (x ? 1 : x); + return temp ? temp : 0; +} + +function d(): string { // expected `: number | boolean` + // equivalent to `return x != null && x` + var x: ?number = null; + return (x != null) ? x : (x != null); +} diff --git a/tests/conditional/jsfmt.spec.js b/tests/conditional/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/conditional/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_all/__snapshots__/jsfmt.spec.js.snap b/tests/config_all/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..abf7e57cd722 --- /dev/null +++ b/tests/config_all/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test no_at_flow.js 1`] = ` +"var x: number = "not a number"; // Error: string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: number = "not a number";// Error: string ~> number + +" +`; diff --git a/tests/config_all/jsfmt.spec.js b/tests/config_all/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_all/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_all/no_at_flow.js b/tests/config_all/no_at_flow.js new file mode 100644 index 000000000000..3d01d67f0e7e --- /dev/null +++ b/tests/config_all/no_at_flow.js @@ -0,0 +1 @@ +var x: number = "not a number"; // Error: string ~> number diff --git a/tests/config_all_false/__snapshots__/jsfmt.spec.js.snap b/tests/config_all_false/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..dc6f37acc919 --- /dev/null +++ b/tests/config_all_false/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test no_at_flow.js 1`] = ` +"var x: number = "not a number"; // No error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: number = "not a number";// No error + +" +`; diff --git a/tests/config_all_false/jsfmt.spec.js b/tests/config_all_false/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_all_false/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_all_false/no_at_flow.js b/tests/config_all_false/no_at_flow.js new file mode 100644 index 000000000000..656a221a89c6 --- /dev/null +++ b/tests/config_all_false/no_at_flow.js @@ -0,0 +1 @@ +var x: number = "not a number"; // No error diff --git a/tests/config_all_weak/__snapshots__/jsfmt.spec.js.snap b/tests/config_all_weak/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a9e1e0a2a26c --- /dev/null +++ b/tests/config_all_weak/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test no_at_flow.js 1`] = ` +"var x; + +x.length; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x; +x.length; + +" +`; diff --git a/tests/config_all_weak/jsfmt.spec.js b/tests/config_all_weak/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_all_weak/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_all_weak/no_at_flow.js b/tests/config_all_weak/no_at_flow.js new file mode 100644 index 000000000000..eacadf62df20 --- /dev/null +++ b/tests/config_all_weak/no_at_flow.js @@ -0,0 +1,3 @@ +var x; + +x.length; diff --git a/tests/config_file_extensions/__snapshots__/jsfmt.spec.js.snap b/tests/config_file_extensions/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..dfca8fc58e4b --- /dev/null +++ b/tests/config_file_extensions/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test test.js 1`] = ` +"/* + * @flow + */ + +function foo(x) { + var a: number = 'asdf'; + return x * 10; +} + +// This file should be ignored, so this should not result in an error +foo('Hello, world!'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @flow + */ +function foo(x) { + var a: number = "asdf"; + return x * 10; +} +// This file should be ignored, so this should not result in an error +foo("Hello, world!"); + +" +`; diff --git a/tests/config_file_extensions/jsfmt.spec.js b/tests/config_file_extensions/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_file_extensions/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_file_extensions/test.js b/tests/config_file_extensions/test.js new file mode 100644 index 000000000000..ec34cbda765b --- /dev/null +++ b/tests/config_file_extensions/test.js @@ -0,0 +1,11 @@ +/* + * @flow + */ + +function foo(x) { + var a: number = 'asdf'; + return x * 10; +} + +// This file should be ignored, so this should not result in an error +foo('Hello, world!'); diff --git a/tests/config_ignore/__snapshots__/jsfmt.spec.js.snap b/tests/config_ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e2b382361017 --- /dev/null +++ b/tests/config_ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,12 @@ +exports[`test foo.js 1`] = ` +"/* @flow */ + +// No error, this file is ignored +var x: number = "string"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// No error, this file is ignored +var x: number = "string"; + +" +`; diff --git a/tests/config_ignore/dir/__snapshots__/jsfmt.spec.js.snap b/tests/config_ignore/dir/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d18373a3898c --- /dev/null +++ b/tests/config_ignore/dir/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test foo.js 1`] = ` +"/* @flow */ + +var x: number = "string"; // Error string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var x: number = "string";// Error string ~> number + +" +`; diff --git a/tests/config_ignore/dir/foo.js b/tests/config_ignore/dir/foo.js new file mode 100644 index 000000000000..b9901bd5b99b --- /dev/null +++ b/tests/config_ignore/dir/foo.js @@ -0,0 +1,3 @@ +/* @flow */ + +var x: number = "string"; // Error string ~> number diff --git a/tests/config_ignore/dir/jsfmt.spec.js b/tests/config_ignore/dir/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_ignore/dir/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_ignore/foo.js b/tests/config_ignore/foo.js new file mode 100644 index 000000000000..1b0029abb16f --- /dev/null +++ b/tests/config_ignore/foo.js @@ -0,0 +1,4 @@ +/* @flow */ + +// No error, this file is ignored +var x: number = "string"; diff --git a/tests/config_ignore/jsfmt.spec.js b/tests/config_ignore/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_ignore/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_name_mapper_PROJECT_ROOT-1.0/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..049efd334d2b --- /dev/null +++ b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test main.js 1`] = ` +"// @flow + +import {test} from 'testmodule'; + +var a: number = test; +var b: string = test; // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { test } from "testmodule"; +var a: number = test; +var b: string = test;// Error: number ~> string + +" +`; diff --git a/tests/config_module_name_mapper_PROJECT_ROOT-1.0/jsfmt.spec.js b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_name_mapper_PROJECT_ROOT-1.0/main.js b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/main.js new file mode 100644 index 000000000000..8168ba9c3ce0 --- /dev/null +++ b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/main.js @@ -0,0 +1,6 @@ +// @flow + +import {test} from 'testmodule'; + +var a: number = test; +var b: string = test; // Error: number ~> string diff --git a/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8f51a9c7ac9d --- /dev/null +++ b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test testmodule.js 1`] = ` +"// @flow + +export let test = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export let test = 42; + +" +`; diff --git a/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/jsfmt.spec.js b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/testmodule.js b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/testmodule.js new file mode 100644 index 000000000000..1e0fc93cca56 --- /dev/null +++ b/tests/config_module_name_mapper_PROJECT_ROOT-1.0/src/testmodule.js @@ -0,0 +1,3 @@ +// @flow + +export let test = 42; diff --git a/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2ad57396e31f --- /dev/null +++ b/tests/config_module_name_mapper_filetype/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,12 @@ +exports[`test test.js 1`] = ` +"// @flow + +import {className} from "./SomeCSSFile.css"; +import {doesntExist} from "./SomeCSSFile.css"; // Error: \`doestExist\` isn't an export +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { className } from "./SomeCSSFile.css"; +import { doesntExist } from "./SomeCSSFile.css";// Error: \`doestExist\` isn't an export + +" +`; diff --git a/tests/config_module_name_mapper_filetype/jsfmt.spec.js b/tests/config_module_name_mapper_filetype/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_name_mapper_filetype/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_name_mapper_filetype/test.js b/tests/config_module_name_mapper_filetype/test.js new file mode 100644 index 000000000000..8b209dd801c6 --- /dev/null +++ b/tests/config_module_name_mapper_filetype/test.js @@ -0,0 +1,4 @@ +// @flow + +import {className} from "./SomeCSSFile.css"; +import {doesntExist} from "./SomeCSSFile.css"; // Error: `doestExist` isn't an export diff --git a/tests/config_module_name_rewrite_haste/A.js b/tests/config_module_name_rewrite_haste/A.js new file mode 100644 index 000000000000..ca5185b4bcf6 --- /dev/null +++ b/tests/config_module_name_rewrite_haste/A.js @@ -0,0 +1,13 @@ +/* @flow */ + +var m1 = require('1DoesntExist'); +import {numVal as numVal1} from '1DoesntExist'; +var a_1: number = m1.numVal; +var a_2: number = numVal1; + +// Error: 'Exists2' is not a valid module name +// +// This tests that, for haste, the first name_mapper regexp that happens to +// match the given module name string is picked. +var m2 = require('2DoesntExist'); // Error +import {numVal as numVal2} from '3DoesntExist'; // Error diff --git a/tests/config_module_name_rewrite_haste/Exists.js b/tests/config_module_name_rewrite_haste/Exists.js new file mode 100644 index 000000000000..b91779d3ebe0 --- /dev/null +++ b/tests/config_module_name_rewrite_haste/Exists.js @@ -0,0 +1,8 @@ +/** + * @providesModule Exists + * @flow + */ + +module.exports = { + numVal: 42 +}; diff --git a/tests/config_module_name_rewrite_haste/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_name_rewrite_haste/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6ccef0e73a9b --- /dev/null +++ b/tests/config_module_name_rewrite_haste/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,48 @@ +exports[`test A.js 1`] = ` +"/* @flow */ + +var m1 = require('1DoesntExist'); +import {numVal as numVal1} from '1DoesntExist'; +var a_1: number = m1.numVal; +var a_2: number = numVal1; + +// Error: 'Exists2' is not a valid module name +// +// This tests that, for haste, the first name_mapper regexp that happens to +// match the given module name string is picked. +var m2 = require('2DoesntExist'); // Error +import {numVal as numVal2} from '3DoesntExist'; // Error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var m1 = require("1DoesntExist"); +import { numVal as numVal1 } from "1DoesntExist"; +var a_1: number = m1.numVal; +var a_2: number = numVal1; +// Error: 'Exists2' is not a valid module name +// +// This tests that, for haste, the first name_mapper regexp that happens to +// match the given module name string is picked. +var m2 = require("2DoesntExist");// Error +import { numVal as numVal2 } from "3DoesntExist";// Error + +" +`; + +exports[`test Exists.js 1`] = ` +"/** + * @providesModule Exists + * @flow + */ + +module.exports = { + numVal: 42 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule Exists + * @flow + */ +module.exports = { numVal: 42 }; + +" +`; diff --git a/tests/config_module_name_rewrite_haste/jsfmt.spec.js b/tests/config_module_name_rewrite_haste/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_name_rewrite_haste/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_name_rewrite_node/A.js b/tests/config_module_name_rewrite_node/A.js new file mode 100644 index 000000000000..5f42adbf50d1 --- /dev/null +++ b/tests/config_module_name_rewrite_node/A.js @@ -0,0 +1,25 @@ +/* @flow */ + +var m1 = require('./1DoesntExist'); +var a_1: number = m1.numVal; +var a_2: string = m1.numVal; // Error: number ~> string +import {numVal} from './1DoesntExist'; +var a_3: number = numVal; +var a_4: string = numVal; // Error: number ~> string + +// This tests that, for node, the first name mapping that both matches *and* +// results in a valid module filename is picked. +var m2 = require('./2DoesntExist'); +var b_1: number = m2.numVal; +var b_2: string = m2.numVal; // Error: number ~> string +import {numVal as numVal2} from './3DoesntExist'; +var b_3: number = numVal2; +var b_4: string = numVal2; // Error: number ~> string + +// node_modules/Exists/index.js +var m3 = require('4DoesntExist'); +var c_1: number = m3.numVal; +var c_2: string = m3.numVal; // Error: number ~> string +import {numVal as numVal3} from '5DoesntExist'; +var c_3: number = numVal3; +var c_4: string = numVal3; // Error: number ~> string diff --git a/tests/config_module_name_rewrite_node/Exists.js b/tests/config_module_name_rewrite_node/Exists.js new file mode 100644 index 000000000000..1b63e9c8bbf7 --- /dev/null +++ b/tests/config_module_name_rewrite_node/Exists.js @@ -0,0 +1,5 @@ +/* @flow */ + +module.exports = { + numVal: 42 +}; diff --git a/tests/config_module_name_rewrite_node/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_name_rewrite_node/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e8252c84db6e --- /dev/null +++ b/tests/config_module_name_rewrite_node/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,65 @@ +exports[`test A.js 1`] = ` +"/* @flow */ + +var m1 = require('./1DoesntExist'); +var a_1: number = m1.numVal; +var a_2: string = m1.numVal; // Error: number ~> string +import {numVal} from './1DoesntExist'; +var a_3: number = numVal; +var a_4: string = numVal; // Error: number ~> string + +// This tests that, for node, the first name mapping that both matches *and* +// results in a valid module filename is picked. +var m2 = require('./2DoesntExist'); +var b_1: number = m2.numVal; +var b_2: string = m2.numVal; // Error: number ~> string +import {numVal as numVal2} from './3DoesntExist'; +var b_3: number = numVal2; +var b_4: string = numVal2; // Error: number ~> string + +// node_modules/Exists/index.js +var m3 = require('4DoesntExist'); +var c_1: number = m3.numVal; +var c_2: string = m3.numVal; // Error: number ~> string +import {numVal as numVal3} from '5DoesntExist'; +var c_3: number = numVal3; +var c_4: string = numVal3; // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var m1 = require("./1DoesntExist"); +var a_1: number = m1.numVal; +var a_2: string = m1.numVal;// Error: number ~> string +import { numVal } from "./1DoesntExist"; +var a_3: number = numVal; +var a_4: string = numVal;// Error: number ~> string +// This tests that, for node, the first name mapping that both matches *and* +// results in a valid module filename is picked. +var m2 = require("./2DoesntExist"); +var b_1: number = m2.numVal; +var b_2: string = m2.numVal;// Error: number ~> string +import { numVal as numVal2 } from "./3DoesntExist"; +var b_3: number = numVal2; +var b_4: string = numVal2;// Error: number ~> string +// node_modules/Exists/index.js +var m3 = require("4DoesntExist"); +var c_1: number = m3.numVal; +var c_2: string = m3.numVal;// Error: number ~> string +import { numVal as numVal3 } from "5DoesntExist"; +var c_3: number = numVal3; +var c_4: string = numVal3;// Error: number ~> string + +" +`; + +exports[`test Exists.js 1`] = ` +"/* @flow */ + +module.exports = { + numVal: 42 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports = { numVal: 42 }; + +" +`; diff --git a/tests/config_module_name_rewrite_node/jsfmt.spec.js b/tests/config_module_name_rewrite_node/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_name_rewrite_node/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_system_node_resolve_dirname/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_system_node_resolve_dirname/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f6a5d798672e --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test toplevel.js 1`] = ` +"// @flow + +import {name} from "testproj"; + +(name: "node_modules/testproj"); +(name: "custom_resolve_dir/testproj"); // Error: Resolve from node_modules first! +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { name } from "testproj"; +(name: "node_modules/testproj"); +(name: "custom_resolve_dir/testproj");// Error: Resolve from node_modules first! + +" +`; diff --git a/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..075fd4fa9f24 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test index.js 1`] = ` +"// @flow + +export var name: "otherdir/testproj" = "otherdir/testproj"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export var name: "otherdir/testproj" = "otherdir/testproj"; + +" +`; diff --git a/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/index.js b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/index.js new file mode 100644 index 000000000000..25037710b852 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "otherdir/testproj" = "otherdir/testproj"; diff --git a/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/jsfmt.spec.js b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..23b55094cf43 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test index.js 1`] = ` +"// @flow + +export var name: "otherdir/testproj2" = "otherdir/testproj2"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export var name: "otherdir/testproj2" = "otherdir/testproj2"; + +" +`; diff --git a/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/index.js b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/index.js new file mode 100644 index 000000000000..ddd1f996f728 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "otherdir/testproj2" = "otherdir/testproj2"; diff --git a/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/jsfmt.spec.js b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/custom_resolve_dir/testproj2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_system_node_resolve_dirname/jsfmt.spec.js b/tests/config_module_system_node_resolve_dirname/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_system_node_resolve_dirname/subdir/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_system_node_resolve_dirname/subdir/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a3e521c32436 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/subdir/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test sublevel.js 1`] = ` +"// @flow + +import {name} from "testproj2"; + +(name: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! +(name: "subdir/custom_resolve_dir/testproj2"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { name } from "testproj2"; +(name: "node_modules/testproj2");// Error: Resolve from sibling 'custom_resolve_dir' first! +(name: "subdir/custom_resolve_dir/testproj2"); + +" +`; diff --git a/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap b/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bec06490d473 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test index.js 1`] = ` +"// @flow + +export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; + +" +`; diff --git a/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/index.js b/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/index.js new file mode 100644 index 000000000000..af4294a36c2a --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/index.js @@ -0,0 +1,3 @@ +// @flow + +export var name: "subdir/custom_resolve_dir/testproj2" = "subdir/custom_resolve_dir/testproj2"; diff --git a/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/jsfmt.spec.js b/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/subdir/custom_resolve_dir/testproj2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_system_node_resolve_dirname/subdir/jsfmt.spec.js b/tests/config_module_system_node_resolve_dirname/subdir/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/subdir/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_module_system_node_resolve_dirname/subdir/sublevel.js b/tests/config_module_system_node_resolve_dirname/subdir/sublevel.js new file mode 100644 index 000000000000..e080e5378dcd --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/subdir/sublevel.js @@ -0,0 +1,6 @@ +// @flow + +import {name} from "testproj2"; + +(name: "node_modules/testproj2"); // Error: Resolve from sibling 'custom_resolve_dir' first! +(name: "subdir/custom_resolve_dir/testproj2"); diff --git a/tests/config_module_system_node_resolve_dirname/toplevel.js b/tests/config_module_system_node_resolve_dirname/toplevel.js new file mode 100644 index 000000000000..5207c12bbba2 --- /dev/null +++ b/tests/config_module_system_node_resolve_dirname/toplevel.js @@ -0,0 +1,6 @@ +// @flow + +import {name} from "testproj"; + +(name: "node_modules/testproj"); +(name: "custom_resolve_dir/testproj"); // Error: Resolve from node_modules first! diff --git a/tests/config_munging_underscores/__snapshots__/jsfmt.spec.js.snap b/tests/config_munging_underscores/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9f42da9c160a --- /dev/null +++ b/tests/config_munging_underscores/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,98 @@ +exports[`test chain.js 1`] = ` +"/* @flow */ + +class A { + _property1: number; + static _sProperty: number; + + constructor() { + this._property1 = 5; + } + _method1(): number { + return 1; + } + static _sMethod(): string { + return "some string"; + } +} +A._sProperty = 48; + +class B extends A { + _property1: string; + static _sProperty: string; + + constructor() { + super(); + this._property1 = "another string"; + } + _method1(): string { + return "yet another string"; + } + static _sMethod(): number { + return 23; + } +} +B._sProperty = "B._sProperty string"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class A { + _property1: number; + static _sProperty: number; + constructor() { + this._property1 = 5; + } + _method1(): number { + return 1; + } + _sMethod(): string { + return "some string"; + } +} +A._sProperty = 48; +class B extends A { + _property1: string; + static _sProperty: string; + constructor() { + super(); + this._property1 = "another string"; + } + _method1(): string { + return "yet another string"; + } + _sMethod(): number { + return 23; + } +} +B._sProperty = "B._sProperty string"; + +" +`; + +exports[`test commonjs_export.js 1`] = ` +"/* @flow */ + +class C { + _p: string; +} + +module.exports = new C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class C { + _p: string; +} +module.exports = new C(); + +" +`; + +exports[`test commonjs_import.js 1`] = ` +"/* @flow */ + +import {_p} from "./commonjs_export"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +import { _p } from "./commonjs_export"; + +" +`; diff --git a/tests/config_munging_underscores/chain.js b/tests/config_munging_underscores/chain.js new file mode 100644 index 000000000000..6eb45e480216 --- /dev/null +++ b/tests/config_munging_underscores/chain.js @@ -0,0 +1,34 @@ +/* @flow */ + +class A { + _property1: number; + static _sProperty: number; + + constructor() { + this._property1 = 5; + } + _method1(): number { + return 1; + } + static _sMethod(): string { + return "some string"; + } +} +A._sProperty = 48; + +class B extends A { + _property1: string; + static _sProperty: string; + + constructor() { + super(); + this._property1 = "another string"; + } + _method1(): string { + return "yet another string"; + } + static _sMethod(): number { + return 23; + } +} +B._sProperty = "B._sProperty string"; diff --git a/tests/config_munging_underscores/commonjs_export.js b/tests/config_munging_underscores/commonjs_export.js new file mode 100644 index 000000000000..bbecd1ae4574 --- /dev/null +++ b/tests/config_munging_underscores/commonjs_export.js @@ -0,0 +1,7 @@ +/* @flow */ + +class C { + _p: string; +} + +module.exports = new C; diff --git a/tests/config_munging_underscores/commonjs_import.js b/tests/config_munging_underscores/commonjs_import.js new file mode 100644 index 000000000000..f63d24a7f7ad --- /dev/null +++ b/tests/config_munging_underscores/commonjs_import.js @@ -0,0 +1,3 @@ +/* @flow */ + +import {_p} from "./commonjs_export"; diff --git a/tests/config_munging_underscores/jsfmt.spec.js b/tests/config_munging_underscores/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_munging_underscores/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/config_munging_underscores2/__snapshots__/jsfmt.spec.js.snap b/tests/config_munging_underscores2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..89fc8a4c07b3 --- /dev/null +++ b/tests/config_munging_underscores2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,69 @@ +exports[`test chain.js 1`] = ` +"/* @flow */ + +class A { + _property1: number; + static _sProperty: number; + + constructor() { + this._property1 = 5; + } + _method1(): number { + return 1; + } + static _sMethod(): string { + return "some string"; + } +} +A._sProperty = 48; + +class B extends A { + _property1: string; + static _sProperty: string; + + constructor() { + super(); + this._property1 = "another string"; + } + _method1(): string { + return "yet another string"; + } + static _sMethod(): number { + return 23; + } +} +B._sProperty = "B._sProperty string"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class A { + _property1: number; + static _sProperty: number; + constructor() { + this._property1 = 5; + } + _method1(): number { + return 1; + } + _sMethod(): string { + return "some string"; + } +} +A._sProperty = 48; +class B extends A { + _property1: string; + static _sProperty: string; + constructor() { + super(); + this._property1 = "another string"; + } + _method1(): string { + return "yet another string"; + } + _sMethod(): number { + return 23; + } +} +B._sProperty = "B._sProperty string"; + +" +`; diff --git a/tests/config_munging_underscores2/chain.js b/tests/config_munging_underscores2/chain.js new file mode 100644 index 000000000000..6eb45e480216 --- /dev/null +++ b/tests/config_munging_underscores2/chain.js @@ -0,0 +1,34 @@ +/* @flow */ + +class A { + _property1: number; + static _sProperty: number; + + constructor() { + this._property1 = 5; + } + _method1(): number { + return 1; + } + static _sMethod(): string { + return "some string"; + } +} +A._sProperty = 48; + +class B extends A { + _property1: string; + static _sProperty: string; + + constructor() { + super(); + this._property1 = "another string"; + } + _method1(): string { + return "yet another string"; + } + static _sMethod(): number { + return 23; + } +} +B._sProperty = "B._sProperty string"; diff --git a/tests/config_munging_underscores2/jsfmt.spec.js b/tests/config_munging_underscores2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/config_munging_underscores2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/const_params/__snapshots__/jsfmt.spec.js.snap b/tests/const_params/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..028d8606c6c4 --- /dev/null +++ b/tests/const_params/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,63 @@ +exports[`test test.js 1`] = ` +"/** + * test handling of const params + * - reassignment prohibited + * - durable refinements + * + * Currently gated in .flowconfig: + * + * [options] + * experimental.const_params + * + * Syntax to follow + * + * @flow + */ + +function cannot_reassign(x: string) { + x = "hey"; // error, const param cannot be reassigned +} + +// Note: const params use the same machinery as explicit +// const bindings, which are tested more extensively elsewhere. +// Here we're just making sure the machinery is hooked up. +// +function durable_refi(x: ?number) { + if (x) { + // ok: if x is truthy here, it's truthy everywhere + return () => { var y:number = x; }; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * test handling of const params + * - reassignment prohibited + * - durable refinements + * + * Currently gated in .flowconfig: + * + * [options] + * experimental.const_params + * + * Syntax to follow + * + * @flow + */ +function cannot_reassign(x: string) { + x = "hey";// error, const param cannot be reassigned +} +// Note: const params use the same machinery as explicit +// const bindings, which are tested more extensively elsewhere. +// Here we're just making sure the machinery is hooked up. +// +function durable_refi(x: ?number) { + if (x) { + // ok: if x is truthy here, it's truthy everywhere + return () => { + var y: number = x; + }; + } +} + +" +`; diff --git a/tests/const_params/jsfmt.spec.js b/tests/const_params/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/const_params/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/const_params/test.js b/tests/const_params/test.js new file mode 100644 index 000000000000..0f7838c3c1fa --- /dev/null +++ b/tests/const_params/test.js @@ -0,0 +1,29 @@ +/** + * test handling of const params + * - reassignment prohibited + * - durable refinements + * + * Currently gated in .flowconfig: + * + * [options] + * experimental.const_params + * + * Syntax to follow + * + * @flow + */ + +function cannot_reassign(x: string) { + x = "hey"; // error, const param cannot be reassigned +} + +// Note: const params use the same machinery as explicit +// const bindings, which are tested more extensively elsewhere. +// Here we're just making sure the machinery is hooked up. +// +function durable_refi(x: ?number) { + if (x) { + // ok: if x is truthy here, it's truthy everywhere + return () => { var y:number = x; }; + } +} diff --git a/tests/constructor/__snapshots__/jsfmt.spec.js.snap b/tests/constructor/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..038fdeca83c6 --- /dev/null +++ b/tests/constructor/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test constructor.js 1`] = ` +"class C { + constructor() { } +} + +class D { + constructor():number { } +} + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + constructor() { + + } +} +class D { + constructor(): number { + + } +} +module.exports = C; + +" +`; diff --git a/tests/constructor/constructor.js b/tests/constructor/constructor.js new file mode 100644 index 000000000000..92038b6e4e2d --- /dev/null +++ b/tests/constructor/constructor.js @@ -0,0 +1,9 @@ +class C { + constructor() { } +} + +class D { + constructor():number { } +} + +module.exports = C; diff --git a/tests/constructor/jsfmt.spec.js b/tests/constructor/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/constructor/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap b/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b50f3d576333 --- /dev/null +++ b/tests/constructor_annots/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,63 @@ +exports[`test constructors.js 1`] = ` +"// Foo is a class-like function +function Foo() { + this.x = 0; // constructs objects with property x +} +Foo.y = 0; // has static property y +Foo.prototype = { m() { return 0; } }; + +// exporting Foo directly doesn\'t work +// Foo\'s instance and static props are not picked up +exports.Foo = Foo; + +// so you want to type Foo, by declaring it as a class +interface IFooPrototype { + m: () => number; +} +interface IFoo extends IFooPrototype { + x: boolean; // error, should have declared x: number instead + static (): void; + static y: boolean; // error, should have declared static y: number instead +} +exports.Foo2 = (Foo: Class); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected : (19:9) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:33) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4424:8) + at Parser.pp$7.flowParseObjectType (/node_modules/babylon/lib/index.js:4809:27) + at Parser.pp$7.flowParseInterfaceish (/node_modules/babylon/lib/index.js:4575:20) + at Parser.pp$7.flowParseInterface (/node_modules/babylon/lib/index.js:4592:8) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5222:21) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test test.js 1`] = ` +"var Foo = require(\'./constructors\').Foo; +var x: string = new Foo().x; // error, found number instead of string +var y: string = Foo.y; // error, found number instead of string +var z: string = new Foo().m(); + +var Foo2 = require(\'./constructors\').Foo2; +var x2: string = new Foo2().x; // error, found boolean instead of string +var y2: string = Foo2.y; // error, found boolean instead of string +var z2: string = new Foo2().m(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var Foo = require(\"./constructors\").Foo; +var x: string = new Foo().x;// error, found number instead of string +var y: string = Foo.y;// error, found number instead of string +var z: string = new Foo().m(); +var Foo2 = require(\"./constructors\").Foo2; +var x2: string = new Foo2().x;// error, found boolean instead of string +var y2: string = Foo2.y;// error, found boolean instead of string +var z2: string = new Foo2().m(); + +" +`; diff --git a/tests/constructor_annots/constructors.js b/tests/constructor_annots/constructors.js new file mode 100644 index 000000000000..dac947e6d829 --- /dev/null +++ b/tests/constructor_annots/constructors.js @@ -0,0 +1,21 @@ +// Foo is a class-like function +function Foo() { + this.x = 0; // constructs objects with property x +} +Foo.y = 0; // has static property y +Foo.prototype = { m() { return 0; } }; + +// exporting Foo directly doesn't work +// Foo's instance and static props are not picked up +exports.Foo = Foo; + +// so you want to type Foo, by declaring it as a class +interface IFooPrototype { + m: () => number; +} +interface IFoo extends IFooPrototype { + x: boolean; // error, should have declared x: number instead + static (): void; + static y: boolean; // error, should have declared static y: number instead +} +exports.Foo2 = (Foo: Class); diff --git a/tests/constructor_annots/jsfmt.spec.js b/tests/constructor_annots/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/constructor_annots/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/constructor_annots/test.js b/tests/constructor_annots/test.js new file mode 100644 index 000000000000..985cc8b19f36 --- /dev/null +++ b/tests/constructor_annots/test.js @@ -0,0 +1,9 @@ +var Foo = require('./constructors').Foo; +var x: string = new Foo().x; // error, found number instead of string +var y: string = Foo.y; // error, found number instead of string +var z: string = new Foo().m(); + +var Foo2 = require('./constructors').Foo2; +var x2: string = new Foo2().x; // error, found boolean instead of string +var y2: string = Foo2.y; // error, found boolean instead of string +var z2: string = new Foo2().m(); diff --git a/tests/contents/ignore/__snapshots__/jsfmt.spec.js.snap b/tests/contents/ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..71e57278fc6a --- /dev/null +++ b/tests/contents/ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test dummy.js 1`] = ` +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test test.js 1`] = ` +"require('./dummy'); +var xxx = 0; +xxx +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./dummy"); +var xxx = 0; +xxx; + +" +`; diff --git a/tests/contents/ignore/dummy.js b/tests/contents/ignore/dummy.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/contents/ignore/jsfmt.spec.js b/tests/contents/ignore/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/contents/ignore/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/contents/ignore/test.js b/tests/contents/ignore/test.js new file mode 100644 index 000000000000..ac04887822df --- /dev/null +++ b/tests/contents/ignore/test.js @@ -0,0 +1,3 @@ +require('./dummy'); +var xxx = 0; +xxx diff --git a/tests/contents/no_flow/__snapshots__/jsfmt.spec.js.snap b/tests/contents/no_flow/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..71e57278fc6a --- /dev/null +++ b/tests/contents/no_flow/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test dummy.js 1`] = ` +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test test.js 1`] = ` +"require('./dummy'); +var xxx = 0; +xxx +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./dummy"); +var xxx = 0; +xxx; + +" +`; diff --git a/tests/contents/no_flow/dummy.js b/tests/contents/no_flow/dummy.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/contents/no_flow/jsfmt.spec.js b/tests/contents/no_flow/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/contents/no_flow/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/contents/no_flow/test.js b/tests/contents/no_flow/test.js new file mode 100644 index 000000000000..ac04887822df --- /dev/null +++ b/tests/contents/no_flow/test.js @@ -0,0 +1,3 @@ +require('./dummy'); +var xxx = 0; +xxx diff --git a/tests/core_tests/__snapshots__/jsfmt.spec.js.snap b/tests/core_tests/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8d649a93948a --- /dev/null +++ b/tests/core_tests/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,253 @@ +exports[`test boolean.js 1`] = ` +"// @flow + +// Boolean (the class) tests. booleans (the literals) are not part of core.js + +let tests = [ + // constructor + function() { + new Boolean(); + new Boolean(0); + new Boolean(-0); + new Boolean(null); + new Boolean(false); + new Boolean(NaN); + new Boolean(undefined); + new Boolean(\"\"); + }, + + // toString + function() { + (true).toString(); + let x: boolean = false; + x.toString(); + (new Boolean(true)).toString(); + }, + + // valueOf + function() { + ((new Boolean(0)).valueOf(): boolean); + }, + + // casting + function() { + Boolean(); + Boolean(0); + Boolean(-0); + Boolean(null); + Boolean(false); + Boolean(NaN); + Boolean(undefined); + Boolean(\"\"); + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// Boolean (the class) tests. booleans (the literals) are not part of core.js +let tests = [ + // constructor + function() { + new Boolean(); + new Boolean(0); + new Boolean(-0); + new Boolean(null); + new Boolean(false); + new Boolean(NaN); + new Boolean(undefined); + new Boolean(\"\"); + }, + // toString + function() { + true.toString(); + let x: boolean = false; + x.toString(); + new Boolean(true).toString(); + }, + // valueOf + function() { + (new Boolean(0).valueOf(): boolean); + }, + // casting + function() { + Boolean(); + Boolean(0); + Boolean(-0); + Boolean(null); + Boolean(false); + Boolean(NaN); + Boolean(undefined); + Boolean(\"\"); + } +]; + +" +`; + +exports[`test map.js 1`] = ` +"// @flow + +function* generator(): Iterable<[string, number]> { + while (true) { + yield [\'foo\', 123]; + } +} + +let tests = [ + // good constructors + function() { + let w = new Map(); + let x = new Map(null); + let y = new Map([[\'foo\', 123]]); + let z = new Map(generator()); + let a: Map = new Map(); + let b: Map = new Map([[\'foo\', 123]]); + let c: Map = new Map(generator()); + }, + + // bad constructors + function() { + let x = new Map([\'foo\', 123]); // error + let y: Map = new Map([[\'foo\', 123]]); // error + }, + + // get() + function(x: Map) { + (x.get(\'foo\'): boolean); // error, string | void + x.get(123); // error, wrong key type + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test regexp.js 1`] = ` +"// @flow + +let tests = [ + // constructor + function() { + new RegExp(\'foo\'); + new RegExp(/foo/); + new RegExp(\'foo\', \'i\'); + new RegExp(\'foo\', \'ig\'); + new RegExp(/foo/, \'i\'); // invalid in ES5, valid in ES6 + new RegExp(/foo/g, \'i\'); // invalid in ES5, valid in ES6 + }, + + // called as a function (equivalent to the constructor per ES6 21.2.3) + function() { + RegExp(\'foo\'); + RegExp(/foo/); + RegExp(\'foo\', \'i\'); + RegExp(\'foo\', \'ig\'); + RegExp(/foo/, \'i\'); // invalid in ES5, valid in ES6 + RegExp(/foo/g, \'i\'); // invalid in ES5, valid in ES6 + }, + + // invalid flags + function() { + RegExp(\'foo\', \'z\'); // error + new RegExp(\'foo\', \'z\'); // error + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // constructor + function() { + new RegExp(\"foo\"); + new RegExp(/foo/); + new RegExp(\"foo\", \"i\"); + new RegExp(\"foo\", \"ig\"); + new RegExp(/foo/, \"i\");// invalid in ES5, valid in ES6 + new RegExp(/foo/g, \"i\");// invalid in ES5, valid in ES6 + }, + // called as a function (equivalent to the constructor per ES6 21.2.3) + function() { + RegExp(\"foo\"); + RegExp(/foo/); + RegExp(\"foo\", \"i\"); + RegExp(\"foo\", \"ig\"); + RegExp(/foo/, \"i\");// invalid in ES5, valid in ES6 + RegExp(/foo/g, \"i\");// invalid in ES5, valid in ES6 + }, + // invalid flags + function() { + RegExp(\"foo\", \"z\");// error + new RegExp(\"foo\", \"z\");// error + } +]; + +" +`; + +exports[`test weakset.js 1`] = ` +"// @flow + +let ws = new WeakSet(); +let obj: Object = {}; +let dict: {foo: string} = {foo: \'bar\'}; + +ws.add(window); +ws.add(obj); +ws.add(dict); +ws.has(window); +ws.has(obj); +ws.has(dict); +ws.delete(window); +ws.delete(obj); +ws.delete(dict); + +let ws2 = new WeakSet([obj, dict]); + +let ws3 = new WeakSet([1, 2, 3]); // error, must be objects + +function* generator(): Iterable<{foo: string}> { + while (true) { + yield {foo: \'bar\'}; + } +} + +let ws4 = new WeakSet(generator()); + +function* numbers(): Iterable { + let i = 0; + while (true) { + yield i++; + } +} + +let ws5 = new WeakSet(numbers()); // error, must be objects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/core_tests/boolean.js b/tests/core_tests/boolean.js new file mode 100644 index 000000000000..6917378f95bc --- /dev/null +++ b/tests/core_tests/boolean.js @@ -0,0 +1,42 @@ +// @flow + +// Boolean (the class) tests. booleans (the literals) are not part of core.js + +let tests = [ + // constructor + function() { + new Boolean(); + new Boolean(0); + new Boolean(-0); + new Boolean(null); + new Boolean(false); + new Boolean(NaN); + new Boolean(undefined); + new Boolean(""); + }, + + // toString + function() { + (true).toString(); + let x: boolean = false; + x.toString(); + (new Boolean(true)).toString(); + }, + + // valueOf + function() { + ((new Boolean(0)).valueOf(): boolean); + }, + + // casting + function() { + Boolean(); + Boolean(0); + Boolean(-0); + Boolean(null); + Boolean(false); + Boolean(NaN); + Boolean(undefined); + Boolean(""); + }, +]; diff --git a/tests/core_tests/jsfmt.spec.js b/tests/core_tests/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/core_tests/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/core_tests/map.js b/tests/core_tests/map.js new file mode 100644 index 000000000000..414b794c74c0 --- /dev/null +++ b/tests/core_tests/map.js @@ -0,0 +1,32 @@ +// @flow + +function* generator(): Iterable<[string, number]> { + while (true) { + yield ['foo', 123]; + } +} + +let tests = [ + // good constructors + function() { + let w = new Map(); + let x = new Map(null); + let y = new Map([['foo', 123]]); + let z = new Map(generator()); + let a: Map = new Map(); + let b: Map = new Map([['foo', 123]]); + let c: Map = new Map(generator()); + }, + + // bad constructors + function() { + let x = new Map(['foo', 123]); // error + let y: Map = new Map([['foo', 123]]); // error + }, + + // get() + function(x: Map) { + (x.get('foo'): boolean); // error, string | void + x.get(123); // error, wrong key type + }, +]; diff --git a/tests/core_tests/regexp.js b/tests/core_tests/regexp.js new file mode 100644 index 000000000000..d3bca655cb91 --- /dev/null +++ b/tests/core_tests/regexp.js @@ -0,0 +1,29 @@ +// @flow + +let tests = [ + // constructor + function() { + new RegExp('foo'); + new RegExp(/foo/); + new RegExp('foo', 'i'); + new RegExp('foo', 'ig'); + new RegExp(/foo/, 'i'); // invalid in ES5, valid in ES6 + new RegExp(/foo/g, 'i'); // invalid in ES5, valid in ES6 + }, + + // called as a function (equivalent to the constructor per ES6 21.2.3) + function() { + RegExp('foo'); + RegExp(/foo/); + RegExp('foo', 'i'); + RegExp('foo', 'ig'); + RegExp(/foo/, 'i'); // invalid in ES5, valid in ES6 + RegExp(/foo/g, 'i'); // invalid in ES5, valid in ES6 + }, + + // invalid flags + function() { + RegExp('foo', 'z'); // error + new RegExp('foo', 'z'); // error + } +]; diff --git a/tests/core_tests/weakset.js b/tests/core_tests/weakset.js new file mode 100644 index 000000000000..76d7ae1ee83c --- /dev/null +++ b/tests/core_tests/weakset.js @@ -0,0 +1,36 @@ +// @flow + +let ws = new WeakSet(); +let obj: Object = {}; +let dict: {foo: string} = {foo: 'bar'}; + +ws.add(window); +ws.add(obj); +ws.add(dict); +ws.has(window); +ws.has(obj); +ws.has(dict); +ws.delete(window); +ws.delete(obj); +ws.delete(dict); + +let ws2 = new WeakSet([obj, dict]); + +let ws3 = new WeakSet([1, 2, 3]); // error, must be objects + +function* generator(): Iterable<{foo: string}> { + while (true) { + yield {foo: 'bar'}; + } +} + +let ws4 = new WeakSet(generator()); + +function* numbers(): Iterable { + let i = 0; + while (true) { + yield i++; + } +} + +let ws5 = new WeakSet(numbers()); // error, must be objects diff --git a/tests/covariance/__snapshots__/jsfmt.spec.js.snap b/tests/covariance/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..491e6e935231 --- /dev/null +++ b/tests/covariance/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,68 @@ +exports[`test test.js 1`] = ` +"type CovArrayVerbose = Array; +var b: CovArrayVerbose = []; +var y: CovArrayVerbose = b; +y[0] = \"\"; // error + +class NVerbose { + x: CovArrayVerbose; + foo(): CovArrayVerbose { return this.x; } +} + +var nv: NVerbose = new NVerbose; +nv.x = [0]; +(nv.x[0]: string); // error +(nv.foo()[0]: string); // error + +/* TODO: use existentials for non-verbose covariance? + +type CovArray = Array<*:X>; +var c: CovArray = [0]; +var z: CovArray = c; // error + +var d: CovArray = []; +var w: CovArray = d; +w[0] = \"\"; // error + +type P = CovArray; +var p: P = []; +(p[0]: number); // not an error! +p[0] = \"\"; // error + +class M { + x: CovArray; + foo(): CovArray { return this.x; } + bar(x: string) { this.foo()[0] = x; } // error +} + +class N { + x: CovArray; + foo(): CovArray { return this.x; } + bar(e: string) { this.foo()[0] = e; } // error + qux(e: E) { this.foo()[0] = e; } +} + +var n: N = new N; +n.x = [0]; +(n.x[0]: string); // error +(n.foo()[0]: string); // not an error! + +*/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/covariance/jsfmt.spec.js b/tests/covariance/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/covariance/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/covariance/test.js b/tests/covariance/test.js new file mode 100644 index 000000000000..9383b247fc8d --- /dev/null +++ b/tests/covariance/test.js @@ -0,0 +1,49 @@ +type CovArrayVerbose = Array; +var b: CovArrayVerbose = []; +var y: CovArrayVerbose = b; +y[0] = ""; // error + +class NVerbose { + x: CovArrayVerbose; + foo(): CovArrayVerbose { return this.x; } +} + +var nv: NVerbose = new NVerbose; +nv.x = [0]; +(nv.x[0]: string); // error +(nv.foo()[0]: string); // error + +/* TODO: use existentials for non-verbose covariance? + +type CovArray = Array<*:X>; +var c: CovArray = [0]; +var z: CovArray = c; // error + +var d: CovArray = []; +var w: CovArray = d; +w[0] = ""; // error + +type P = CovArray; +var p: P = []; +(p[0]: number); // not an error! +p[0] = ""; // error + +class M { + x: CovArray; + foo(): CovArray { return this.x; } + bar(x: string) { this.foo()[0] = x; } // error +} + +class N { + x: CovArray; + foo(): CovArray { return this.x; } + bar(e: string) { this.foo()[0] = e; } // error + qux(e: E) { this.foo()[0] = e; } +} + +var n: N = new N; +n.x = [0]; +(n.x[0]: string); // error +(n.foo()[0]: string); // not an error! + +*/ diff --git a/tests/coverage/__snapshots__/jsfmt.spec.js.snap b/tests/coverage/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5343f59a1e2e --- /dev/null +++ b/tests/coverage/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,80 @@ +exports[`test crash.js 1`] = ` +"// This file triggers a violation of the "disjoint-or-nested ranges invariant" +// that we implicitly assume in type-at-pos and coverage implementations. In +// particular, when unchecked it causes a crash with coverage --color. + +declare module foo { +} + +declare module bar { +} + +// TODO +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// This file triggers a violation of the "disjoint-or-nested ranges invariant" +// that we implicitly assume in type-at-pos and coverage implementations. In +// particular, when unchecked it causes a crash with coverage --color. +declare module foo { + +} +declare module bar { + +}// TODO + +" +`; + +exports[`test declare_module.js 1`] = ` +"// check coverage of declare module + +declare module foo { +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// check coverage of declare module +declare module foo { + +} + +" +`; + +exports[`test no_pragma.js 1`] = ` +"let x = 0; +(x: string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +let x = 0; +(x: string); + +" +`; + +exports[`test non-termination.js 1`] = ` +"// This file triggers a violation of the "disjoint-or-nested ranges invariant" +// that we implicitly assume in type-at-pos and coverage implementations. In +// particular, when unchecked it causes non-termination with coverage --color. + +declare module foo { +} + +declare module bar { +} + +// TODO + +declare class qux { +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// This file triggers a violation of the "disjoint-or-nested ranges invariant" +// that we implicitly assume in type-at-pos and coverage implementations. In +// particular, when unchecked it causes non-termination with coverage --color. +declare module foo { + +} +declare module bar { + +} +// TODO +declare class qux {} + +" +`; diff --git a/tests/coverage/crash.js b/tests/coverage/crash.js new file mode 100644 index 000000000000..16aa9e752c9d --- /dev/null +++ b/tests/coverage/crash.js @@ -0,0 +1,11 @@ +// This file triggers a violation of the "disjoint-or-nested ranges invariant" +// that we implicitly assume in type-at-pos and coverage implementations. In +// particular, when unchecked it causes a crash with coverage --color. + +declare module foo { +} + +declare module bar { +} + +// TODO diff --git a/tests/coverage/declare_module.js b/tests/coverage/declare_module.js new file mode 100644 index 000000000000..88ad5dab23f2 --- /dev/null +++ b/tests/coverage/declare_module.js @@ -0,0 +1,4 @@ +// check coverage of declare module + +declare module foo { +} diff --git a/tests/coverage/jsfmt.spec.js b/tests/coverage/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/coverage/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/coverage/no_pragma.js b/tests/coverage/no_pragma.js new file mode 100644 index 000000000000..865e412c16d6 --- /dev/null +++ b/tests/coverage/no_pragma.js @@ -0,0 +1,2 @@ +let x = 0; +(x: string); diff --git a/tests/coverage/non-termination.js b/tests/coverage/non-termination.js new file mode 100644 index 000000000000..86e8c24301ff --- /dev/null +++ b/tests/coverage/non-termination.js @@ -0,0 +1,14 @@ +// This file triggers a violation of the "disjoint-or-nested ranges invariant" +// that we implicitly assume in type-at-pos and coverage implementations. In +// particular, when unchecked it causes non-termination with coverage --color. + +declare module foo { +} + +declare module bar { +} + +// TODO + +declare class qux { +} diff --git a/tests/cycle/A.js b/tests/cycle/A.js new file mode 100644 index 000000000000..a49a8f290e31 --- /dev/null +++ b/tests/cycle/A.js @@ -0,0 +1,5 @@ +var B = require('./B'); + +class A extends B { } + +module.exports = A; diff --git a/tests/cycle/B.js b/tests/cycle/B.js new file mode 100644 index 000000000000..e5c1da823f74 --- /dev/null +++ b/tests/cycle/B.js @@ -0,0 +1,5 @@ +var A = require('./A'); + +//class B extends A { } + +module.exports = B; diff --git a/tests/cycle/__snapshots__/jsfmt.spec.js.snap b/tests/cycle/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4986c12b758a --- /dev/null +++ b/tests/cycle/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test A.js 1`] = ` +"var B = require('./B'); + +class A extends B { } + +module.exports = A; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var B = require("./B"); +class A extends B {} +module.exports = A; + +" +`; + +exports[`test B.js 1`] = ` +"var A = require('./A'); + +//class B extends A { } + +module.exports = B; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var A = require("./A"); +//class B extends A { } +module.exports = B; + +" +`; diff --git a/tests/cycle/jsfmt.spec.js b/tests/cycle/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/cycle/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/date/__snapshots__/jsfmt.spec.js.snap b/tests/date/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a79fda0e82f2 --- /dev/null +++ b/tests/date/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,57 @@ +exports[`test date.js 1`] = ` +"var d = new Date(0); +var x:string = d.getTime(); + +var y:number = d; + +// valid constructors +new Date(); +new Date(1234567890); +new Date('2015/06/18'); +new Date(2015, 6); +new Date(2015, 6, 18); +new Date(2015, 6, 18, 11); +new Date(2015, 6, 18, 11, 55); +new Date(2015, 6, 18, 11, 55, 42); +new Date(2015, 6, 18, 11, 55, 42, 999); + +// invalid constructors +new Date({}); +new Date(2015, '6'); +new Date(2015, 6, '18'); +new Date(2015, 6, 18, '11'); +new Date(2015, 6, 18, 11, '55'); +new Date(2015, 6, 18, 11, 55, '42'); +new Date(2015, 6, 18, 11, 55, 42, '999'); + +// invalid constructors that we incorrectly consider valid +new Date('2015', 6); +new Date(2015, 6, 18, 11, 55, 42, 999, 'hahaha'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var d = new Date(0); +var x: string = d.getTime(); +var y: number = d; +// valid constructors +new Date(); +new Date(1234567890); +new Date("2015/06/18"); +new Date(2015, 6); +new Date(2015, 6, 18); +new Date(2015, 6, 18, 11); +new Date(2015, 6, 18, 11, 55); +new Date(2015, 6, 18, 11, 55, 42); +new Date(2015, 6, 18, 11, 55, 42, 999); +// invalid constructors +new Date({}); +new Date(2015, "6"); +new Date(2015, 6, "18"); +new Date(2015, 6, 18, "11"); +new Date(2015, 6, 18, 11, "55"); +new Date(2015, 6, 18, 11, 55, "42"); +new Date(2015, 6, 18, 11, 55, 42, "999"); +// invalid constructors that we incorrectly consider valid +new Date("2015", 6); +new Date(2015, 6, 18, 11, 55, 42, 999, "hahaha"); + +" +`; diff --git a/tests/date/date.js b/tests/date/date.js new file mode 100644 index 000000000000..dddd8aa08d2b --- /dev/null +++ b/tests/date/date.js @@ -0,0 +1,28 @@ +var d = new Date(0); +var x:string = d.getTime(); + +var y:number = d; + +// valid constructors +new Date(); +new Date(1234567890); +new Date('2015/06/18'); +new Date(2015, 6); +new Date(2015, 6, 18); +new Date(2015, 6, 18, 11); +new Date(2015, 6, 18, 11, 55); +new Date(2015, 6, 18, 11, 55, 42); +new Date(2015, 6, 18, 11, 55, 42, 999); + +// invalid constructors +new Date({}); +new Date(2015, '6'); +new Date(2015, 6, '18'); +new Date(2015, 6, 18, '11'); +new Date(2015, 6, 18, 11, '55'); +new Date(2015, 6, 18, 11, 55, '42'); +new Date(2015, 6, 18, 11, 55, 42, '999'); + +// invalid constructors that we incorrectly consider valid +new Date('2015', 6); +new Date(2015, 6, 18, 11, 55, 42, 999, 'hahaha'); diff --git a/tests/date/jsfmt.spec.js b/tests/date/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/date/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_haste/ExplicitProvidesModuleDifferentName.js b/tests/declaration_files_haste/ExplicitProvidesModuleDifferentName.js new file mode 100644 index 000000000000..90fdd624d92e --- /dev/null +++ b/tests/declaration_files_haste/ExplicitProvidesModuleDifferentName.js @@ -0,0 +1,6 @@ +/* + * @providesModule ExplicitProvidesModuleDifferentName + * @flow + */ + +module.exports.fun = (): string => "hello there"; diff --git a/tests/declaration_files_haste/ExplicitProvidesModuleSameName.js b/tests/declaration_files_haste/ExplicitProvidesModuleSameName.js new file mode 100644 index 000000000000..420b439f46c9 --- /dev/null +++ b/tests/declaration_files_haste/ExplicitProvidesModuleSameName.js @@ -0,0 +1,6 @@ +/* + * @providesModule ExplicitProvidesModuleSameName + * @flow + */ + +module.exports.fun = (): string => "hello there"; diff --git a/tests/declaration_files_haste/ImplicitProvidesModule.js b/tests/declaration_files_haste/ImplicitProvidesModule.js new file mode 100644 index 000000000000..9fa3b2cc07d6 --- /dev/null +++ b/tests/declaration_files_haste/ImplicitProvidesModule.js @@ -0,0 +1,6 @@ +/* + * @providesModule ImplicitProvidesModule + * @flow + */ + +module.exports.fun = (): string => "hello there"; diff --git a/tests/declaration_files_haste/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_haste/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..53ece1a8733a --- /dev/null +++ b/tests/declaration_files_haste/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,81 @@ +exports[`test ExplicitProvidesModuleDifferentName.js 1`] = ` +"/* + * @providesModule ExplicitProvidesModuleDifferentName + * @flow + */ + +module.exports.fun = (): string => "hello there"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @providesModule ExplicitProvidesModuleDifferentName + * @flow + */ +module.exports.fun = (): string => "hello there"; + +" +`; + +exports[`test ExplicitProvidesModuleSameName.js 1`] = ` +"/* + * @providesModule ExplicitProvidesModuleSameName + * @flow + */ + +module.exports.fun = (): string => "hello there"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @providesModule ExplicitProvidesModuleSameName + * @flow + */ +module.exports.fun = (): string => "hello there"; + +" +`; + +exports[`test ImplicitProvidesModule.js 1`] = ` +"/* + * @providesModule ImplicitProvidesModule + * @flow + */ + +module.exports.fun = (): string => "hello there"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @providesModule ImplicitProvidesModule + * @flow + */ +module.exports.fun = (): string => "hello there"; + +" +`; + +exports[`test md5.js 1`] = ` +"/* @providesModule md5 */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test test.js 1`] = ` +"/* @flow */ + +var Implicit = require('ImplicitProvidesModule'); +(Implicit.fun(): string); + +var ExplicitSameName = require('ExplicitProvidesModuleSameName'); +(ExplicitSameName.fun(): string); + +var ExplicitDifferentName = require('ExplicitProvidesModuleDifferentName'); +(ExplicitDifferentName.fun(): string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var Implicit = require("ImplicitProvidesModule"); +(Implicit.fun(): string); +var ExplicitSameName = require("ExplicitProvidesModuleSameName"); +(ExplicitSameName.fun(): string); +var ExplicitDifferentName = require("ExplicitProvidesModuleDifferentName"); +(ExplicitDifferentName.fun(): string); + +" +`; diff --git a/tests/declaration_files_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8eedeb757628 --- /dev/null +++ b/tests/declaration_files_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test min.js 1`] = ` +"module.exports.fun = (): string => "hello there"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports.fun = (): string => "hello there"; + +" +`; diff --git a/tests/declaration_files_haste/external/_d3/jsfmt.spec.js b/tests/declaration_files_haste/external/_d3/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_haste/external/_d3/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_haste/external/_d3/min.js b/tests/declaration_files_haste/external/_d3/min.js new file mode 100644 index 000000000000..94884777ff10 --- /dev/null +++ b/tests/declaration_files_haste/external/_d3/min.js @@ -0,0 +1 @@ +module.exports.fun = (): string => "hello there"; diff --git a/tests/declaration_files_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ac5bbc602ad1 --- /dev/null +++ b/tests/declaration_files_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,28 @@ +exports[`test nested_test.js 1`] = ` +"/* @flow */ + +var docblock = require('qux/docblock'); +var min = require('d3/min.js'); +var corge = require('qux/corge'); + +// make sure we don't pick up non-header @providesModule +// annotations - see node_modules/qux/docblock.js +var unreachable = require('annotation'); + +(docblock.fun(): string); +(min.fun(): string); +(corge.fun(): string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var docblock = require("qux/docblock"); +var min = require("d3/min.js"); +var corge = require("qux/corge"); +// make sure we don't pick up non-header @providesModule +// annotations - see node_modules/qux/docblock.js +var unreachable = require("annotation"); +(docblock.fun(): string); +(min.fun(): string); +(corge.fun(): string); + +" +`; diff --git a/tests/declaration_files_haste/foo/bar/jsfmt.spec.js b/tests/declaration_files_haste/foo/bar/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_haste/foo/bar/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_haste/foo/bar/nested_test.js b/tests/declaration_files_haste/foo/bar/nested_test.js new file mode 100644 index 000000000000..c9522bc6e6b5 --- /dev/null +++ b/tests/declaration_files_haste/foo/bar/nested_test.js @@ -0,0 +1,13 @@ +/* @flow */ + +var docblock = require('qux/docblock'); +var min = require('d3/min.js'); +var corge = require('qux/corge'); + +// make sure we don't pick up non-header @providesModule +// annotations - see node_modules/qux/docblock.js +var unreachable = require('annotation'); + +(docblock.fun(): string); +(min.fun(): string); +(corge.fun(): string); diff --git a/tests/declaration_files_haste/jsfmt.spec.js b/tests/declaration_files_haste/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_haste/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_haste/md5.js b/tests/declaration_files_haste/md5.js new file mode 100644 index 000000000000..c358d72168a6 --- /dev/null +++ b/tests/declaration_files_haste/md5.js @@ -0,0 +1 @@ +/* @providesModule md5 */ diff --git a/tests/declaration_files_haste/test.js b/tests/declaration_files_haste/test.js new file mode 100644 index 000000000000..88fe21f03875 --- /dev/null +++ b/tests/declaration_files_haste/test.js @@ -0,0 +1,10 @@ +/* @flow */ + +var Implicit = require('ImplicitProvidesModule'); +(Implicit.fun(): string); + +var ExplicitSameName = require('ExplicitProvidesModuleSameName'); +(ExplicitSameName.fun(): string); + +var ExplicitDifferentName = require('ExplicitProvidesModuleDifferentName'); +(ExplicitDifferentName.fun(): string); diff --git a/tests/declaration_files_haste/ws/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_haste/ws/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..72caaf084cb1 --- /dev/null +++ b/tests/declaration_files_haste/ws/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,6 @@ +exports[`test index.js 1`] = ` +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/declaration_files_haste/ws/index.js b/tests/declaration_files_haste/ws/index.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/declaration_files_haste/ws/jsfmt.spec.js b/tests/declaration_files_haste/ws/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_haste/ws/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_haste/ws/test/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_haste/ws/test/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f54d0216ceb7 --- /dev/null +++ b/tests/declaration_files_haste/ws/test/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test client.js 1`] = ` +"var ws = require('../'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var ws = require("../"); + +" +`; diff --git a/tests/declaration_files_haste/ws/test/client.js b/tests/declaration_files_haste/ws/test/client.js new file mode 100644 index 000000000000..2fb0ed6d4dfd --- /dev/null +++ b/tests/declaration_files_haste/ws/test/client.js @@ -0,0 +1 @@ +var ws = require('../'); diff --git a/tests/declaration_files_haste/ws/test/jsfmt.spec.js b/tests/declaration_files_haste/ws/test/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_haste/ws/test/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_haste/A.js b/tests/declaration_files_incremental_haste/A.js new file mode 100644 index 000000000000..9ad347d2c7b9 --- /dev/null +++ b/tests/declaration_files_incremental_haste/A.js @@ -0,0 +1,3 @@ +/* @providesModule A */ +class Implementation {} +export function foo(): Implementation { return new Implementation; } diff --git a/tests/declaration_files_incremental_haste/ExplicitProvidesModuleDifferentName.js b/tests/declaration_files_incremental_haste/ExplicitProvidesModuleDifferentName.js new file mode 100644 index 000000000000..b31795b56a69 --- /dev/null +++ b/tests/declaration_files_incremental_haste/ExplicitProvidesModuleDifferentName.js @@ -0,0 +1,7 @@ +/* + * @providesModule ExplicitProvidesModuleDifferentName + * @flow + */ + +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; diff --git a/tests/declaration_files_incremental_haste/ExplicitProvidesModuleSameName.js b/tests/declaration_files_incremental_haste/ExplicitProvidesModuleSameName.js new file mode 100644 index 000000000000..2b8762f7b39d --- /dev/null +++ b/tests/declaration_files_incremental_haste/ExplicitProvidesModuleSameName.js @@ -0,0 +1,7 @@ +/* + * @providesModule ExplicitProvidesModuleSameName + * @flow + */ + +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; diff --git a/tests/declaration_files_incremental_haste/ImplicitProvidesModule.js b/tests/declaration_files_incremental_haste/ImplicitProvidesModule.js new file mode 100644 index 000000000000..855ff08d972d --- /dev/null +++ b/tests/declaration_files_incremental_haste/ImplicitProvidesModule.js @@ -0,0 +1,7 @@ +/* + * @providesModule ImplicitProvidesModule + * @flow + */ + +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; diff --git a/tests/declaration_files_incremental_haste/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_incremental_haste/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3abccda6a355 --- /dev/null +++ b/tests/declaration_files_incremental_haste/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,101 @@ +exports[`test A.js 1`] = ` +"/* @providesModule A */ +class Implementation {} +export function foo(): Implementation { return new Implementation; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule A */ +class Implementation {} +export function foo(): Implementation { + return new Implementation(); +} + +" +`; + +exports[`test ExplicitProvidesModuleDifferentName.js 1`] = ` +"/* + * @providesModule ExplicitProvidesModuleDifferentName + * @flow + */ + +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @providesModule ExplicitProvidesModuleDifferentName + * @flow + */ +class Implementation {} +module.exports.fun = (): Implementation => new Implementation(); + +" +`; + +exports[`test ExplicitProvidesModuleSameName.js 1`] = ` +"/* + * @providesModule ExplicitProvidesModuleSameName + * @flow + */ + +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @providesModule ExplicitProvidesModuleSameName + * @flow + */ +class Implementation {} +module.exports.fun = (): Implementation => new Implementation(); + +" +`; + +exports[`test ImplicitProvidesModule.js 1`] = ` +"/* + * @providesModule ImplicitProvidesModule + * @flow + */ + +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * @providesModule ImplicitProvidesModule + * @flow + */ +class Implementation {} +module.exports.fun = (): Implementation => new Implementation(); + +" +`; + +exports[`test md5.js 1`] = ` +"/* @providesModule md5 */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test test.js 1`] = ` +"/* @flow */ + +var Implicit = require('ImplicitProvidesModule'); +(Implicit.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean + +var ExplicitSameName = require('ExplicitProvidesModuleSameName'); +(ExplicitSameName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean + +var ExplicitDifferentName = require('ExplicitProvidesModuleDifferentName'); +(ExplicitDifferentName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var Implicit = require("ImplicitProvidesModule"); +(Implicit.fun(): boolean);// Error: Either Implementation ~> boolean or Declaration ~> boolean +var ExplicitSameName = require("ExplicitProvidesModuleSameName"); +(ExplicitSameName.fun(): boolean);// Error: Either Implementation ~> boolean or Declaration ~> boolean +var ExplicitDifferentName = require("ExplicitProvidesModuleDifferentName"); +(ExplicitDifferentName.fun(): boolean);// Error: Either Implementation ~> boolean or Declaration ~> boolean + +" +`; diff --git a/tests/declaration_files_incremental_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_incremental_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..67b927b140c4 --- /dev/null +++ b/tests/declaration_files_incremental_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test min.js 1`] = ` +"class Implementation {} +module.exports.fun = (): Implementation => new Implementation; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class Implementation {} +module.exports.fun = (): Implementation => new Implementation(); + +" +`; diff --git a/tests/declaration_files_incremental_haste/external/_d3/jsfmt.spec.js b/tests/declaration_files_incremental_haste/external/_d3/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_incremental_haste/external/_d3/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_haste/external/_d3/min.js b/tests/declaration_files_incremental_haste/external/_d3/min.js new file mode 100644 index 000000000000..330a5d7de8ca --- /dev/null +++ b/tests/declaration_files_incremental_haste/external/_d3/min.js @@ -0,0 +1,2 @@ +class Implementation {} +module.exports.fun = (): Implementation => new Implementation; diff --git a/tests/declaration_files_incremental_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_incremental_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b213b5938c18 --- /dev/null +++ b/tests/declaration_files_incremental_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,21 @@ +exports[`test nested_test.js 1`] = ` +"/* @flow */ + +var docblock = require('qux/docblock'); +var min = require('d3/min.js'); +var corge = require('qux/corge'); + +(docblock.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean +(min.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean +(corge.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var docblock = require("qux/docblock"); +var min = require("d3/min.js"); +var corge = require("qux/corge"); +(docblock.fun(): boolean);// Error: Either Implementation ~> boolean or Declaration ~> boolean +(min.fun(): boolean);// Error: Either Implementation ~> boolean or Declaration ~> boolean +(corge.fun(): boolean);// Error: Either Implementation ~> boolean or Declaration ~> boolean + +" +`; diff --git a/tests/declaration_files_incremental_haste/foo/bar/jsfmt.spec.js b/tests/declaration_files_incremental_haste/foo/bar/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_incremental_haste/foo/bar/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_haste/foo/bar/nested_test.js b/tests/declaration_files_incremental_haste/foo/bar/nested_test.js new file mode 100644 index 000000000000..ffc6bac4625a --- /dev/null +++ b/tests/declaration_files_incremental_haste/foo/bar/nested_test.js @@ -0,0 +1,9 @@ +/* @flow */ + +var docblock = require('qux/docblock'); +var min = require('d3/min.js'); +var corge = require('qux/corge'); + +(docblock.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean +(min.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean +(corge.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean diff --git a/tests/declaration_files_incremental_haste/jsfmt.spec.js b/tests/declaration_files_incremental_haste/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_incremental_haste/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_haste/md5.js b/tests/declaration_files_incremental_haste/md5.js new file mode 100644 index 000000000000..c358d72168a6 --- /dev/null +++ b/tests/declaration_files_incremental_haste/md5.js @@ -0,0 +1 @@ +/* @providesModule md5 */ diff --git a/tests/declaration_files_incremental_haste/test.js b/tests/declaration_files_incremental_haste/test.js new file mode 100644 index 000000000000..c139d4c41746 --- /dev/null +++ b/tests/declaration_files_incremental_haste/test.js @@ -0,0 +1,10 @@ +/* @flow */ + +var Implicit = require('ImplicitProvidesModule'); +(Implicit.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean + +var ExplicitSameName = require('ExplicitProvidesModuleSameName'); +(ExplicitSameName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean + +var ExplicitDifferentName = require('ExplicitProvidesModuleDifferentName'); +(ExplicitDifferentName.fun(): boolean); // Error: Either Implementation ~> boolean or Declaration ~> boolean diff --git a/tests/declaration_files_incremental_haste/ws/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_incremental_haste/ws/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..72caaf084cb1 --- /dev/null +++ b/tests/declaration_files_incremental_haste/ws/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,6 @@ +exports[`test index.js 1`] = ` +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/declaration_files_incremental_haste/ws/index.js b/tests/declaration_files_incremental_haste/ws/index.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/declaration_files_incremental_haste/ws/jsfmt.spec.js b/tests/declaration_files_incremental_haste/ws/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_incremental_haste/ws/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_haste/ws/test/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_incremental_haste/ws/test/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f54d0216ceb7 --- /dev/null +++ b/tests/declaration_files_incremental_haste/ws/test/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test client.js 1`] = ` +"var ws = require('../'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var ws = require("../"); + +" +`; diff --git a/tests/declaration_files_incremental_haste/ws/test/client.js b/tests/declaration_files_incremental_haste/ws/test/client.js new file mode 100644 index 000000000000..2fb0ed6d4dfd --- /dev/null +++ b/tests/declaration_files_incremental_haste/ws/test/client.js @@ -0,0 +1 @@ +var ws = require('../'); diff --git a/tests/declaration_files_incremental_haste/ws/test/jsfmt.spec.js b/tests/declaration_files_incremental_haste/ws/test/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_incremental_haste/ws/test/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_node/A.js b/tests/declaration_files_incremental_node/A.js new file mode 100644 index 000000000000..e1abbb2ca677 --- /dev/null +++ b/tests/declaration_files_incremental_node/A.js @@ -0,0 +1,2 @@ +class Implementation {} +export function foo(): Implementation { return new Implementation; } diff --git a/tests/declaration_files_incremental_node/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_incremental_node/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..77b78352e073 --- /dev/null +++ b/tests/declaration_files_incremental_node/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,98 @@ +exports[`test A.js 1`] = ` +"class Implementation {} +export function foo(): Implementation { return new Implementation; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class Implementation {} +export function foo(): Implementation { + return new Implementation(); +} + +" +`; + +exports[`test test_absolute.js 1`] = ` +"/* @flow */ + +// This will require ./node_modules/B.js.flow +var B1 = require('B'); +(B1.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +// This will require ./node_modules/B.js.flow +var B2 = require('B.js'); +(B2.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var C = require('package_with_full_main'); +(C.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var D = require('package_with_partial_main'); +(D.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var E = require('package_with_no_package_json'); +(E.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var F = require('package_with_dir_main'); +(F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +// This will require ./node_modules/B.js.flow +var B1 = require('B'); +(B1.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +// This will require ./node_modules/B.js.flow +var B2 = require('B.js'); +(B2.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var C = require('package_with_full_main'); +(C.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var D = require('package_with_partial_main'); +(D.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var E = require('package_with_no_package_json'); +(E.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var F = require('package_with_dir_main'); +(F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// This will require ./node_modules/B.js.flow +var B1 = require("B"); +(B1.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +// This will require ./node_modules/B.js.flow +var B2 = require("B.js"); +(B2.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var C = require("package_with_full_main"); +(C.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var D = require("package_with_partial_main"); +(D.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var E = require("package_with_no_package_json"); +(E.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var F = require("package_with_dir_main"); +(F.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +// This will require ./node_modules/B.js.flow +var B1 = require("B"); +(B1.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +// This will require ./node_modules/B.js.flow +var B2 = require("B.js"); +(B2.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var C = require("package_with_full_main"); +(C.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var D = require("package_with_partial_main"); +(D.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var E = require("package_with_no_package_json"); +(E.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean +var F = require("package_with_dir_main"); +(F.fun(): boolean);// Error either Implementation ~> boolean or Declaration ~> boolean + +" +`; + +exports[`test test_relative.js 1`] = ` +"import { foo } from './A'; + +(foo(): boolean); // Error: either Implementation ~> boolean or Definition ~> boolean +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import { foo } from "./A"; +(foo(): boolean);// Error: either Implementation ~> boolean or Definition ~> boolean + +" +`; diff --git a/tests/declaration_files_incremental_node/jsfmt.spec.js b/tests/declaration_files_incremental_node/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_incremental_node/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_incremental_node/test_absolute.js b/tests/declaration_files_incremental_node/test_absolute.js new file mode 100644 index 000000000000..ec99b67abe32 --- /dev/null +++ b/tests/declaration_files_incremental_node/test_absolute.js @@ -0,0 +1,41 @@ +/* @flow */ + +// This will require ./node_modules/B.js.flow +var B1 = require('B'); +(B1.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +// This will require ./node_modules/B.js.flow +var B2 = require('B.js'); +(B2.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var C = require('package_with_full_main'); +(C.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var D = require('package_with_partial_main'); +(D.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var E = require('package_with_no_package_json'); +(E.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var F = require('package_with_dir_main'); +(F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +// This will require ./node_modules/B.js.flow +var B1 = require('B'); +(B1.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +// This will require ./node_modules/B.js.flow +var B2 = require('B.js'); +(B2.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var C = require('package_with_full_main'); +(C.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var D = require('package_with_partial_main'); +(D.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var E = require('package_with_no_package_json'); +(E.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean + +var F = require('package_with_dir_main'); +(F.fun(): boolean); // Error either Implementation ~> boolean or Declaration ~> boolean diff --git a/tests/declaration_files_incremental_node/test_relative.js b/tests/declaration_files_incremental_node/test_relative.js new file mode 100644 index 000000000000..abd7f0b8ca8f --- /dev/null +++ b/tests/declaration_files_incremental_node/test_relative.js @@ -0,0 +1,3 @@ +import { foo } from './A'; + +(foo(): boolean); // Error: either Implementation ~> boolean or Definition ~> boolean diff --git a/tests/declaration_files_node/A.js b/tests/declaration_files_node/A.js new file mode 100644 index 000000000000..d948c87f95a2 --- /dev/null +++ b/tests/declaration_files_node/A.js @@ -0,0 +1,3 @@ +/* @flow */ + +module.exports.fun = (): string => 'hello there!'; diff --git a/tests/declaration_files_node/CJS.js b/tests/declaration_files_node/CJS.js new file mode 100644 index 000000000000..a0dfc0144a62 --- /dev/null +++ b/tests/declaration_files_node/CJS.js @@ -0,0 +1,2 @@ +// @flow +module.exports = 42; diff --git a/tests/declaration_files_node/__snapshots__/jsfmt.spec.js.snap b/tests/declaration_files_node/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2b9e69b03631 --- /dev/null +++ b/tests/declaration_files_node/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,91 @@ +exports[`test A.js 1`] = ` +"/* @flow */ + +module.exports.fun = (): string => 'hello there!'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports.fun = (): string => "hello there!"; + +" +`; + +exports[`test CJS.js 1`] = ` +"// @flow +module.exports = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +module.exports = 42; + +" +`; + +exports[`test test_absolute.js 1`] = ` +"/* @flow */ + +// This will require ./node_modules/B.js.flow +var B1 = require('B'); +(B1.fun(): string); // Error number ~> string + +// This will require ./node_modules/B.js.flow +var B2 = require('B.js'); +(B2.fun(): string); // Error number ~> string + +var C = require('package_with_full_main'); +(C.fun(): string); // Error number ~> string + +var D = require('package_with_partial_main'); +(D.fun(): string); // Error number ~> string + +var E = require('package_with_no_package_json'); +(E.fun(): string); // Error number ~> string + +var F = require('package_with_dir_main'); +(F.fun(): string); // Error number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// This will require ./node_modules/B.js.flow +var B1 = require("B"); +(B1.fun(): string);// Error number ~> string +// This will require ./node_modules/B.js.flow +var B2 = require("B.js"); +(B2.fun(): string);// Error number ~> string +var C = require("package_with_full_main"); +(C.fun(): string);// Error number ~> string +var D = require("package_with_partial_main"); +(D.fun(): string);// Error number ~> string +var E = require("package_with_no_package_json"); +(E.fun(): string);// Error number ~> string +var F = require("package_with_dir_main"); +(F.fun(): string);// Error number ~> string + +" +`; + +exports[`test test_relative.js 1`] = ` +"/* @flow */ + +// This will require ./A.js.flow +var A1 = require('./A'); +(A1.fun(): string); // Error number ~> string + +// This will require ./A.js.flow +var A2 = require('./A.js'); +(A2.fun(): string); // Error number ~> string + +var CJS = require('./CJS.js'); +(CJS: string); +(CJS: number); // Error: string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// This will require ./A.js.flow +var A1 = require("./A"); +(A1.fun(): string);// Error number ~> string +// This will require ./A.js.flow +var A2 = require("./A.js"); +(A2.fun(): string);// Error number ~> string +var CJS = require("./CJS.js"); +(CJS: string); +(CJS: number);// Error: string ~> number + +" +`; diff --git a/tests/declaration_files_node/jsfmt.spec.js b/tests/declaration_files_node/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declaration_files_node/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declaration_files_node/test_absolute.js b/tests/declaration_files_node/test_absolute.js new file mode 100644 index 000000000000..cf562b0f1254 --- /dev/null +++ b/tests/declaration_files_node/test_absolute.js @@ -0,0 +1,21 @@ +/* @flow */ + +// This will require ./node_modules/B.js.flow +var B1 = require('B'); +(B1.fun(): string); // Error number ~> string + +// This will require ./node_modules/B.js.flow +var B2 = require('B.js'); +(B2.fun(): string); // Error number ~> string + +var C = require('package_with_full_main'); +(C.fun(): string); // Error number ~> string + +var D = require('package_with_partial_main'); +(D.fun(): string); // Error number ~> string + +var E = require('package_with_no_package_json'); +(E.fun(): string); // Error number ~> string + +var F = require('package_with_dir_main'); +(F.fun(): string); // Error number ~> string diff --git a/tests/declaration_files_node/test_relative.js b/tests/declaration_files_node/test_relative.js new file mode 100644 index 000000000000..340a3f68cdfe --- /dev/null +++ b/tests/declaration_files_node/test_relative.js @@ -0,0 +1,13 @@ +/* @flow */ + +// This will require ./A.js.flow +var A1 = require('./A'); +(A1.fun(): string); // Error number ~> string + +// This will require ./A.js.flow +var A2 = require('./A.js'); +(A2.fun(): string); // Error number ~> string + +var CJS = require('./CJS.js'); +(CJS: string); +(CJS: number); // Error: string ~> number diff --git a/tests/declare_class/__snapshots__/jsfmt.spec.js.snap b/tests/declare_class/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ed66b2e693cc --- /dev/null +++ b/tests/declare_class/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,29 @@ +exports[`test declare_class.js 1`] = ` +"declare class C { + static x: number; + static foo(x: number): void; +} + +C.x = \"\"; +C.foo(\"\"); + +(C.name: string); +(C.name: number); // error, it\'s a string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/declare_class/declare_class.js b/tests/declare_class/declare_class.js new file mode 100644 index 000000000000..3096c97af9fd --- /dev/null +++ b/tests/declare_class/declare_class.js @@ -0,0 +1,10 @@ +declare class C { + static x: number; + static foo(x: number): void; +} + +C.x = ""; +C.foo(""); + +(C.name: string); +(C.name: number); // error, it's a string diff --git a/tests/declare_class/jsfmt.spec.js b/tests/declare_class/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_class/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_class/lib/__snapshots__/jsfmt.spec.js.snap b/tests/declare_class/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fcb6db09e975 --- /dev/null +++ b/tests/declare_class/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,28 @@ +exports[`test test.js 1`] = ` +"declare class _C { + foo(): number; +} +declare var _module: { + C: Class<_C>; +} +declare class D extends _module.C { + foo(): string; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/declare_class/lib/jsfmt.spec.js b/tests/declare_class/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_class/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_class/lib/test.js b/tests/declare_class/lib/test.js new file mode 100644 index 000000000000..03ce578f62fc --- /dev/null +++ b/tests/declare_class/lib/test.js @@ -0,0 +1,9 @@ +declare class _C { + foo(): number; +} +declare var _module: { + C: Class<_C>; +} +declare class D extends _module.C { + foo(): string; +} diff --git a/tests/declare_export/B.js b/tests/declare_export/B.js new file mode 100644 index 000000000000..e4d0f1b41f44 --- /dev/null +++ b/tests/declare_export/B.js @@ -0,0 +1,3 @@ +/* @flow */ + +exports.numberValue = 42; diff --git a/tests/declare_export/C.js b/tests/declare_export/C.js new file mode 100644 index 000000000000..e667c4717b69 --- /dev/null +++ b/tests/declare_export/C.js @@ -0,0 +1 @@ +/* @flow */ diff --git a/tests/declare_export/CommonJS_Clobbering_Class.js b/tests/declare_export/CommonJS_Clobbering_Class.js new file mode 100644 index 000000000000..4fbd96118432 --- /dev/null +++ b/tests/declare_export/CommonJS_Clobbering_Class.js @@ -0,0 +1,21 @@ +/** + * @providesModule CommonJS_Clobbering_Class + * @flow + */ + +class Base { + static baseProp: number; +} + +class Test extends Base { + static childProp: number; + + static staticNumber1():number { return 1; } + static staticNumber2():number { return 2; } + static staticNumber3():number { return 3; } + + instNumber1():number { return 1; } + instNumber2():number { return 2; } +}; + +module.exports = Test; diff --git a/tests/declare_export/CommonJS_Clobbering_Lit.js b/tests/declare_export/CommonJS_Clobbering_Lit.js new file mode 100644 index 000000000000..991b7bc37c12 --- /dev/null +++ b/tests/declare_export/CommonJS_Clobbering_Lit.js @@ -0,0 +1,12 @@ +/** + * @providesModule CommonJS_Clobbering_Lit + * @flow + */ + +module.exports = { + numberValue1: 1, + numberValue2: 2, + numberValue3: 3, + numberValue4: 4, + numberValue5: 5 +}; diff --git a/tests/declare_export/CommonJS_Named.js b/tests/declare_export/CommonJS_Named.js new file mode 100644 index 000000000000..698ec4f05276 --- /dev/null +++ b/tests/declare_export/CommonJS_Named.js @@ -0,0 +1,10 @@ +/** + * @providesModule CommonJS_Named + * @flow + */ + +exports.numberValue1 = 1; +exports.numberValue2 = 2; +exports.numberValue3 = 3; +exports.numberValue4 = 4; +exports.numberValue5 = 5; diff --git a/tests/declare_export/ES6_DefaultAndNamed.js b/tests/declare_export/ES6_DefaultAndNamed.js new file mode 100644 index 000000000000..afa31fd3ea2c --- /dev/null +++ b/tests/declare_export/ES6_DefaultAndNamed.js @@ -0,0 +1,4 @@ +/* @flow */ + +declare export default number; +declare export var str: string; diff --git a/tests/declare_export/ES6_Default_AnonFunction1.js b/tests/declare_export/ES6_Default_AnonFunction1.js new file mode 100644 index 000000000000..d93d3f0a1feb --- /dev/null +++ b/tests/declare_export/ES6_Default_AnonFunction1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_AnonFunction1 + * @flow + */ + +declare export default () => number; diff --git a/tests/declare_export/ES6_Default_AnonFunction2.js b/tests/declare_export/ES6_Default_AnonFunction2.js new file mode 100644 index 000000000000..f539ad3c1ec7 --- /dev/null +++ b/tests/declare_export/ES6_Default_AnonFunction2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_AnonFunction2 + * @flow + */ + +declare export default () =>number; diff --git a/tests/declare_export/ES6_Default_NamedClass1.js b/tests/declare_export/ES6_Default_NamedClass1.js new file mode 100644 index 000000000000..7779c6081957 --- /dev/null +++ b/tests/declare_export/ES6_Default_NamedClass1.js @@ -0,0 +1,12 @@ +/** + * @providesModule ES6_Default_NamedClass1 + * @flow + */ + +declare export default class FooImpl { givesANum(): number; }; + +// Regression test for https://github.com/facebook/flow/issues/511 +// +// Default-exported class should also be available in local scope +declare export { FooImpl as Foo } +declare export function getAFoo(): FooImpl; diff --git a/tests/declare_export/ES6_Default_NamedClass2.js b/tests/declare_export/ES6_Default_NamedClass2.js new file mode 100644 index 000000000000..9c27f1f9b9eb --- /dev/null +++ b/tests/declare_export/ES6_Default_NamedClass2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_NamedClass2 + * @flow + */ + +declare export default class Foo { givesANum(): number; }; diff --git a/tests/declare_export/ES6_Default_NamedFunction1.js b/tests/declare_export/ES6_Default_NamedFunction1.js new file mode 100644 index 000000000000..186dcb632069 --- /dev/null +++ b/tests/declare_export/ES6_Default_NamedFunction1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_NamedFunction1 + * @flow + */ + +declare export default function foo():number; diff --git a/tests/declare_export/ES6_Default_NamedFunction2.js b/tests/declare_export/ES6_Default_NamedFunction2.js new file mode 100644 index 000000000000..87b3d290d93c --- /dev/null +++ b/tests/declare_export/ES6_Default_NamedFunction2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_NamedFunction2 + * @flow + */ + +declare export default function foo():number; diff --git a/tests/declare_export/ES6_ExportAllFromMulti.js b/tests/declare_export/ES6_ExportAllFromMulti.js new file mode 100644 index 000000000000..b0f1d15ffaa4 --- /dev/null +++ b/tests/declare_export/ES6_ExportAllFromMulti.js @@ -0,0 +1,4 @@ +// @flow + +declare export * from "./ES6_ExportAllFrom_Source1"; +declare export * from "./ES6_ExportAllFrom_Source2"; diff --git a/tests/declare_export/ES6_ExportAllFrom_Intermediary1.js b/tests/declare_export/ES6_ExportAllFrom_Intermediary1.js new file mode 100644 index 000000000000..7fc67e38b8eb --- /dev/null +++ b/tests/declare_export/ES6_ExportAllFrom_Intermediary1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Intermediary1 + * @flow + */ + +declare export * from "ES6_ExportAllFrom_Source1"; diff --git a/tests/declare_export/ES6_ExportAllFrom_Intermediary2.js b/tests/declare_export/ES6_ExportAllFrom_Intermediary2.js new file mode 100644 index 000000000000..5239b4ec9b3f --- /dev/null +++ b/tests/declare_export/ES6_ExportAllFrom_Intermediary2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Intermediary2 + * @flow + */ + +declare export * from "ES6_ExportAllFrom_Source2"; diff --git a/tests/declare_export/ES6_ExportAllFrom_Source1.js b/tests/declare_export/ES6_ExportAllFrom_Source1.js new file mode 100644 index 000000000000..349a2519ab5a --- /dev/null +++ b/tests/declare_export/ES6_ExportAllFrom_Source1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Source1 + * @flow + */ + +declare export var numberValue1: number; diff --git a/tests/declare_export/ES6_ExportAllFrom_Source2.js b/tests/declare_export/ES6_ExportAllFrom_Source2.js new file mode 100644 index 000000000000..b048c4c660af --- /dev/null +++ b/tests/declare_export/ES6_ExportAllFrom_Source2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Source2 + * @flow + */ + +declare export var numberValue2: number; diff --git a/tests/declare_export/ES6_ExportFrom_Intermediary1.js b/tests/declare_export/ES6_ExportFrom_Intermediary1.js new file mode 100644 index 000000000000..42deb8f3cab4 --- /dev/null +++ b/tests/declare_export/ES6_ExportFrom_Intermediary1.js @@ -0,0 +1,9 @@ +/** + * @providesModule ES6_ExportFrom_Intermediary1 + * @flow + */ + +declare export { + numberValue1, + numberValue2 as numberValue2_renamed +} from "ES6_ExportFrom_Source1"; diff --git a/tests/declare_export/ES6_ExportFrom_Intermediary2.js b/tests/declare_export/ES6_ExportFrom_Intermediary2.js new file mode 100644 index 000000000000..bb52574f5f76 --- /dev/null +++ b/tests/declare_export/ES6_ExportFrom_Intermediary2.js @@ -0,0 +1,9 @@ +/** + * @providesModule ES6_ExportFrom_Intermediary2 + * @flow + */ + +declare export { + numberValue1, + numberValue2 as numberValue2_renamed2 +} from "ES6_ExportFrom_Source2"; diff --git a/tests/declare_export/ES6_ExportFrom_Source1.js b/tests/declare_export/ES6_ExportFrom_Source1.js new file mode 100644 index 000000000000..519dacde3334 --- /dev/null +++ b/tests/declare_export/ES6_ExportFrom_Source1.js @@ -0,0 +1,7 @@ +/** + * @providesModule ES6_ExportFrom_Source1 + * @flow + */ + +declare export var numberValue1: number; +declare export var numberValue2: number; diff --git a/tests/declare_export/ES6_ExportFrom_Source2.js b/tests/declare_export/ES6_ExportFrom_Source2.js new file mode 100644 index 000000000000..71ba5d456098 --- /dev/null +++ b/tests/declare_export/ES6_ExportFrom_Source2.js @@ -0,0 +1,7 @@ +/** + * @providesModule ES6_ExportFrom_Source2 + * @flow + */ + +declare export var numberValue1: number; +declare export var numberValue2: number; diff --git a/tests/declare_export/ES6_Named1.js b/tests/declare_export/ES6_Named1.js new file mode 100644 index 000000000000..b448ee324be3 --- /dev/null +++ b/tests/declare_export/ES6_Named1.js @@ -0,0 +1,21 @@ +/** + * @providesModule ES6_Named1 + * @flow + */ + +var specifierNumber1 = 1; +var specifierNumber2 = 2; +var specifierNumber3 = 3; +var groupedSpecifierNumber1 = 1; +var groupedSpecifierNumber2 = 2; + +declare export {specifierNumber1}; +declare export {specifierNumber2 as specifierNumber2Renamed}; +declare export {specifierNumber3}; +declare export {groupedSpecifierNumber1, groupedSpecifierNumber2}; + +declare export function givesANumber(): number; +declare export class NumberGenerator { givesANumber(): number; }; + +declare export var varDeclNumber1: number; +declare export var varDeclNumber2: number; diff --git a/tests/declare_export/ES6_Named2.js b/tests/declare_export/ES6_Named2.js new file mode 100644 index 000000000000..5f29921f40b5 --- /dev/null +++ b/tests/declare_export/ES6_Named2.js @@ -0,0 +1,19 @@ +/** + * @providesModule ES6_Named2 + * @flow + */ + +var specifierNumber4 = 1; +var specifierNumber5 = 2; +var groupedSpecifierNumber3 = 1; +var groupedSpecifierNumber4 = 2; + +declare export {specifierNumber4}; +declare export {specifierNumber5 as specifierNumber5Renamed}; +declare export {groupedSpecifierNumber3, groupedSpecifierNumber4}; + +declare export function givesANumber2(): number; +declare export class NumberGenerator2 { givesANumber(): number; }; + +declare export var varDeclNumber3: number; +declare export var varDeclNumber4: number; diff --git a/tests/declare_export/ProvidesModuleA.js b/tests/declare_export/ProvidesModuleA.js new file mode 100644 index 000000000000..f2cbd52ce005 --- /dev/null +++ b/tests/declare_export/ProvidesModuleA.js @@ -0,0 +1,10 @@ +/** + * @providesModule A + * @flow + */ + +exports.numberValue1 = 42; +exports.numberValue2 = 42; +exports.numberValue3 = 42; +exports.numberValue4 = 42; +exports.stringValue = "str"; diff --git a/tests/declare_export/ProvidesModuleCJSDefault.js b/tests/declare_export/ProvidesModuleCJSDefault.js new file mode 100644 index 000000000000..a3d9c135a2c1 --- /dev/null +++ b/tests/declare_export/ProvidesModuleCJSDefault.js @@ -0,0 +1,8 @@ +/** + * @providesModule CJSDefault + * @flow + */ + +module.exports = { + numberValue: 42 +}; diff --git a/tests/declare_export/ProvidesModuleD.js b/tests/declare_export/ProvidesModuleD.js new file mode 100644 index 000000000000..a4d5ee842062 --- /dev/null +++ b/tests/declare_export/ProvidesModuleD.js @@ -0,0 +1,4 @@ +/** + * @providesModule D + * @flow + */ diff --git a/tests/declare_export/ProvidesModuleES6Default.js b/tests/declare_export/ProvidesModuleES6Default.js new file mode 100644 index 000000000000..636a1946109c --- /dev/null +++ b/tests/declare_export/ProvidesModuleES6Default.js @@ -0,0 +1,10 @@ +/** + * @providesModule ES6Default + * @flow + */ + +/* +export default { + numberValue: 42, +}; +*/ diff --git a/tests/declare_export/SideEffects.js b/tests/declare_export/SideEffects.js new file mode 100644 index 000000000000..e667c4717b69 --- /dev/null +++ b/tests/declare_export/SideEffects.js @@ -0,0 +1 @@ +/* @flow */ diff --git a/tests/declare_export/__snapshots__/jsfmt.spec.js.snap b/tests/declare_export/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..829bbe76b0ee --- /dev/null +++ b/tests/declare_export/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,1212 @@ +exports[`test B.js 1`] = ` +"/* @flow */ + +exports.numberValue = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +exports.numberValue = 42; + +" +`; + +exports[`test C.js 1`] = ` +"/* @flow */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test CommonJS_Clobbering_Class.js 1`] = ` +"/** + * @providesModule CommonJS_Clobbering_Class + * @flow + */ + +class Base { + static baseProp: number; +} + +class Test extends Base { + static childProp: number; + + static staticNumber1():number { return 1; } + static staticNumber2():number { return 2; } + static staticNumber3():number { return 3; } + + instNumber1():number { return 1; } + instNumber2():number { return 2; } +}; + +module.exports = Test; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Clobbering_Class + * @flow + */ +class Base { + static baseProp: number; +} +class Test extends Base { + static childProp: number; + staticNumber1(): number { + return 1; + } + staticNumber2(): number { + return 2; + } + staticNumber3(): number { + return 3; + } + instNumber1(): number { + return 1; + } + instNumber2(): number { + return 2; + } +} +module.exports = Test; + +" +`; + +exports[`test CommonJS_Clobbering_Lit.js 1`] = ` +"/** + * @providesModule CommonJS_Clobbering_Lit + * @flow + */ + +module.exports = { + numberValue1: 1, + numberValue2: 2, + numberValue3: 3, + numberValue4: 4, + numberValue5: 5 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Clobbering_Lit + * @flow + */ +module.exports = { + numberValue1: 1, + numberValue2: 2, + numberValue3: 3, + numberValue4: 4, + numberValue5: 5 +}; + +" +`; + +exports[`test CommonJS_Named.js 1`] = ` +"/** + * @providesModule CommonJS_Named + * @flow + */ + +exports.numberValue1 = 1; +exports.numberValue2 = 2; +exports.numberValue3 = 3; +exports.numberValue4 = 4; +exports.numberValue5 = 5; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Named + * @flow + */ +exports.numberValue1 = 1; +exports.numberValue2 = 2; +exports.numberValue3 = 3; +exports.numberValue4 = 4; +exports.numberValue5 = 5; + +" +`; + +exports[`test ES6_Default_AnonFunction1.js 1`] = ` +"/** + * @providesModule ES6_Default_AnonFunction1 + * @flow + */ + +declare export default () => number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Default_AnonFunction2.js 1`] = ` +"/** + * @providesModule ES6_Default_AnonFunction2 + * @flow + */ + +declare export default () =>number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Default_NamedClass1.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedClass1 + * @flow + */ + +declare export default class FooImpl { givesANum(): number; }; + +// Regression test for https://github.com/facebook/flow/issues/511 +// +// Default-exported class should also be available in local scope +declare export { FooImpl as Foo } +declare export function getAFoo(): FooImpl; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Default_NamedClass2.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedClass2 + * @flow + */ + +declare export default class Foo { givesANum(): number; }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Default_NamedFunction1.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedFunction1 + * @flow + */ + +declare export default function foo():number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Default_NamedFunction2.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedFunction2 + * @flow + */ + +declare export default function foo():number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_DefaultAndNamed.js 1`] = ` +"/* @flow */ + +declare export default number; +declare export var str: string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportAllFrom_Intermediary1.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Intermediary1 + * @flow + */ + +declare export * from \"ES6_ExportAllFrom_Source1\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportAllFrom_Intermediary2.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Intermediary2 + * @flow + */ + +declare export * from \"ES6_ExportAllFrom_Source2\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportAllFrom_Source1.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Source1 + * @flow + */ + +declare export var numberValue1: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportAllFrom_Source2.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Source2 + * @flow + */ + +declare export var numberValue2: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportAllFromMulti.js 1`] = ` +"// @flow + +declare export * from \"./ES6_ExportAllFrom_Source1\"; +declare export * from \"./ES6_ExportAllFrom_Source2\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportFrom_Intermediary1.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Intermediary1 + * @flow + */ + +declare export { + numberValue1, + numberValue2 as numberValue2_renamed +} from \"ES6_ExportFrom_Source1\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportFrom_Intermediary2.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Intermediary2 + * @flow + */ + +declare export { + numberValue1, + numberValue2 as numberValue2_renamed2 +} from \"ES6_ExportFrom_Source2\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportFrom_Source1.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Source1 + * @flow + */ + +declare export var numberValue1: number; +declare export var numberValue2: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_ExportFrom_Source2.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Source2 + * @flow + */ + +declare export var numberValue1: number; +declare export var numberValue2: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (6:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Named1.js 1`] = ` +"/** + * @providesModule ES6_Named1 + * @flow + */ + +var specifierNumber1 = 1; +var specifierNumber2 = 2; +var specifierNumber3 = 3; +var groupedSpecifierNumber1 = 1; +var groupedSpecifierNumber2 = 2; + +declare export {specifierNumber1}; +declare export {specifierNumber2 as specifierNumber2Renamed}; +declare export {specifierNumber3}; +declare export {groupedSpecifierNumber1, groupedSpecifierNumber2}; + +declare export function givesANumber(): number; +declare export class NumberGenerator { givesANumber(): number; }; + +declare export var varDeclNumber1: number; +declare export var varDeclNumber2: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (12:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ES6_Named2.js 1`] = ` +"/** + * @providesModule ES6_Named2 + * @flow + */ + +var specifierNumber4 = 1; +var specifierNumber5 = 2; +var groupedSpecifierNumber3 = 1; +var groupedSpecifierNumber4 = 2; + +declare export {specifierNumber4}; +declare export {specifierNumber5 as specifierNumber5Renamed}; +declare export {groupedSpecifierNumber3, groupedSpecifierNumber4}; + +declare export function givesANumber2(): number; +declare export class NumberGenerator2 { givesANumber(): number; }; + +declare export var varDeclNumber3: number; +declare export var varDeclNumber4: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (11:8) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseExpressionStatement (/node_modules/babylon/lib/index.js:2109:8) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5246:20) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) +" +`; + +exports[`test ProvidesModuleA.js 1`] = ` +"/** + * @providesModule A + * @flow + */ + +exports.numberValue1 = 42; +exports.numberValue2 = 42; +exports.numberValue3 = 42; +exports.numberValue4 = 42; +exports.stringValue = \"str\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule A + * @flow + */ +exports.numberValue1 = 42; +exports.numberValue2 = 42; +exports.numberValue3 = 42; +exports.numberValue4 = 42; +exports.stringValue = \"str\"; + +" +`; + +exports[`test ProvidesModuleCJSDefault.js 1`] = ` +"/** + * @providesModule CJSDefault + * @flow + */ + +module.exports = { + numberValue: 42 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CJSDefault + * @flow + */ +module.exports = { numberValue: 42 }; + +" +`; + +exports[`test ProvidesModuleD.js 1`] = ` +"/** + * @providesModule D + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test ProvidesModuleES6Default.js 1`] = ` +"/** + * @providesModule ES6Default + * @flow + */ + +/* +export default { + numberValue: 42, +}; +*/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test SideEffects.js 1`] = ` +"/* @flow */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test es6modules.js 1`] = ` +"/* @flow */ + +// ===================== // +// == Path Resolution == // +// ===================== // + +// @providesModule +import * as DefaultA from \"A\"; +var a1: number = DefaultA.numberValue1; +var a2: string = DefaultA.numberValue1; // Error: number ~> string + +// File path +import * as DefaultB from \"./B\"; +var b1: number = DefaultB.numberValue; +var b2: string = DefaultB.numberValue; // Error: number ~> string + +// C.js exists, but not as a providesModule +import DefaultC from \"C\"; // Error: No such module + +// @providesModule D exists, but not as a filename +import DefaultD from \"./D\"; // Error: No such module + +// ================================================ // +// == CommonJS Clobbering Literal Exports -> ES6 == // +// ================================================ // + +import {doesntExist1} from \"CommonJS_Clobbering_Lit\"; // Error: Not an exported binding + +import {numberValue1} from \"CommonJS_Clobbering_Lit\"; +var c1: number = numberValue1; +var c2: string = numberValue1; // Error: number ~> string + +import {numberValue2 as numVal1} from \"CommonJS_Clobbering_Lit\"; +var d1: number = numVal1; +var d2: string = numVal1; // Error: number ~> string + +import CJS_Clobb_Lit from \"CommonJS_Clobbering_Lit\"; +var e1: number = CJS_Clobb_Lit.numberValue3; +var e2: string = CJS_Clobb_Lit.numberValue3; // Error: number ~> string +CJS_Clobb_Lit.doesntExist; // Error: doesntExist isn\'t a property + +import * as CJS_Clobb_Lit_NS from \"CommonJS_Clobbering_Lit\"; +var f1: number = CJS_Clobb_Lit_NS.numberValue4; +var f2: number = CJS_Clobb_Lit_NS.default.numberValue4; +CJS_Clobb_Lit_NS.default.default; // Error: No \'default\' property on the exported obj +var f3: string = CJS_Clobb_Lit_NS.numberValue4; // Error: number ~> string +var f4: string = CJS_Clobb_Lit_NS.default.numberValue5; // Error: number ~> string + +// ============================================== // +// == CommonJS Clobbering Class Exports -> ES6 == // +// ============================================== // + +import {doesntExist2} from \"CommonJS_Clobbering_Class\"; // Error: Not an exported binding + +// The following import should error because class statics are not turned into +// named exports for now. This avoids complexities with polymorphic static +// members (where the polymophism is defined on the class itself rather than the +// method). +import {staticNumber1, baseProp, childProp} from \"CommonJS_Clobbering_Class\"; // Error + +import CJS_Clobb_Class from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class(); +new CJS_Clobb_Class().doesntExist; // Error: Class has no \`doesntExist\` property +var h1: number = CJS_Clobb_Class.staticNumber2(); +var h2: string = CJS_Clobb_Class.staticNumber2(); // Error: number ~> string +var h3: number = new CJS_Clobb_Class().instNumber1(); +var h4: string = new CJS_Clobb_Class().instNumber1(); // Error: number ~> string + +import * as CJS_Clobb_Class_NS from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class_NS(); // Error: Namespace object isn\'t constructable +var i1: number = CJS_Clobb_Class_NS.staticNumber3(); // Error: Class statics not copied to Namespace object +var i2: number = new CJS_Clobb_Class_NS.default().instNumber2(); +var i3: string = new CJS_Clobb_Class_NS.default().instNumber2(); // Error: number ~> string + +// =================================== // +// == CommonJS Named Exports -> ES6 == // +// =================================== // + +import {doesntExist3} from \"CommonJS_Named\"; // Error: Not an exported binding + +import {numberValue2} from \"CommonJS_Named\"; +var j1: number = numberValue2; +var j2: string = numberValue2; // Error: number ~> string + +import {numberValue3 as numVal3} from \"CommonJS_Named\"; +var k1: number = numVal3; +var k2: string = numVal3; // Error: number ~> string + +import * as CJS_Named from \"CommonJS_Named\"; +var l1: number = CJS_Named.numberValue1; +var l2: string = CJS_Named.numberValue1; // Error: number ~> string +CJS_Named.doesntExist; // Error: doesntExist isn\'t a property + +import * as CJS_Named_NS from \"CommonJS_Named\"; +var m1: number = CJS_Named_NS.numberValue4; +var m2: string = CJS_Named_NS.default.numberValue4; // Error: CommonJS_Named has no default export +var m3: string = CJS_Named_NS.numberValue4; // Error: number ~> string + +////////////////////////////// +// == ES6 Default -> ES6 == // +////////////////////////////// + +import {doesntExist4} from \"ES6_Default_AnonFunction1\"; // Error: Not an exported binding + +import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\"; +var n1: number = ES6_Def_AnonFunc1(); +var n2: string = ES6_Def_AnonFunc1(); // Error: number ~> string + +import ES6_Def_NamedFunc1 from \"ES6_Default_NamedFunction1\"; +var o1: number = ES6_Def_NamedFunc1(); +var o2: string = ES6_Def_NamedFunc1(); // Error: number ~> string + + + + + +import ES6_Def_NamedClass1 from \"ES6_Default_NamedClass1\"; +var q1: number = new ES6_Def_NamedClass1().givesANum(); +var q2: string = new ES6_Def_NamedClass1().givesANum(); // Error: number ~> string + +//////////////////////////// +// == ES6 Named -> ES6 == // +//////////////////////////// + +import doesntExist5 from \"ES6_Named1\"; // Error: Not an exported binding + +import {specifierNumber1 as specifierNumber1_1} from \"ES6_Named1\"; +var r1: number = specifierNumber1_1; +var r2: string = specifierNumber1_1; // Error: number ~> string + +import {specifierNumber2Renamed} from \"ES6_Named1\"; +var s1: number = specifierNumber2Renamed; +var s2: string = specifierNumber2Renamed; // Error: number ~> string + +import {specifierNumber3 as specifierNumber3Renamed} from \"ES6_Named1\"; +var t1: number = specifierNumber3Renamed; +var t2: string = specifierNumber3Renamed; // Error: number ~> string + +import {groupedSpecifierNumber1, groupedSpecifierNumber2} from \"ES6_Named1\"; +var u1: number = groupedSpecifierNumber1; +var u2: number = groupedSpecifierNumber2; +var u3: string = groupedSpecifierNumber1; // Error: number ~> string +var u4: string = groupedSpecifierNumber2; // Error: number ~> string + +import {givesANumber} from \"ES6_Named1\"; +var v1: number = givesANumber(); +var v2: string = givesANumber(); // Error: number ~> string + +import {NumberGenerator} from \"ES6_Named1\"; +var w1: number = new NumberGenerator().givesANumber(); +var w2: string = new NumberGenerator().givesANumber(); // Error: number ~> string + +import {varDeclNumber1, varDeclNumber2} from \"ES6_Named1\"; +var x1: number = varDeclNumber1; +var x2: number = varDeclNumber2; +var x3: string = varDeclNumber1; // Error: number ~> string +var x4: string = varDeclNumber2; // Error: number ~> string + + + + + + + + + +import {numberValue1 as numberValue4} from \"ES6_ExportFrom_Intermediary1\"; +var aa1: number = numberValue4; +var aa2: string = numberValue4; // Error: number ~> string + +import {numberValue2_renamed} from \"ES6_ExportFrom_Intermediary1\"; +var ab1: number = numberValue2_renamed; +var ab2: string = numberValue2_renamed; // Error: number ~> string + +import {numberValue1 as numberValue5} from \"ES6_ExportAllFrom_Intermediary1\"; +var ac1: number = numberValue5; +var ac2: string = numberValue5; // Error: number ~> string + +/////////////////////////////////// +// == ES6 Default -> CommonJS == // +/////////////////////////////////// + +require(\'ES6_Default_AnonFunction2\').doesntExist; // Error: \'doesntExist\' isn\'t an export + +var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default; +var ad1: number = ES6_Def_AnonFunc2(); +var ad2: string = ES6_Def_AnonFunc2(); // Error: number ~> string + +var ES6_Def_NamedFunc2 = require(\"ES6_Default_NamedFunction2\").default; +var ae1: number = ES6_Def_NamedFunc2(); +var ae2: string = ES6_Def_NamedFunc2(); // Error: number ~> string + + + + + +var ES6_Def_NamedClass2 = require(\"ES6_Default_NamedClass2\").default; +var ag1: number = new ES6_Def_NamedClass2().givesANum(); +var ag2: string = new ES6_Def_NamedClass2().givesANum(); // Error: number ~> string + +///////////////////////////////// +// == ES6 Named -> CommonJS == // +///////////////////////////////// + +var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4; +var ah1: number = specifierNumber4; +var ah2: string = specifierNumber4; // Error: number ~> string + +var specifierNumber5Renamed = require(\"ES6_Named2\").specifierNumber5Renamed; +var ai1: number = specifierNumber5Renamed; +var ai2: string = specifierNumber5Renamed; // Error: number ~> string + +var groupedSpecifierNumber3 = require(\"ES6_Named2\").groupedSpecifierNumber3; +var groupedSpecifierNumber4 = require(\"ES6_Named2\").groupedSpecifierNumber4; +var aj1: number = groupedSpecifierNumber3; +var aj2: number = groupedSpecifierNumber4; +var aj3: string = groupedSpecifierNumber3; // Error: number ~> string +var aj4: string = groupedSpecifierNumber4; // Error: number ~> string + +var givesANumber2 = require(\"ES6_Named2\").givesANumber2; +var ak1: number = givesANumber2(); +var ak2: string = givesANumber2(); // Error: number ~> string + +var NumberGenerator2 = require(\"ES6_Named2\").NumberGenerator2; +var al1: number = new NumberGenerator2().givesANumber(); +var al2: string = new NumberGenerator2().givesANumber(); // Error: number ~> string + +var varDeclNumber3 = require(\"ES6_Named2\").varDeclNumber3; +var varDeclNumber4 = require(\"ES6_Named2\").varDeclNumber4; +var am1: number = varDeclNumber3; +var am2: number = varDeclNumber4; +var am3: string = varDeclNumber3; // Error: number ~> string +var am4: string = varDeclNumber4; // Error: number ~> string + + + + + + + + + +var numberValue6 = require(\"ES6_ExportFrom_Intermediary2\").numberValue1; +var ap1: number = numberValue6; +var ap2: string = numberValue6; // Error: number ~> string + +var numberValue2_renamed2 = require(\"ES6_ExportFrom_Intermediary2\").numberValue2_renamed2; +var aq1: number = numberValue2_renamed2; +var aq2: string = numberValue2_renamed2; // Error: number ~> string + +var numberValue7 = require(\"ES6_ExportAllFrom_Intermediary2\").numberValue2; +var ar1: number = numberValue7; +var ar2: string = numberValue7; // Error: number ~> string + +//////////////////////////////////////////////////////// +// == ES6 Default+Named -> ES6 import Default+Named== // +//////////////////////////////////////////////////////// + +import defaultNum, {str as namedStr} from \"./ES6_DefaultAndNamed\"; + +var as1: number = defaultNum; +var as2: string = defaultNum; // Error: number ~> string + +var as3: string = namedStr; +var as4: number = namedStr; // Error: string ~> number + +//////////////////////////////////////// +// == Side-effect only ES6 imports == // +//////////////////////////////////////// + +import \"./SideEffects\"; + +////////////////////////////////////////////// +// == Suggest export name on likely typo == // +////////////////////////////////////////////// +import specifierNumber1 from \"ES6_Named1\"; // Error: Did you mean \`import {specifierNumber1} from ...\`? +import {specifierNumber} from \"ES6_Named1\"; // Error: Did you mean \`specifierNumber1\`? + +/////////////////////////////////////////////////// +// == Multi \`export *\` should combine exports == // +/////////////////////////////////////////////////// +import { + numberValue1 as numberValue8, + numberValue2 as numberValue9 +} from \"./ES6_ExportAllFromMulti\"; + +var at1: number = numberValue8; +var at2: string = numberValue8; // Error: number ~> string + +var at3: number = numberValue9; +var at4: string = numberValue9; // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// ===================== // +// == Path Resolution == // +// ===================== // +// @providesModule +import * as DefaultA from \"A\"; +var a1: number = DefaultA.numberValue1; +var a2: string = DefaultA.numberValue1;// Error: number ~> string +// File path +import * as DefaultB from \"./B\"; +var b1: number = DefaultB.numberValue; +var b2: string = DefaultB.numberValue;// Error: number ~> string +// C.js exists, but not as a providesModule +import DefaultC from \"C\";// Error: No such module +// @providesModule D exists, but not as a filename +import DefaultD from \"./D\";// Error: No such module +// ================================================ // +// == CommonJS Clobbering Literal Exports -> ES6 == // +// ================================================ // +import { doesntExist1 } from \"CommonJS_Clobbering_Lit\";// Error: Not an exported binding +import { numberValue1 } from \"CommonJS_Clobbering_Lit\"; +var c1: number = numberValue1; +var c2: string = numberValue1;// Error: number ~> string +import { numberValue2 as numVal1 } from \"CommonJS_Clobbering_Lit\"; +var d1: number = numVal1; +var d2: string = numVal1;// Error: number ~> string +import CJS_Clobb_Lit from \"CommonJS_Clobbering_Lit\"; +var e1: number = CJS_Clobb_Lit.numberValue3; +var e2: string = CJS_Clobb_Lit.numberValue3;// Error: number ~> string +CJS_Clobb_Lit.doesntExist;// Error: doesntExist isn\'t a property +import * as CJS_Clobb_Lit_NS from \"CommonJS_Clobbering_Lit\"; +var f1: number = CJS_Clobb_Lit_NS.numberValue4; +var f2: number = CJS_Clobb_Lit_NS.default.numberValue4; +CJS_Clobb_Lit_NS.default.default;// Error: No \'default\' property on the exported obj +var f3: string = CJS_Clobb_Lit_NS.numberValue4;// Error: number ~> string +var f4: string = CJS_Clobb_Lit_NS.default.numberValue5;// Error: number ~> string +// ============================================== // +// == CommonJS Clobbering Class Exports -> ES6 == // +// ============================================== // +import { doesntExist2 } from \"CommonJS_Clobbering_Class\";// Error: Not an exported binding +// The following import should error because class statics are not turned into +// named exports for now. This avoids complexities with polymorphic static +// members (where the polymophism is defined on the class itself rather than the +// method). +import { staticNumber1, baseProp, childProp } from \"CommonJS_Clobbering_Class\";// Error +import CJS_Clobb_Class from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class(); +new CJS_Clobb_Class().doesntExist;// Error: Class has no \`doesntExist\` property +var h1: number = CJS_Clobb_Class.staticNumber2(); +var h2: string = CJS_Clobb_Class.staticNumber2();// Error: number ~> string +var h3: number = new CJS_Clobb_Class().instNumber1(); +var h4: string = new CJS_Clobb_Class().instNumber1();// Error: number ~> string +import * as CJS_Clobb_Class_NS from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class_NS();// Error: Namespace object isn\'t constructable +var i1: number = CJS_Clobb_Class_NS.staticNumber3();// Error: Class statics not copied to Namespace object +var i2: number = new CJS_Clobb_Class_NS.default().instNumber2(); +var i3: string = new CJS_Clobb_Class_NS.default().instNumber2();// Error: number ~> string +// =================================== // +// == CommonJS Named Exports -> ES6 == // +// =================================== // +import { doesntExist3 } from \"CommonJS_Named\";// Error: Not an exported binding +import { numberValue2 } from \"CommonJS_Named\"; +var j1: number = numberValue2; +var j2: string = numberValue2;// Error: number ~> string +import { numberValue3 as numVal3 } from \"CommonJS_Named\"; +var k1: number = numVal3; +var k2: string = numVal3;// Error: number ~> string +import * as CJS_Named from \"CommonJS_Named\"; +var l1: number = CJS_Named.numberValue1; +var l2: string = CJS_Named.numberValue1;// Error: number ~> string +CJS_Named.doesntExist;// Error: doesntExist isn\'t a property +import * as CJS_Named_NS from \"CommonJS_Named\"; +var m1: number = CJS_Named_NS.numberValue4; +var m2: string = CJS_Named_NS.default.numberValue4;// Error: CommonJS_Named has no default export +var m3: string = CJS_Named_NS.numberValue4;// Error: number ~> string +////////////////////////////// +// == ES6 Default -> ES6 == // +////////////////////////////// +import { doesntExist4 } from \"ES6_Default_AnonFunction1\";// Error: Not an exported binding +import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\"; +var n1: number = ES6_Def_AnonFunc1(); +var n2: string = ES6_Def_AnonFunc1();// Error: number ~> string +import ES6_Def_NamedFunc1 from \"ES6_Default_NamedFunction1\"; +var o1: number = ES6_Def_NamedFunc1(); +var o2: string = ES6_Def_NamedFunc1();// Error: number ~> string +import ES6_Def_NamedClass1 from \"ES6_Default_NamedClass1\"; +var q1: number = new ES6_Def_NamedClass1().givesANum(); +var q2: string = new ES6_Def_NamedClass1().givesANum();// Error: number ~> string +//////////////////////////// +// == ES6 Named -> ES6 == // +//////////////////////////// +import doesntExist5 from \"ES6_Named1\";// Error: Not an exported binding +import { specifierNumber1 as specifierNumber1_1 } from \"ES6_Named1\"; +var r1: number = specifierNumber1_1; +var r2: string = specifierNumber1_1;// Error: number ~> string +import { specifierNumber2Renamed } from \"ES6_Named1\"; +var s1: number = specifierNumber2Renamed; +var s2: string = specifierNumber2Renamed;// Error: number ~> string +import { specifierNumber3 as specifierNumber3Renamed } from \"ES6_Named1\"; +var t1: number = specifierNumber3Renamed; +var t2: string = specifierNumber3Renamed;// Error: number ~> string +import { groupedSpecifierNumber1, groupedSpecifierNumber2 } from \"ES6_Named1\"; +var u1: number = groupedSpecifierNumber1; +var u2: number = groupedSpecifierNumber2; +var u3: string = groupedSpecifierNumber1;// Error: number ~> string +var u4: string = groupedSpecifierNumber2;// Error: number ~> string +import { givesANumber } from \"ES6_Named1\"; +var v1: number = givesANumber(); +var v2: string = givesANumber();// Error: number ~> string +import { NumberGenerator } from \"ES6_Named1\"; +var w1: number = new NumberGenerator().givesANumber(); +var w2: string = new NumberGenerator().givesANumber();// Error: number ~> string +import { varDeclNumber1, varDeclNumber2 } from \"ES6_Named1\"; +var x1: number = varDeclNumber1; +var x2: number = varDeclNumber2; +var x3: string = varDeclNumber1;// Error: number ~> string +var x4: string = varDeclNumber2;// Error: number ~> string +import { numberValue1 as numberValue4 } from \"ES6_ExportFrom_Intermediary1\"; +var aa1: number = numberValue4; +var aa2: string = numberValue4;// Error: number ~> string +import { numberValue2_renamed } from \"ES6_ExportFrom_Intermediary1\"; +var ab1: number = numberValue2_renamed; +var ab2: string = numberValue2_renamed;// Error: number ~> string +import { numberValue1 as numberValue5 } from \"ES6_ExportAllFrom_Intermediary1\"; +var ac1: number = numberValue5; +var ac2: string = numberValue5;// Error: number ~> string +/////////////////////////////////// +// == ES6 Default -> CommonJS == // +/////////////////////////////////// +require( + \"ES6_Default_AnonFunction2\" +).doesntExist;// Error: \'doesntExist\' isn\'t an export +var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default; +var ad1: number = ES6_Def_AnonFunc2(); +var ad2: string = ES6_Def_AnonFunc2();// Error: number ~> string +var ES6_Def_NamedFunc2 = require(\"ES6_Default_NamedFunction2\").default; +var ae1: number = ES6_Def_NamedFunc2(); +var ae2: string = ES6_Def_NamedFunc2();// Error: number ~> string +var ES6_Def_NamedClass2 = require(\"ES6_Default_NamedClass2\").default; +var ag1: number = new ES6_Def_NamedClass2().givesANum(); +var ag2: string = new ES6_Def_NamedClass2().givesANum();// Error: number ~> string +///////////////////////////////// +// == ES6 Named -> CommonJS == // +///////////////////////////////// +var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4; +var ah1: number = specifierNumber4; +var ah2: string = specifierNumber4;// Error: number ~> string +var specifierNumber5Renamed = require(\"ES6_Named2\").specifierNumber5Renamed; +var ai1: number = specifierNumber5Renamed; +var ai2: string = specifierNumber5Renamed;// Error: number ~> string +var groupedSpecifierNumber3 = require(\"ES6_Named2\").groupedSpecifierNumber3; +var groupedSpecifierNumber4 = require(\"ES6_Named2\").groupedSpecifierNumber4; +var aj1: number = groupedSpecifierNumber3; +var aj2: number = groupedSpecifierNumber4; +var aj3: string = groupedSpecifierNumber3;// Error: number ~> string +var aj4: string = groupedSpecifierNumber4;// Error: number ~> string +var givesANumber2 = require(\"ES6_Named2\").givesANumber2; +var ak1: number = givesANumber2(); +var ak2: string = givesANumber2();// Error: number ~> string +var NumberGenerator2 = require(\"ES6_Named2\").NumberGenerator2; +var al1: number = new NumberGenerator2().givesANumber(); +var al2: string = new NumberGenerator2().givesANumber();// Error: number ~> string +var varDeclNumber3 = require(\"ES6_Named2\").varDeclNumber3; +var varDeclNumber4 = require(\"ES6_Named2\").varDeclNumber4; +var am1: number = varDeclNumber3; +var am2: number = varDeclNumber4; +var am3: string = varDeclNumber3;// Error: number ~> string +var am4: string = varDeclNumber4;// Error: number ~> string +var numberValue6 = require(\"ES6_ExportFrom_Intermediary2\").numberValue1; +var ap1: number = numberValue6; +var ap2: string = numberValue6;// Error: number ~> string +var numberValue2_renamed2 = require( + \"ES6_ExportFrom_Intermediary2\" +).numberValue2_renamed2; +var aq1: number = numberValue2_renamed2; +var aq2: string = numberValue2_renamed2;// Error: number ~> string +var numberValue7 = require(\"ES6_ExportAllFrom_Intermediary2\").numberValue2; +var ar1: number = numberValue7; +var ar2: string = numberValue7;// Error: number ~> string +//////////////////////////////////////////////////////// +// == ES6 Default+Named -> ES6 import Default+Named== // +//////////////////////////////////////////////////////// +import defaultNum, { str as namedStr } from \"./ES6_DefaultAndNamed\"; +var as1: number = defaultNum; +var as2: string = defaultNum;// Error: number ~> string +var as3: string = namedStr; +var as4: number = namedStr;// Error: string ~> number +//////////////////////////////////////// +// == Side-effect only ES6 imports == // +//////////////////////////////////////// +import \"./SideEffects\"; +////////////////////////////////////////////// +// == Suggest export name on likely typo == // +////////////////////////////////////////////// +import specifierNumber1 from \"ES6_Named1\";// Error: Did you mean \`import {specifierNumber1} from ...\`? +import { specifierNumber } from \"ES6_Named1\";// Error: Did you mean \`specifierNumber1\`? +/////////////////////////////////////////////////// +// == Multi \`export *\` should combine exports == // +/////////////////////////////////////////////////// +import { numberValue1 as numberValue8, numberValue2 as numberValue9 } from \"./ES6_ExportAllFromMulti\"; +var at1: number = numberValue8; +var at2: string = numberValue8;// Error: number ~> string +var at3: number = numberValue9; +var at4: string = numberValue9;// Error: number ~> string + +" +`; diff --git a/tests/declare_export/es6modules.js b/tests/declare_export/es6modules.js new file mode 100644 index 000000000000..a6a52fe441cb --- /dev/null +++ b/tests/declare_export/es6modules.js @@ -0,0 +1,291 @@ +/* @flow */ + +// ===================== // +// == Path Resolution == // +// ===================== // + +// @providesModule +import * as DefaultA from "A"; +var a1: number = DefaultA.numberValue1; +var a2: string = DefaultA.numberValue1; // Error: number ~> string + +// File path +import * as DefaultB from "./B"; +var b1: number = DefaultB.numberValue; +var b2: string = DefaultB.numberValue; // Error: number ~> string + +// C.js exists, but not as a providesModule +import DefaultC from "C"; // Error: No such module + +// @providesModule D exists, but not as a filename +import DefaultD from "./D"; // Error: No such module + +// ================================================ // +// == CommonJS Clobbering Literal Exports -> ES6 == // +// ================================================ // + +import {doesntExist1} from "CommonJS_Clobbering_Lit"; // Error: Not an exported binding + +import {numberValue1} from "CommonJS_Clobbering_Lit"; +var c1: number = numberValue1; +var c2: string = numberValue1; // Error: number ~> string + +import {numberValue2 as numVal1} from "CommonJS_Clobbering_Lit"; +var d1: number = numVal1; +var d2: string = numVal1; // Error: number ~> string + +import CJS_Clobb_Lit from "CommonJS_Clobbering_Lit"; +var e1: number = CJS_Clobb_Lit.numberValue3; +var e2: string = CJS_Clobb_Lit.numberValue3; // Error: number ~> string +CJS_Clobb_Lit.doesntExist; // Error: doesntExist isn't a property + +import * as CJS_Clobb_Lit_NS from "CommonJS_Clobbering_Lit"; +var f1: number = CJS_Clobb_Lit_NS.numberValue4; +var f2: number = CJS_Clobb_Lit_NS.default.numberValue4; +CJS_Clobb_Lit_NS.default.default; // Error: No 'default' property on the exported obj +var f3: string = CJS_Clobb_Lit_NS.numberValue4; // Error: number ~> string +var f4: string = CJS_Clobb_Lit_NS.default.numberValue5; // Error: number ~> string + +// ============================================== // +// == CommonJS Clobbering Class Exports -> ES6 == // +// ============================================== // + +import {doesntExist2} from "CommonJS_Clobbering_Class"; // Error: Not an exported binding + +// The following import should error because class statics are not turned into +// named exports for now. This avoids complexities with polymorphic static +// members (where the polymophism is defined on the class itself rather than the +// method). +import {staticNumber1, baseProp, childProp} from "CommonJS_Clobbering_Class"; // Error + +import CJS_Clobb_Class from "CommonJS_Clobbering_Class"; +new CJS_Clobb_Class(); +new CJS_Clobb_Class().doesntExist; // Error: Class has no `doesntExist` property +var h1: number = CJS_Clobb_Class.staticNumber2(); +var h2: string = CJS_Clobb_Class.staticNumber2(); // Error: number ~> string +var h3: number = new CJS_Clobb_Class().instNumber1(); +var h4: string = new CJS_Clobb_Class().instNumber1(); // Error: number ~> string + +import * as CJS_Clobb_Class_NS from "CommonJS_Clobbering_Class"; +new CJS_Clobb_Class_NS(); // Error: Namespace object isn't constructable +var i1: number = CJS_Clobb_Class_NS.staticNumber3(); // Error: Class statics not copied to Namespace object +var i2: number = new CJS_Clobb_Class_NS.default().instNumber2(); +var i3: string = new CJS_Clobb_Class_NS.default().instNumber2(); // Error: number ~> string + +// =================================== // +// == CommonJS Named Exports -> ES6 == // +// =================================== // + +import {doesntExist3} from "CommonJS_Named"; // Error: Not an exported binding + +import {numberValue2} from "CommonJS_Named"; +var j1: number = numberValue2; +var j2: string = numberValue2; // Error: number ~> string + +import {numberValue3 as numVal3} from "CommonJS_Named"; +var k1: number = numVal3; +var k2: string = numVal3; // Error: number ~> string + +import * as CJS_Named from "CommonJS_Named"; +var l1: number = CJS_Named.numberValue1; +var l2: string = CJS_Named.numberValue1; // Error: number ~> string +CJS_Named.doesntExist; // Error: doesntExist isn't a property + +import * as CJS_Named_NS from "CommonJS_Named"; +var m1: number = CJS_Named_NS.numberValue4; +var m2: string = CJS_Named_NS.default.numberValue4; // Error: CommonJS_Named has no default export +var m3: string = CJS_Named_NS.numberValue4; // Error: number ~> string + +////////////////////////////// +// == ES6 Default -> ES6 == // +////////////////////////////// + +import {doesntExist4} from "ES6_Default_AnonFunction1"; // Error: Not an exported binding + +import ES6_Def_AnonFunc1 from "ES6_Default_AnonFunction1"; +var n1: number = ES6_Def_AnonFunc1(); +var n2: string = ES6_Def_AnonFunc1(); // Error: number ~> string + +import ES6_Def_NamedFunc1 from "ES6_Default_NamedFunction1"; +var o1: number = ES6_Def_NamedFunc1(); +var o2: string = ES6_Def_NamedFunc1(); // Error: number ~> string + + + + + +import ES6_Def_NamedClass1 from "ES6_Default_NamedClass1"; +var q1: number = new ES6_Def_NamedClass1().givesANum(); +var q2: string = new ES6_Def_NamedClass1().givesANum(); // Error: number ~> string + +//////////////////////////// +// == ES6 Named -> ES6 == // +//////////////////////////// + +import doesntExist5 from "ES6_Named1"; // Error: Not an exported binding + +import {specifierNumber1 as specifierNumber1_1} from "ES6_Named1"; +var r1: number = specifierNumber1_1; +var r2: string = specifierNumber1_1; // Error: number ~> string + +import {specifierNumber2Renamed} from "ES6_Named1"; +var s1: number = specifierNumber2Renamed; +var s2: string = specifierNumber2Renamed; // Error: number ~> string + +import {specifierNumber3 as specifierNumber3Renamed} from "ES6_Named1"; +var t1: number = specifierNumber3Renamed; +var t2: string = specifierNumber3Renamed; // Error: number ~> string + +import {groupedSpecifierNumber1, groupedSpecifierNumber2} from "ES6_Named1"; +var u1: number = groupedSpecifierNumber1; +var u2: number = groupedSpecifierNumber2; +var u3: string = groupedSpecifierNumber1; // Error: number ~> string +var u4: string = groupedSpecifierNumber2; // Error: number ~> string + +import {givesANumber} from "ES6_Named1"; +var v1: number = givesANumber(); +var v2: string = givesANumber(); // Error: number ~> string + +import {NumberGenerator} from "ES6_Named1"; +var w1: number = new NumberGenerator().givesANumber(); +var w2: string = new NumberGenerator().givesANumber(); // Error: number ~> string + +import {varDeclNumber1, varDeclNumber2} from "ES6_Named1"; +var x1: number = varDeclNumber1; +var x2: number = varDeclNumber2; +var x3: string = varDeclNumber1; // Error: number ~> string +var x4: string = varDeclNumber2; // Error: number ~> string + + + + + + + + + +import {numberValue1 as numberValue4} from "ES6_ExportFrom_Intermediary1"; +var aa1: number = numberValue4; +var aa2: string = numberValue4; // Error: number ~> string + +import {numberValue2_renamed} from "ES6_ExportFrom_Intermediary1"; +var ab1: number = numberValue2_renamed; +var ab2: string = numberValue2_renamed; // Error: number ~> string + +import {numberValue1 as numberValue5} from "ES6_ExportAllFrom_Intermediary1"; +var ac1: number = numberValue5; +var ac2: string = numberValue5; // Error: number ~> string + +/////////////////////////////////// +// == ES6 Default -> CommonJS == // +/////////////////////////////////// + +require('ES6_Default_AnonFunction2').doesntExist; // Error: 'doesntExist' isn't an export + +var ES6_Def_AnonFunc2 = require("ES6_Default_AnonFunction2").default; +var ad1: number = ES6_Def_AnonFunc2(); +var ad2: string = ES6_Def_AnonFunc2(); // Error: number ~> string + +var ES6_Def_NamedFunc2 = require("ES6_Default_NamedFunction2").default; +var ae1: number = ES6_Def_NamedFunc2(); +var ae2: string = ES6_Def_NamedFunc2(); // Error: number ~> string + + + + + +var ES6_Def_NamedClass2 = require("ES6_Default_NamedClass2").default; +var ag1: number = new ES6_Def_NamedClass2().givesANum(); +var ag2: string = new ES6_Def_NamedClass2().givesANum(); // Error: number ~> string + +///////////////////////////////// +// == ES6 Named -> CommonJS == // +///////////////////////////////// + +var specifierNumber4 = require("ES6_Named2").specifierNumber4; +var ah1: number = specifierNumber4; +var ah2: string = specifierNumber4; // Error: number ~> string + +var specifierNumber5Renamed = require("ES6_Named2").specifierNumber5Renamed; +var ai1: number = specifierNumber5Renamed; +var ai2: string = specifierNumber5Renamed; // Error: number ~> string + +var groupedSpecifierNumber3 = require("ES6_Named2").groupedSpecifierNumber3; +var groupedSpecifierNumber4 = require("ES6_Named2").groupedSpecifierNumber4; +var aj1: number = groupedSpecifierNumber3; +var aj2: number = groupedSpecifierNumber4; +var aj3: string = groupedSpecifierNumber3; // Error: number ~> string +var aj4: string = groupedSpecifierNumber4; // Error: number ~> string + +var givesANumber2 = require("ES6_Named2").givesANumber2; +var ak1: number = givesANumber2(); +var ak2: string = givesANumber2(); // Error: number ~> string + +var NumberGenerator2 = require("ES6_Named2").NumberGenerator2; +var al1: number = new NumberGenerator2().givesANumber(); +var al2: string = new NumberGenerator2().givesANumber(); // Error: number ~> string + +var varDeclNumber3 = require("ES6_Named2").varDeclNumber3; +var varDeclNumber4 = require("ES6_Named2").varDeclNumber4; +var am1: number = varDeclNumber3; +var am2: number = varDeclNumber4; +var am3: string = varDeclNumber3; // Error: number ~> string +var am4: string = varDeclNumber4; // Error: number ~> string + + + + + + + + + +var numberValue6 = require("ES6_ExportFrom_Intermediary2").numberValue1; +var ap1: number = numberValue6; +var ap2: string = numberValue6; // Error: number ~> string + +var numberValue2_renamed2 = require("ES6_ExportFrom_Intermediary2").numberValue2_renamed2; +var aq1: number = numberValue2_renamed2; +var aq2: string = numberValue2_renamed2; // Error: number ~> string + +var numberValue7 = require("ES6_ExportAllFrom_Intermediary2").numberValue2; +var ar1: number = numberValue7; +var ar2: string = numberValue7; // Error: number ~> string + +//////////////////////////////////////////////////////// +// == ES6 Default+Named -> ES6 import Default+Named== // +//////////////////////////////////////////////////////// + +import defaultNum, {str as namedStr} from "./ES6_DefaultAndNamed"; + +var as1: number = defaultNum; +var as2: string = defaultNum; // Error: number ~> string + +var as3: string = namedStr; +var as4: number = namedStr; // Error: string ~> number + +//////////////////////////////////////// +// == Side-effect only ES6 imports == // +//////////////////////////////////////// + +import "./SideEffects"; + +////////////////////////////////////////////// +// == Suggest export name on likely typo == // +////////////////////////////////////////////// +import specifierNumber1 from "ES6_Named1"; // Error: Did you mean `import {specifierNumber1} from ...`? +import {specifierNumber} from "ES6_Named1"; // Error: Did you mean `specifierNumber1`? + +/////////////////////////////////////////////////// +// == Multi `export *` should combine exports == // +/////////////////////////////////////////////////// +import { + numberValue1 as numberValue8, + numberValue2 as numberValue9 +} from "./ES6_ExportAllFromMulti"; + +var at1: number = numberValue8; +var at2: string = numberValue8; // Error: number ~> string + +var at3: number = numberValue9; +var at4: string = numberValue9; // Error: number ~> string diff --git a/tests/declare_export/jsfmt.spec.js b/tests/declare_export/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_export/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_fun/__snapshots__/jsfmt.spec.js.snap b/tests/declare_fun/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1d896985749f --- /dev/null +++ b/tests/declare_fun/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test test.js 1`] = ` +"declare function foo(x: number): string; +declare function foo(x: string): number; +declare function foo(x: X): X; + +(foo(0): string); // OK +(foo(\"hello\"): number); // OK +(foo(false): void); // error, boolean ~/~ undefined +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/declare_fun/jsfmt.spec.js b/tests/declare_fun/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_fun/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_fun/test.js b/tests/declare_fun/test.js new file mode 100644 index 000000000000..db8a37324764 --- /dev/null +++ b/tests/declare_fun/test.js @@ -0,0 +1,7 @@ +declare function foo(x: number): string; +declare function foo(x: string): number; +declare function foo(x: X): X; + +(foo(0): string); // OK +(foo("hello"): number); // OK +(foo(false): void); // error, boolean ~/~ undefined diff --git a/tests/declare_module_exports/__snapshots__/jsfmt.spec.js.snap b/tests/declare_module_exports/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fd7fb86fc55f --- /dev/null +++ b/tests/declare_module_exports/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,49 @@ +exports[`test main.js 1`] = ` +"// @flow + +import declare_module_exports from "declare_module_exports"; +(declare_module_exports: number); +(declare_module_exports: string); // Error: number ~> string + +// Error: Has no named export "str"! +import {str} from "declare_m_e_with_other_value_declares"; + +import type {str2} from "declare_m_e_with_other_type_declares"; +("asdf": str2); +(42: str2); // Error: number ~> string + +/** + * \`declare var exports\` is deprecated, so we have a grace period where both + * syntaxes will work. + */ + +import DEPRECATED__declare_var_exports from "DEPRECATED__declare_var_exports"; +(DEPRECATED__declare_var_exports: number); +(DEPRECATED__declare_var_exports: string); // Error: number ~> string + +import declare_m_e_with_declare_var_e from "declare_m_e_with_declare_var_e"; +(declare_m_e_with_declare_var_e: number); +(declare_m_e_with_declare_var_e: string); // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import declare_module_exports from "declare_module_exports"; +(declare_module_exports: number); +(declare_module_exports: string);// Error: number ~> string +// Error: Has no named export "str"! +import { str } from "declare_m_e_with_other_value_declares"; +import type { str2 } from "declare_m_e_with_other_type_declares"; +("asdf": str2); +(42: str2);// Error: number ~> string +/** + * \`declare var exports\` is deprecated, so we have a grace period where both + * syntaxes will work. + */ +import DEPRECATED__declare_var_exports from "DEPRECATED__declare_var_exports"; +(DEPRECATED__declare_var_exports: number); +(DEPRECATED__declare_var_exports: string);// Error: number ~> string +import declare_m_e_with_declare_var_e from "declare_m_e_with_declare_var_e"; +(declare_m_e_with_declare_var_e: number); +(declare_m_e_with_declare_var_e: string);// Error: number ~> string + +" +`; diff --git a/tests/declare_module_exports/flow-typed/__snapshots__/jsfmt.spec.js.snap b/tests/declare_module_exports/flow-typed/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..610dfff48baf --- /dev/null +++ b/tests/declare_module_exports/flow-typed/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,60 @@ +exports[`test libs.js 1`] = ` +"declare module "declare_module_exports" { + declare module.exports: number; +} + +declare module "declare_m_e_with_other_value_declares" { + declare module.exports: number; + declare var str: string; +} + +declare module "declare_m_e_with_other_type_declares" { + declare module.exports: number; + declare type str2 = string; +} + +/** + * \`declare var exports\` is deprecated, so we have a grace period where both + * syntaxes will work. + */ + +declare module "DEPRECATED__declare_var_exports" { + declare var exports: number; +} + +/** + * Ensure that, if both are present, \`declare module.exports\` wins + */ +declare module "declare_m_e_with_declare_var_e" { + declare module.exports: number; + declare var exports: string; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare module "declare_module_exports" { + declare module.exports: number +} +declare module "declare_m_e_with_other_value_declares" { + declare module.exports: number + declare var str: string; +} +declare module "declare_m_e_with_other_type_declares" { + declare module.exports: number + type str2 = string; +} +/** + * \`declare var exports\` is deprecated, so we have a grace period where both + * syntaxes will work. + */ +declare module "DEPRECATED__declare_var_exports" { + declare var exports: number; +} +/** + * Ensure that, if both are present, \`declare module.exports\` wins + */ +declare module "declare_m_e_with_declare_var_e" { + declare module.exports: number + declare var exports: string; +} + +" +`; diff --git a/tests/declare_module_exports/flow-typed/jsfmt.spec.js b/tests/declare_module_exports/flow-typed/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_module_exports/flow-typed/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_module_exports/flow-typed/libs.js b/tests/declare_module_exports/flow-typed/libs.js new file mode 100644 index 000000000000..25ee31b0a922 --- /dev/null +++ b/tests/declare_module_exports/flow-typed/libs.js @@ -0,0 +1,30 @@ +declare module "declare_module_exports" { + declare module.exports: number; +} + +declare module "declare_m_e_with_other_value_declares" { + declare module.exports: number; + declare var str: string; +} + +declare module "declare_m_e_with_other_type_declares" { + declare module.exports: number; + declare type str2 = string; +} + +/** + * `declare var exports` is deprecated, so we have a grace period where both + * syntaxes will work. + */ + +declare module "DEPRECATED__declare_var_exports" { + declare var exports: number; +} + +/** + * Ensure that, if both are present, `declare module.exports` wins + */ +declare module "declare_m_e_with_declare_var_e" { + declare module.exports: number; + declare var exports: string; +} diff --git a/tests/declare_module_exports/jsfmt.spec.js b/tests/declare_module_exports/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_module_exports/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_module_exports/main.js b/tests/declare_module_exports/main.js new file mode 100644 index 000000000000..7c9cce2c344d --- /dev/null +++ b/tests/declare_module_exports/main.js @@ -0,0 +1,25 @@ +// @flow + +import declare_module_exports from "declare_module_exports"; +(declare_module_exports: number); +(declare_module_exports: string); // Error: number ~> string + +// Error: Has no named export "str"! +import {str} from "declare_m_e_with_other_value_declares"; + +import type {str2} from "declare_m_e_with_other_type_declares"; +("asdf": str2); +(42: str2); // Error: number ~> string + +/** + * `declare var exports` is deprecated, so we have a grace period where both + * syntaxes will work. + */ + +import DEPRECATED__declare_var_exports from "DEPRECATED__declare_var_exports"; +(DEPRECATED__declare_var_exports: number); +(DEPRECATED__declare_var_exports: string); // Error: number ~> string + +import declare_m_e_with_declare_var_e from "declare_m_e_with_declare_var_e"; +(declare_m_e_with_declare_var_e: number); +(declare_m_e_with_declare_var_e: string); // Error: number ~> string diff --git a/tests/declare_type/__snapshots__/jsfmt.spec.js.snap b/tests/declare_type/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..70ade6b61551 --- /dev/null +++ b/tests/declare_type/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,49 @@ +exports[`test import_declare_type.js 1`] = ` +"/** + * @flow + */ + +//////////////////////////////////////////////////////////// +// == Import Declared Type Alias From Declared Module == // +////////////////////////////////////////////////////////// +import type {baz} from \"ModuleAliasFoo\"; +import {foo} from \"ModuleAliasFoo\"; +var k1: baz = 42; +var k2: baz = \"shab\"; // Error: string to int +var k3: toz = foo(k1); // works + +import type {toz} from \"ModuleAliasFoo\"; +var k4: toz = foo(k1); // works + +////////////////////////////////////////////////////////// +// == Declared Module with exports prop (issue 880) == // +//////////////////////////////////////////////////////// + +import blah from \'foo\'; +import type { Foo, Bar, Id } from \'foo\'; + +blah(0, 0); + +({toz:3} : Foo); // error : {toz : number} ~> string + +(3 : Bar); // error : number ~> A + +(\"lol\" : Id); // error : string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/declare_type/import_declare_type.js b/tests/declare_type/import_declare_type.js new file mode 100644 index 000000000000..3cd90be747b0 --- /dev/null +++ b/tests/declare_type/import_declare_type.js @@ -0,0 +1,30 @@ +/** + * @flow + */ + +//////////////////////////////////////////////////////////// +// == Import Declared Type Alias From Declared Module == // +////////////////////////////////////////////////////////// +import type {baz} from "ModuleAliasFoo"; +import {foo} from "ModuleAliasFoo"; +var k1: baz = 42; +var k2: baz = "shab"; // Error: string to int +var k3: toz = foo(k1); // works + +import type {toz} from "ModuleAliasFoo"; +var k4: toz = foo(k1); // works + +////////////////////////////////////////////////////////// +// == Declared Module with exports prop (issue 880) == // +//////////////////////////////////////////////////////// + +import blah from 'foo'; +import type { Foo, Bar, Id } from 'foo'; + +blah(0, 0); + +({toz:3} : Foo); // error : {toz : number} ~> string + +(3 : Bar); // error : number ~> A + +("lol" : Id); // error : string ~> number diff --git a/tests/declare_type/jsfmt.spec.js b/tests/declare_type/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_type/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/declare_type/lib/DeclareModule_TypeAlias.js b/tests/declare_type/lib/DeclareModule_TypeAlias.js new file mode 100644 index 000000000000..325d344de110 --- /dev/null +++ b/tests/declare_type/lib/DeclareModule_TypeAlias.js @@ -0,0 +1,9 @@ +/** + * @flow + */ + +declare module ModuleAliasFoo { + declare type baz = number; + declare type toz = string; + declare function foo(bar : baz) : toz; +} diff --git a/tests/declare_type/lib/__snapshots__/jsfmt.spec.js.snap b/tests/declare_type/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ae6ef708d866 --- /dev/null +++ b/tests/declare_type/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,65 @@ +exports[`test DeclareModule_TypeAlias.js 1`] = ` +"/** + * @flow + */ + +declare module ModuleAliasFoo { + declare type baz = number; + declare type toz = string; + declare function foo(bar : baz) : toz; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test declare_type_exports.js 1`] = ` +"/* @flow */ + +declare module \'foo\' { + declare class A { + toz : number + } + + declare var n : string; + + declare type Foo = typeof n; + declare type Bar = A; + declare type Id = T; + + declare var exports : { + (a : number, b : number) : number + }; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/declare_type/lib/declare_type_exports.js b/tests/declare_type/lib/declare_type_exports.js new file mode 100644 index 000000000000..dac1a6bd9a92 --- /dev/null +++ b/tests/declare_type/lib/declare_type_exports.js @@ -0,0 +1,17 @@ +/* @flow */ + +declare module 'foo' { + declare class A { + toz : number + } + + declare var n : string; + + declare type Foo = typeof n; + declare type Bar = A; + declare type Id = T; + + declare var exports : { + (a : number, b : number) : number + }; +} diff --git a/tests/declare_type/lib/jsfmt.spec.js b/tests/declare_type/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/declare_type/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/def_site_variance/__snapshots__/jsfmt.spec.js.snap b/tests/def_site_variance/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..cd46d9b9ba9b --- /dev/null +++ b/tests/def_site_variance/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,50 @@ +exports[`test test.js 1`] = ` +"class Variance<+Out,-In> { + foo(x: Out): Out { return x; } + bar(y: In): In { return y; } +} + +class A { } +class B extends A { } + +function subtyping( + v1: Variance, + v2: Variance +) { + (v1: Variance); // error on both targs (A ~/~> B) + (v2: Variance); // OK for both targs (B ~> A) +} + +class PropVariance<+Out,-In> { + inv1: Out; // error + inv2: In; // error + -co1: Out; // error + -co2: In; // ok + +con1: Out; // ok + +con2: In; // error + + inv_dict1: {[k:string]: Out}; // error + inv_dict2: {[k:string]: In}; // error + co_dict1: {+[k:string]: Out}; // ok + co_dict2: {+[k:string]: In}; // error + con_dict1: {-[k:string]: Out}; // error + con_dict2: {-[k:string]: In}; // ok +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/def_site_variance/jsfmt.spec.js b/tests/def_site_variance/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/def_site_variance/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/def_site_variance/test.js b/tests/def_site_variance/test.js new file mode 100644 index 000000000000..72f756eeaa21 --- /dev/null +++ b/tests/def_site_variance/test.js @@ -0,0 +1,31 @@ +class Variance<+Out,-In> { + foo(x: Out): Out { return x; } + bar(y: In): In { return y; } +} + +class A { } +class B extends A { } + +function subtyping( + v1: Variance, + v2: Variance +) { + (v1: Variance); // error on both targs (A ~/~> B) + (v2: Variance); // OK for both targs (B ~> A) +} + +class PropVariance<+Out,-In> { + inv1: Out; // error + inv2: In; // error + -co1: Out; // error + -co2: In; // ok + +con1: Out; // ok + +con2: In; // error + + inv_dict1: {[k:string]: Out}; // error + inv_dict2: {[k:string]: In}; // error + co_dict1: {+[k:string]: Out}; // ok + co_dict2: {+[k:string]: In}; // error + con_dict1: {-[k:string]: Out}; // error + con_dict2: {-[k:string]: In}; // ok +} diff --git a/tests/demo/1/__snapshots__/jsfmt.spec.js.snap b/tests/demo/1/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6a6eab1a73fe --- /dev/null +++ b/tests/demo/1/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +exports[`test f.js 1`] = ` +"/* demo */ + +function f(x) { return 42/x; } + +var x = null; +//... + +f(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* demo */ +function f(x) { + return 42 / x; +} +var x = null; +//... +f(x); + +" +`; diff --git a/tests/demo/1/f.js b/tests/demo/1/f.js new file mode 100644 index 000000000000..fd73a91e9cc9 --- /dev/null +++ b/tests/demo/1/f.js @@ -0,0 +1,8 @@ +/* demo */ + +function f(x) { return 42/x; } + +var x = null; +//... + +f(x); diff --git a/tests/demo/1/jsfmt.spec.js b/tests/demo/1/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/demo/1/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/demo/2/A.js b/tests/demo/2/A.js new file mode 100644 index 000000000000..b0281e07e714 --- /dev/null +++ b/tests/demo/2/A.js @@ -0,0 +1,19 @@ +/* @providesModule Demo */ + +class A { + x: number; // instance field declaration + constructor(x) { this.x = x; } + + getX() { return this.x; } + + onLoad(callback) { + return callback(this.getX()); + } +} + +function callback(x: string) { return x.length; } + +var a = new A(42); +a.onLoad(callback); + +module.exports = A; diff --git a/tests/demo/2/B.js b/tests/demo/2/B.js new file mode 100644 index 000000000000..4c44780b9e90 --- /dev/null +++ b/tests/demo/2/B.js @@ -0,0 +1,3 @@ +var A = require('Demo'); + +var z = new A("42").getX(); diff --git a/tests/demo/2/__snapshots__/jsfmt.spec.js.snap b/tests/demo/2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..faf41ca9a6bd --- /dev/null +++ b/tests/demo/2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,54 @@ +exports[`test A.js 1`] = ` +"/* @providesModule Demo */ + +class A { + x: number; // instance field declaration + constructor(x) { this.x = x; } + + getX() { return this.x; } + + onLoad(callback) { + return callback(this.getX()); + } +} + +function callback(x: string) { return x.length; } + +var a = new A(42); +a.onLoad(callback); + +module.exports = A; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Demo */ +class A { + x: number;// instance field declaration + constructor(x) { + this.x = x; + } + getX() { + return this.x; + } + onLoad(callback) { + return callback(this.getX()); + } +} +function callback(x: string) { + return x.length; +} +var a = new A(42); +a.onLoad(callback); +module.exports = A; + +" +`; + +exports[`test B.js 1`] = ` +"var A = require('Demo'); + +var z = new A("42").getX(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var A = require("Demo"); +var z = new A("42").getX(); + +" +`; diff --git a/tests/demo/2/jsfmt.spec.js b/tests/demo/2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/demo/2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/deps/A.js b/tests/deps/A.js new file mode 100644 index 000000000000..5a8c55d5bf63 --- /dev/null +++ b/tests/deps/A.js @@ -0,0 +1 @@ +require('./C'); diff --git a/tests/deps/B.js b/tests/deps/B.js new file mode 100644 index 000000000000..5a8c55d5bf63 --- /dev/null +++ b/tests/deps/B.js @@ -0,0 +1 @@ +require('./C'); diff --git a/tests/deps/C.js b/tests/deps/C.js new file mode 100644 index 000000000000..a006ecb7fb7d --- /dev/null +++ b/tests/deps/C.js @@ -0,0 +1,4 @@ +require('./D'); +require('./E'); +require('./F'); +require('./G'); diff --git a/tests/deps/D.js b/tests/deps/D.js new file mode 100644 index 000000000000..c5dbbb7bc2e4 --- /dev/null +++ b/tests/deps/D.js @@ -0,0 +1 @@ +require('./I'); diff --git a/tests/deps/E.js b/tests/deps/E.js new file mode 100644 index 000000000000..c5dbbb7bc2e4 --- /dev/null +++ b/tests/deps/E.js @@ -0,0 +1 @@ +require('./I'); diff --git a/tests/deps/F.js b/tests/deps/F.js new file mode 100644 index 000000000000..8b1a393741c9 --- /dev/null +++ b/tests/deps/F.js @@ -0,0 +1 @@ +// empty diff --git a/tests/deps/G.js b/tests/deps/G.js new file mode 100644 index 000000000000..4c21ad55c16d --- /dev/null +++ b/tests/deps/G.js @@ -0,0 +1 @@ +require('./H'); diff --git a/tests/deps/H.js b/tests/deps/H.js new file mode 100644 index 000000000000..8b1a393741c9 --- /dev/null +++ b/tests/deps/H.js @@ -0,0 +1 @@ +// empty diff --git a/tests/deps/I.js b/tests/deps/I.js new file mode 100644 index 000000000000..39ab86c96453 --- /dev/null +++ b/tests/deps/I.js @@ -0,0 +1 @@ +require('./A'); diff --git a/tests/deps/__snapshots__/jsfmt.spec.js.snap b/tests/deps/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d5665196b01d --- /dev/null +++ b/tests/deps/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,77 @@ +exports[`test A.js 1`] = ` +"require('./C'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./C"); + +" +`; + +exports[`test B.js 1`] = ` +"require('./C'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./C"); + +" +`; + +exports[`test C.js 1`] = ` +"require('./D'); +require('./E'); +require('./F'); +require('./G'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./D"); +require("./E"); +require("./F"); +require("./G"); + +" +`; + +exports[`test D.js 1`] = ` +"require('./I'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./I"); + +" +`; + +exports[`test E.js 1`] = ` +"require('./I'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./I"); + +" +`; + +exports[`test F.js 1`] = ` +"// empty +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test G.js 1`] = ` +"require('./H'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./H"); + +" +`; + +exports[`test H.js 1`] = ` +"// empty +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test I.js 1`] = ` +"require('./A'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +require("./A"); + +" +`; diff --git a/tests/deps/jsfmt.spec.js b/tests/deps/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/deps/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/destructuring/__snapshots__/jsfmt.spec.js.snap b/tests/destructuring/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..874ac970940b --- /dev/null +++ b/tests/destructuring/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,480 @@ +exports[`test array_rest.js 1`] = ` +"let xs = [0, \"\", true]; +let [a, ...ys] = xs; +let [b, ...zs] = ys; +let c = zs[0]; // retain tuple info +let d = zs[1]; // run off the end + +(a: void); // error: number ~> void +(b: void); // error: string ~> void +(c: void); // error: boolean ~> void +(d: void); // error: number|string|boolean ~> void + +let [...e] = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +let xs = [ 0, \"\", true ]; +let [ a, ...ys ] = xs; +let [ b, ...zs ] = ys; +let c = zs[0];// retain tuple info +let d = zs[1];// run off the end +(a: void);// error: number ~> void +(b: void);// error: string ~> void +(c: void);// error: boolean ~> void +(d: void);// error: number|string|boolean ~> void +let [ ...e ] = 0; + +" +`; + +exports[`test computed.js 1`] = ` +"var { [\"key\"]: val1 } = { key: \"val\" }; +(val1: void); // error: string ~> void + +var key: string = \"key\"; +var { [key]: val2 } = { key: \"val\" }; +(val2: void); // ok (gasp!) by existing StrT -> ElemT rule + +var { [\"key\"]: val3, ...spread } = { key: \"val\" }; +(spread.key: void); // error (gasp!) in general we don\'t know if a computed prop should be excluded from spread +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var { [\"key\"]: val1 } = { key: \"val\" }; +(val1: void);// error: string ~> void +var key: string = \"key\"; +var { [key]: val2 } = { key: \"val\" }; +(val2: void);// ok (gasp!) by existing StrT -> ElemT rule +var { [\"key\"]: val3, ...spread } = { key: \"val\" }; +(spread.key: void);// error (gasp!) in general we don\'t know if a computed prop should be excluded from spread + +" +`; + +exports[`test defaults.js 1`] = ` +"/* @flow */ + +function obj_prop_fun({p:{q=0}={q:true}}={p:{q:\"\"}}) { + // errors: + // * number ~> void, from default on _.p.q + // * boolean ~> void, from default on _.p + // * string ~> void, from default on _ + // * null ~> void, from call below + (q:void); +} +obj_prop_fun(); // ok +obj_prop_fun({}); // ok +obj_prop_fun({p:{}}); // ok +obj_prop_fun({p:{q:null}}); // ok, provides add\'l lower bound + +function obj_prop_var(o={p:{q:\"\"}}) { + var {p:{q=0}={q:true}} = o; + // errors: + // * number ~> void, from default on o.p.q + // * boolean ~> void, from default on o.p + // * string ~> void, from default on o + // * null ~> void, from call below + (q:void); +} +obj_prop_var(); // ok +obj_prop_var({}); // ok +obj_prop_var({p:{}}); // ok +obj_prop_var({p:{q:null}}); // ok, provides add\'l lower bound + +function obj_rest({p:{q,...o}={q:0,r:0}}={p:{q:0,r:\"\"}}) { + // errors: + // * number ~> void, from default on _.p + // * string ~> void, from default on _ + // * null ~> void, from call below + (o.r:void); +} +obj_rest(); // ok +obj_rest({}); // ok +obj_rest({p:{}}); // ok +obj_rest({p:{q:0,r:null}}); + +function obj_prop_annot({ + p = true // error: boolean ~> string +}: { + p: string +} = { + p: 0 // error: number ~> string +}) { + (p:void); // error: string ~> void +} + +var { + p = true // error: boolean ~> string +}: { + p: string +} = { + p: 0 // error: number ~> string +}; +(p:void); // error: string ~> void + +function obj_prop_err({x:{y}}=null) {} // error: property \`x\` cannot be accessed on null +function obj_rest_err({...o}=0) {} // error: expected object instead of number +function arr_elem_err([x]=null) {} // error: element 0 cannot be accessed on null +function arr_rest_err([...a]=null) {} // error: expected array instead of null + +function gen(x:T,{p=x}:{p:T}):T { + return p; +} + +// Default values in destructuring unwrap optional types +obj_prop_fun(({} : {p?:{q?:null}})); // ok +obj_prop_var(({} : {p?:{q?:null}})); // ok + +// union-like upper bounds preserved through destructuring +function obj_prop_opt({p}:{p?:string}={p:0}) {} +function obj_prop_maybe({p}:{p:?string}={p:0}) {} +function obj_prop_union({p}:{p:number|string}={p:true}) {} + +// TODO: union-of-objects upper bounds preserved through destructuring +function obj_prop_union2({p}:{p:number}|{p:string}={p:true}) {} + +function default_expr_scope({a, b = a}) {} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test destructuring.js 1`] = ` +"declare var a:string; +declare var b:string; +declare var c:string; +[{a1:a, b},c] = [{a1:0, b:1},2]; + +var {m} = {m:0}; +({m} = {m:m}); + +var obj; +({n: obj.x} = {n:3}); +[obj.x] = [\'foo\']; + +function foo({p, z:[r]}) { + a = p; + b = z; + c = r; +} +foo({p:0, z:[1,2]}); + +[a,,b,...c] = [0,1,true,3]; + +function bar({x, ...z}) { + var o:{x: string; y: number;} = z; +} +bar({x:\"\",y:0}); + +var spread = {y:\"\"}; +var extend: {x:number; y:string; z: boolean} = {x:0, ...spread}; + +function qux(_: {a:number}) { } +qux({a:\"\"}); +function corge({b}: {b:string}) { } +corge({b:0}); + +var {n}:{n: number} = {n: \"\"} + +function test() { + var {foo} = {bar: 123}; // error on foo + var {bar, baz} = {bar: 123} // error on baz +} + +function test() { + var x = {foo: \'abc\', bar: 123}; + var {foo, ...rest} = x; + (x.baz: string); // error, baz doesn\'t exist + (rest.baz: string); // no error, rest is unsealed +} + +module.exports = corge; + +class Base { + baseprop1: number; + baseprop2: number; +} + +class Child extends Base { + childprop1: number; + childprop2: number; +} + +var {baseprop1, childprop1, ...others} = new Child(); + +var bp1: number = baseprop1; +var bp1_err: string = baseprop1; // Error: number ~> string +var bp2: number = others.baseprop2; +var bp2_err: string = others.baseprop2; // Error: number ~> string + +var cp1: number = childprop1; +var cp1_err: string = childprop1; // Error: number ~> string +var cp2: number = others.childprop1; +var cp2_err: string = others.childprop2; // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare var a: string; +declare var b: string; +declare var c: string; +[ { a1: a, b }, c ] = [ { a1: 0, b: 1 }, 2 ]; +var { m } = { m: 0 }; +{ m } = { m: m }; +var obj; +{ n: obj.x } = { n: 3 }; +[ obj.x ] = [ \"foo\" ]; +function foo({ p, z: [ r ] }) { + a = p; + b = z; + c = r; +} +foo({ p: 0, z: [ 1, 2 ] }); +[ a, , b, ...c ] = [ 0, 1, true, 3 ]; +function bar({ x, ...z }) { + var o: { x: string, y: number } = z; +} +bar({ x: \"\", y: 0 }); +var spread = { y: \"\" }; +var extend: { x: number, y: string, z: boolean } = { x: 0, ...spread }; +function qux(_: { a: number }) { + +} +qux({ a: \"\" }); +function corge({ b }) { + +} +corge({ b: 0 }); +var { n } = { n: \"\" }; +function test() { + var { foo } = { bar: 123 };// error on foo + var { bar, baz } = { bar: 123 };// error on baz +} +function test() { + var x = { foo: \"abc\", bar: 123 }; + var { foo, ...rest } = x; + (x.baz: string);// error, baz doesn\'t exist + (rest.baz: string);// no error, rest is unsealed +} +module.exports = corge; +class Base { + baseprop1: number; + baseprop2: number; +} +class Child extends Base { + childprop1: number; + childprop2: number; +} +var { baseprop1, childprop1, ...others } = new Child(); +var bp1: number = baseprop1; +var bp1_err: string = baseprop1;// Error: number ~> string +var bp2: number = others.baseprop2; +var bp2_err: string = others.baseprop2;// Error: number ~> string +var cp1: number = childprop1; +var cp1_err: string = childprop1;// Error: number ~> string +var cp2: number = others.childprop1; +var cp2_err: string = others.childprop2;// Error: number ~> string + +" +`; + +exports[`test destructuring_init.js 1`] = ` +"var {foo}; +var [bar]; +var []; +var {}; +var [], {toz}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Complex binding patterns require an initialization value (1:9) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$1.parseVar (/node_modules/babylon/lib/index.js:2215:12) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2042:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) + at Object.parse (/index.js:34:26) +" +`; + +exports[`test destructuring_param.js 1`] = ` +"function f(a, { b }) { + return a + b; +} + +function g(a, { a }) { + return a; +} + +function h({ a, { b } }, { c }, { { d } }) { + return a + b + c + d; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Argument name clash in strict mode (5:16) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$2.checkLVal (/node_modules/babylon/lib/index.js:3007:16) + at Parser.checkLVal (/node_modules/babylon/lib/index.js:5446:22) + at Parser.pp$2.checkLVal (/node_modules/babylon/lib/index.js:3034:14) + at Parser.checkLVal (/node_modules/babylon/lib/index.js:5446:22) + at Parser.pp$3.parseFunctionBody (/node_modules/babylon/lib/index.js:4072:12) + at Parser.parseFunctionBody (/node_modules/babylon/lib/index.js:5211:20) + at Parser.pp$1.parseFunction (/node_modules/babylon/lib/index.js:2257:8) + at Parser.pp$1.parseFunctionStatement (/node_modules/babylon/lib/index.js:1926:15) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1712:19) +" +`; + +exports[`test eager.js 1`] = ` +"var x; +({x} = null); // error, property \`x\` can not be accessed on \`null\` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x; +{ x } = null;// error, property \`x\` can not be accessed on \`null\` + +" +`; + +exports[`test poly.js 1`] = ` +"// @flow + +function obj_pattern({ prop } : { prop: X }) {} // prop: X +type Prop = { prop: X }; +function obj_pattern2({ prop } : Prop) {} // prop: X + +function arr_pattern([ elem ] : X[]) {} // elem: X +type Elem = X[]; +function arr_pattern2([ elem ] : Elem) {} // elem: X + +function tup_pattern([ proj ] : [X]) {} // proj: X +type Proj = [X]; +function tup_pattern2([ proj ] : Proj) {} // proj: X + +function rest_antipattern(...t: T) {} // nonsense +function rest_pattern(...r: X[]) {} // r: X[] + +function obj_rest_pattern({ _, ...o } : { _: any, x: X }) { // o: { x: X } + o.x; +} +type ObjRest = { _: any, x: X }; +function obj_rest_pattern({ _, ...o } : ObjRest) { // o: { x: X } + o.x; +} + +function arr_rest_pattern([ _, ...a ] : [ any, X ]) { // a: [X] + a[0]; +} +type ArrRest = [ any, X ]; +function arr_rest_pattern([ _, ...a ] : ArrRest) { // a: [X] + a[0]; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test rec.js 1`] = ` +"// @flow + +// Make sure that destructuring doesn\'t cause infinite loops when combined with +// funny doses of repositioning + +let foo = (i: number) => [i]; + +const bar = (i: number) => { + [i] = foo(i); + return [i]; +}; + +foo = (i: number) => { + return bar(i); +}; + +// Also make sure that the following doesn\'t loop + +declare var o; +var { x: o } = o; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// Make sure that destructuring doesn\'t cause infinite loops when combined with +// funny doses of repositioning +let foo = (i: number) => [ i ]; +const bar = (i: number) => { + [ i ] = foo(i); + return [ i ]; +}; +foo = (i: number) => { + return bar(i); +}; +// Also make sure that the following doesn\'t loop +declare var o; +var { x: o } = o; + +" +`; + +exports[`test string_lit.js 1`] = ` +"var { \"key\": val } = { key: \"val\" }; +(val: void); // error: string ~> void + +var { \"with-dash\": with_dash } = { \"with-dash\": \"motivating example\" }; +(with_dash: \"motivating example\"); // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var { \"key\": val } = { key: \"val\" }; +(val: void);// error: string ~> void +var { \"with-dash\": with_dash } = { \"with-dash\": \"motivating example\" }; +(with_dash: \"motivating example\");// ok + +" +`; + +exports[`test unannotated.js 1`] = ` +"// @flow + +var { x } = { + x: { foo: \"foo\" } +}; + +function bar() { + x.bar +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var { x } = { x: { foo: \"foo\" } }; +function bar() { + x.bar; +} + +" +`; diff --git a/tests/destructuring/array_rest.js b/tests/destructuring/array_rest.js new file mode 100644 index 000000000000..df9c2364fef7 --- /dev/null +++ b/tests/destructuring/array_rest.js @@ -0,0 +1,12 @@ +let xs = [0, "", true]; +let [a, ...ys] = xs; +let [b, ...zs] = ys; +let c = zs[0]; // retain tuple info +let d = zs[1]; // run off the end + +(a: void); // error: number ~> void +(b: void); // error: string ~> void +(c: void); // error: boolean ~> void +(d: void); // error: number|string|boolean ~> void + +let [...e] = 0; diff --git a/tests/destructuring/computed.js b/tests/destructuring/computed.js new file mode 100644 index 000000000000..5f5f2d241152 --- /dev/null +++ b/tests/destructuring/computed.js @@ -0,0 +1,9 @@ +var { ["key"]: val1 } = { key: "val" }; +(val1: void); // error: string ~> void + +var key: string = "key"; +var { [key]: val2 } = { key: "val" }; +(val2: void); // ok (gasp!) by existing StrT -> ElemT rule + +var { ["key"]: val3, ...spread } = { key: "val" }; +(spread.key: void); // error (gasp!) in general we don't know if a computed prop should be excluded from spread diff --git a/tests/destructuring/defaults.js b/tests/destructuring/defaults.js new file mode 100644 index 000000000000..0c5fcfb358bc --- /dev/null +++ b/tests/destructuring/defaults.js @@ -0,0 +1,82 @@ +/* @flow */ + +function obj_prop_fun({p:{q=0}={q:true}}={p:{q:""}}) { + // errors: + // * number ~> void, from default on _.p.q + // * boolean ~> void, from default on _.p + // * string ~> void, from default on _ + // * null ~> void, from call below + (q:void); +} +obj_prop_fun(); // ok +obj_prop_fun({}); // ok +obj_prop_fun({p:{}}); // ok +obj_prop_fun({p:{q:null}}); // ok, provides add'l lower bound + +function obj_prop_var(o={p:{q:""}}) { + var {p:{q=0}={q:true}} = o; + // errors: + // * number ~> void, from default on o.p.q + // * boolean ~> void, from default on o.p + // * string ~> void, from default on o + // * null ~> void, from call below + (q:void); +} +obj_prop_var(); // ok +obj_prop_var({}); // ok +obj_prop_var({p:{}}); // ok +obj_prop_var({p:{q:null}}); // ok, provides add'l lower bound + +function obj_rest({p:{q,...o}={q:0,r:0}}={p:{q:0,r:""}}) { + // errors: + // * number ~> void, from default on _.p + // * string ~> void, from default on _ + // * null ~> void, from call below + (o.r:void); +} +obj_rest(); // ok +obj_rest({}); // ok +obj_rest({p:{}}); // ok +obj_rest({p:{q:0,r:null}}); + +function obj_prop_annot({ + p = true // error: boolean ~> string +}: { + p: string +} = { + p: 0 // error: number ~> string +}) { + (p:void); // error: string ~> void +} + +var { + p = true // error: boolean ~> string +}: { + p: string +} = { + p: 0 // error: number ~> string +}; +(p:void); // error: string ~> void + +function obj_prop_err({x:{y}}=null) {} // error: property `x` cannot be accessed on null +function obj_rest_err({...o}=0) {} // error: expected object instead of number +function arr_elem_err([x]=null) {} // error: element 0 cannot be accessed on null +function arr_rest_err([...a]=null) {} // error: expected array instead of null + +function gen(x:T,{p=x}:{p:T}):T { + return p; +} + +// Default values in destructuring unwrap optional types +obj_prop_fun(({} : {p?:{q?:null}})); // ok +obj_prop_var(({} : {p?:{q?:null}})); // ok + +// union-like upper bounds preserved through destructuring +function obj_prop_opt({p}:{p?:string}={p:0}) {} +function obj_prop_maybe({p}:{p:?string}={p:0}) {} +function obj_prop_union({p}:{p:number|string}={p:true}) {} + +// TODO: union-of-objects upper bounds preserved through destructuring +function obj_prop_union2({p}:{p:number}|{p:string}={p:true}) {} + +function default_expr_scope({a, b = a}) {} diff --git a/tests/destructuring/destructuring.js b/tests/destructuring/destructuring.js new file mode 100644 index 000000000000..697454b1fceb --- /dev/null +++ b/tests/destructuring/destructuring.js @@ -0,0 +1,71 @@ +declare var a:string; +declare var b:string; +declare var c:string; +[{a1:a, b},c] = [{a1:0, b:1},2]; + +var {m} = {m:0}; +({m} = {m:m}); + +var obj; +({n: obj.x} = {n:3}); +[obj.x] = ['foo']; + +function foo({p, z:[r]}) { + a = p; + b = z; + c = r; +} +foo({p:0, z:[1,2]}); + +[a,,b,...c] = [0,1,true,3]; + +function bar({x, ...z}) { + var o:{x: string; y: number;} = z; +} +bar({x:"",y:0}); + +var spread = {y:""}; +var extend: {x:number; y:string; z: boolean} = {x:0, ...spread}; + +function qux(_: {a:number}) { } +qux({a:""}); +function corge({b}: {b:string}) { } +corge({b:0}); + +var {n}:{n: number} = {n: ""} + +function test() { + var {foo} = {bar: 123}; // error on foo + var {bar, baz} = {bar: 123} // error on baz +} + +function test() { + var x = {foo: 'abc', bar: 123}; + var {foo, ...rest} = x; + (x.baz: string); // error, baz doesn't exist + (rest.baz: string); // no error, rest is unsealed +} + +module.exports = corge; + +class Base { + baseprop1: number; + baseprop2: number; +} + +class Child extends Base { + childprop1: number; + childprop2: number; +} + +var {baseprop1, childprop1, ...others} = new Child(); + +var bp1: number = baseprop1; +var bp1_err: string = baseprop1; // Error: number ~> string +var bp2: number = others.baseprop2; +var bp2_err: string = others.baseprop2; // Error: number ~> string + +var cp1: number = childprop1; +var cp1_err: string = childprop1; // Error: number ~> string +var cp2: number = others.childprop1; +var cp2_err: string = others.childprop2; // Error: number ~> string diff --git a/tests/destructuring/destructuring_init.js b/tests/destructuring/destructuring_init.js new file mode 100644 index 000000000000..2a62fe4344d4 --- /dev/null +++ b/tests/destructuring/destructuring_init.js @@ -0,0 +1,5 @@ +var {foo}; +var [bar]; +var []; +var {}; +var [], {toz}; diff --git a/tests/destructuring/destructuring_param.js b/tests/destructuring/destructuring_param.js new file mode 100644 index 000000000000..85b6a5d42888 --- /dev/null +++ b/tests/destructuring/destructuring_param.js @@ -0,0 +1,11 @@ +function f(a, { b }) { + return a + b; +} + +function g(a, { a }) { + return a; +} + +function h({ a, { b } }, { c }, { { d } }) { + return a + b + c + d; +} diff --git a/tests/destructuring/eager.js b/tests/destructuring/eager.js new file mode 100644 index 000000000000..5b668bb68003 --- /dev/null +++ b/tests/destructuring/eager.js @@ -0,0 +1,2 @@ +var x; +({x} = null); // error, property `x` can not be accessed on `null` diff --git a/tests/destructuring/jsfmt.spec.js b/tests/destructuring/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/destructuring/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/destructuring/poly.js b/tests/destructuring/poly.js new file mode 100644 index 000000000000..bbfb5ccf7761 --- /dev/null +++ b/tests/destructuring/poly.js @@ -0,0 +1,32 @@ +// @flow + +function obj_pattern({ prop } : { prop: X }) {} // prop: X +type Prop = { prop: X }; +function obj_pattern2({ prop } : Prop) {} // prop: X + +function arr_pattern([ elem ] : X[]) {} // elem: X +type Elem = X[]; +function arr_pattern2([ elem ] : Elem) {} // elem: X + +function tup_pattern([ proj ] : [X]) {} // proj: X +type Proj = [X]; +function tup_pattern2([ proj ] : Proj) {} // proj: X + +function rest_antipattern(...t: T) {} // nonsense +function rest_pattern(...r: X[]) {} // r: X[] + +function obj_rest_pattern({ _, ...o } : { _: any, x: X }) { // o: { x: X } + o.x; +} +type ObjRest = { _: any, x: X }; +function obj_rest_pattern({ _, ...o } : ObjRest) { // o: { x: X } + o.x; +} + +function arr_rest_pattern([ _, ...a ] : [ any, X ]) { // a: [X] + a[0]; +} +type ArrRest = [ any, X ]; +function arr_rest_pattern([ _, ...a ] : ArrRest) { // a: [X] + a[0]; +} diff --git a/tests/destructuring/rec.js b/tests/destructuring/rec.js new file mode 100644 index 000000000000..8dcd432df6cc --- /dev/null +++ b/tests/destructuring/rec.js @@ -0,0 +1,20 @@ +// @flow + +// Make sure that destructuring doesn't cause infinite loops when combined with +// funny doses of repositioning + +let foo = (i: number) => [i]; + +const bar = (i: number) => { + [i] = foo(i); + return [i]; +}; + +foo = (i: number) => { + return bar(i); +}; + +// Also make sure that the following doesn't loop + +declare var o; +var { x: o } = o; diff --git a/tests/destructuring/string_lit.js b/tests/destructuring/string_lit.js new file mode 100644 index 000000000000..95da8eaf33b8 --- /dev/null +++ b/tests/destructuring/string_lit.js @@ -0,0 +1,5 @@ +var { "key": val } = { key: "val" }; +(val: void); // error: string ~> void + +var { "with-dash": with_dash } = { "with-dash": "motivating example" }; +(with_dash: "motivating example"); // ok diff --git a/tests/destructuring/unannotated.js b/tests/destructuring/unannotated.js new file mode 100644 index 000000000000..fc2d27a34661 --- /dev/null +++ b/tests/destructuring/unannotated.js @@ -0,0 +1,9 @@ +// @flow + +var { x } = { + x: { foo: "foo" } +}; + +function bar() { + x.bar +} diff --git a/tests/dictionary/__snapshots__/jsfmt.spec.js.snap b/tests/dictionary/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..599e2a272cb1 --- /dev/null +++ b/tests/dictionary/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,561 @@ +exports[`test any.js 1`] = ` +"/* @flow */ + +const dict: {[key: string]: number} = {} +const k: any = \'foo\' +const val: string = dict[k] // error: number incompatible with string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +const dict: { [key: string]: number } = {}; +const k: any = \"foo\"; +const val: string = dict[k];// error: number incompatible with string + +" +`; + +exports[`test compatible.js 1`] = ` +"/* @flow */ + +function foo0(x: Array<{[key: string]: mixed}>): Array<{[key: string]: mixed}> { + // this adds a fooBar property to the param type, which should NOT cause + // an error in the return type because it is a dictionary. + x[0].fooBar = \'foobar\'; + return x; +} + +function foo2( + x: {[key: string]: number} +): {[key: string]: number, +toString: () => string} { + // x\'s prototype has a toString method + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test dictionary.js 1`] = ` +"/* Dictionary types are object types that include an indexer, which specifies a + * key type and a value type. The presence of an indexer makes the object type + * unsealed, but all added properties must be consistent with the indexer + * signature. + * + * Dictionaries can be used to represent the common idiom of objects used as + * maps. They can also be used to represent array-like objects, e.g., NodeList + * from the DOM API. + * + * A dictionary is assumed to have every property described by it\'s key type. + * This behavior is similar to the behavior of arrays, which are assumed to have + * a value at every index. + * + * @flow + */ + +// Some logic is variance-sensitive. +class A {} +class B extends A {} +class C extends B {} + +// Just a couple of short type names. Compare to string/number. +class X {} +class Y {} + +// Any property can be set on a dict with string keys. +function set_prop_to_string_key( + o: {[k:string]:any}, +) { + o.prop = \"ok\"; +} + +// **UNSOUND** +// This is allowed by design. We don\'t track get/set and we don\'t wrap the +// return type in a maybe. +function unsound_dict_has_every_key( + o: {[k:string]:X}, +) { + (o.p: X); // ok + (o[\"p\"]: X); // ok +} + +// As with any object type, we can assign subtypes to properties. +function set_prop_covariant( + o: {[k:string]:B}, +) { + o.p = new A; // error, A ~> B + o.p = new B; // ok + o.p = new C; // ok +} + +// This isn\'t specific behavior to dictionaries, but for completeness... +function get_prop_contravariant( + o: {[k:string]:B}, +) { + (o.p: A); // ok + (o.p: B); // ok + (o.p: C); // error, C ~> B +} + +// Dot-notation can not be used to add properties to dictionaries with +// non-string keys, because keys are strings. +function add_prop_to_nonstring_key_dot( + o: {[k:number]:any}, +) { + o.prop = \"err\"; // error: string ~> number +} + +// Bracket notation can be used to add properties to dictionaries with +// non-string keys, even though all keys are strings. This is a convenient +// affordance. +function add_prop_to_nonstring_key_bracket( + o: {[k:number]:any}, +) { + o[0] = \"ok\"; +} + +// Objects can be part dict, part not by mixing an indexer with declared props. +function mix_with_declared_props( + o: {[k:number]:X,p:Y}, + x: X, + y: Y, +) { + (o[0]: X); // ok + (o.p: Y); // ok + o[0] = x; // ok + o.p = y; // ok +} + +// Indeed, dict types are still Objects and have Object.prototype stuff +function object_prototype( + o: {[k:string]:number}, +): {[k:string]:number, +toString: () => string} { + (o.toString(): boolean); // error: string ~> boolean + return o; // ok +} + +// **UNSOUND** +// Because we support non-string props w/ bracket notation, it\'s possible to +// write into a declared prop unsoundly. +function unsound_string_conversion_alias_declared_prop( + o: {[k:number]:any, \"0\":X}, +) { + o[0] = \"not-x\"; // a[\"0\"] no longer X +} + +function unification_dict_values_invariant( + x: Array<{[k:string]:B}>, +) { + let a: Array<{[k:string]:A}> = x; // error + a[0].p = new A; // in[0].p no longer B + + let b: Array<{[k:string]:B}> = x; // ok + + let c: Array<{[k:string]:C}> = x; // error + (x[0].p: C); // not true +} + +function subtype_dict_values_invariant( + x: {[k:string]:B}, +) { + let a: {[k:string]:A} = x; // error + a.p = new A; // x[0].p no longer B + + let b: {[k:string]:B} = x; // ok + + let c: {[k:string]:C} = x; // error + (x.p: C); // not true +} + +function subtype_dict_values_fresh_exception() { + let a: {[k:string]:A} = { + a: new A, // ok, A == A + b: new B, // ok, B <: A + c: new C, // ok, C <: A + }; + + let b: {[k:string]:B} = { + a: new A, // error, A not <: B + b: new B, // ok, B == B + c: new C, // ok, C <: A + }; + + let c: {[k:string]:C} = { + a: new A, // error, A not <: C + b: new B, // error, A not <: C + c: new C, // ok, C == C + }; +} + +// Actually, unsound_string_conversion_alias_declared_prop behavior makes an +// argument that we shouldn\'t really care about this, since we ignore the fact +// that coercing values to string keys can cause unintended aliasing in general. +// Barring some compelling use case for that in this context, though, we choose +// to be strict. +function unification_dict_keys_invariant( + x: Array<{[k:B]:any}>, +) { + let a: Array<{[k:A]:any}> = x; // error + let b: Array<{[k:B]:any}> = x; // ok + let c: Array<{[k:C]:any}> = x; // error +} + +function subtype_dict_keys_invariant( + x: {[k:B]:any}, +) { + let a: {[k:A]:any} = x; // error + let b: {[k:B]:any} = x; // ok + let c: {[k:C]:any} = x; // error +} + +function unification_mix_with_declared_props_invariant_l( + x: Array<{[k:string]:B}>, +) { + let a: Array<{[k:string]:B, p:A}> = x; // error: A ~> B + a[0].p = new A; // x[0].p no longer B + + let b: Array<{[k:string]:B, p:B}> = x; // ok + + let c: Array<{[k:string]:B, p:C}> = x; // error + (x[0].p: C); // not true +} + +function unification_mix_with_declared_props_invariant_r( + xa: Array<{[k:string]:A, p:B}>, + xb: Array<{[k:string]:B, p:B}>, + xc: Array<{[k:string]:C, p:B}>, +) { + let a: Array<{[k:string]:A}> = xa; // error + a[0].p = new A; // xa[0].p no longer B + + let b: Array<{[k:string]:B}> = xb; // ok + + let c: Array<{[k:string]:C}> = xc; // error + (xc[0].p: C); // not true +} + +function subtype_mix_with_declared_props_invariant_l( + x: {[k:string]:B}, +) { + let a: {[k:string]:B, p:A} = x; // error: A ~> B + a.p = new A; // x.p no longer B + + let b: {[k:string]:B, p:B} = x; // ok + + let c: {[k:string]:B, p:C} = x; // error + (x.p: C); // not true +} + +function subtype_mix_with_declared_props_invariant_r( + xa: {[k:string]:A, p:B}, + xb: {[k:string]:B, p:B}, + xc: {[k:string]:C, p:B}, +) { + let a: {[k:string]:A} = xa; // error + a.p = new A; // xa.p no longer B + + let b: {[k:string]:B} = xb; // ok + + let c: {[k:string]:C} = xc; // error + (xc.p: C); // not true +} + +function unification_dict_to_obj( + x: Array<{[k:string]:X}>, +): Array<{p:X}> { + return x; // error: if allowed, could write {p:X,q:Y} into \`x\` +} + +function unification_obj_to_dict( + x: Array<{p:X}>, +): Array<{[k:string]:X}> { + return x; // error: if allowed, could write {p:X,q:Y} into returned array +} + +function subtype_dict_to_obj( + x: {[k:string]:B}, +) { + let a: {p:A} = x; // error + a.p = new A; // x.p no longer B + + let b: {p:B} = x; // ok + + let c: {p:C} = x; // error + (x.p: C); // not true +} + +function subtype_obj_to_dict( + x: {p:B}, +) { + let a: {[k:string]:A} = x; // error + a.p = new A; // x.p no longer B + + let b: {[k:string]:B} = x; + + let c: {[k:string]:C} = x; // error + (x.p: C); // not true +} + +// Only props in l which are not in u must match indexer, but must do so +// exactly. +function subtype_obj_to_mixed( + x: {p:B, x:X}, +) { + let a: {[k:string]:A,x:X} = x; // error (as above), but exclusive of x + let b: {[k:string]:B,x:X} = x; // ok, + let c: {[k:string]:C,x:X} = x; // error (as above), but exclusive of x +} + +function unification_dict_to_mixed( + x: Array<{[k:string]:B}>, +) { + let a: Array<{[k:string]:B, p:A}> = x; // error + let b: Array<{[k:string]:B, p:B}> = x; // ok + let c: Array<{[k:string]:B, p:C}> = x; // error +} + +function subtype_dict_to_mixed( + x: {[k:string]:B}, +) { + let a: {[k:string]:B, p:A} = x; // error + let b: {[k:string]:B, p:B} = x; // ok + let c: {[k:string]:B, p:C} = x; // error +} + +function subtype_dict_to_optional_a( + x: {[k:string]:B}, +) { + let a: {p?:A} = x; // error +} + +function subtype_dict_to_optional_b( + x: {[k:string]:B}, +) { + let b: {p?:B} = x; // ok +} + +function subtype_dict_to_optional_c( + x: {[k:string]:B}, +) { + let c: {p?:C} = x; // error +} + +function subtype_optional_a_to_dict( + x: {p?:A}, +): {[k:string]:B} { // error: A ~> B + return x; +} + +function subtype_optional_b_to_dict( + x: {p?:B}, +): {[k:string]:B} { // ok + return x; +} + +function subtype_optional_c_to_dict( + x: {p?:C}, +): {[k:string]:B} { // error: C ~> B + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test incompatible.js 1`] = ` +"/* @flow */ + +var x : {[key: string]: string} = {}; +var y : {[key: string]: number} = x; // 2 errors, number !~> string & vice versa +var z : {[key: number]: string} = x; // 2 errors, string !~> number & vice versa + +var a : {[key: string]: ?string} = {}; +var b : {[key: string]: string} = a; // 2 errors (null & undefined) +var c : {[key: string]: ?string} = b; // 2 errors, since c[\'x\'] = null updates b + +// 2 errors (number !~> string, string !~> number) +function foo0(x: Array<{[key: string]: number}>): Array<{[key: string]: string}> { + return x; +} + +// error, fooBar:string !~> number (x\'s dictionary) +function foo1( + x: Array<{[key: string]: number}> +): Array<{[key: string]: number, fooBar: string}> { + return x; +} + +function foo2( + x: Array<{[key: string]: mixed}> +): Array<{[key: string]: mixed, fooBar: string}> { + x[0].fooBar = 123; // OK, since number ~> mixed (x elem\'s dictionary) + return x; // error: mixed ~> string +} + +// OK, since we assume dictionaries have every key +function foo3(x: {[key: string]: number}): {foo: number} { + return x; +} + +// error: foo can\'t exist in x +function foo4(x: {[key: string]: number}): {[key: string]: number, foo: string} { + return x; +} + +// error, some prop in x could be incompatible (covariance) +function foo5(x: Array<{[key: string]: number}>): Array<{foo: number}> { + return x; +} + +// error, some prop in return could be incompatible +function foo6(x: Array<{foo: number}>): Array<{[key: string]: number}> { + return x; +} + +function foo7(x: {bar: string, [key: string]: number}) { + (x.bar: string); +} + +function foo8(x: {[key: string]: number}) { + (x.foo: string); // error + (x.foo: number); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1745.js 1`] = ` +"/* @flow */ + +class A { + x: {[k:string]: number}; + + m1() { + this.x = { bar: 0 }; // no error + } + + m2() { + this.x.foo = 0; // no error + } +} + +class B { + x: {[k:string]: number}; + + m2() { + this.x.foo = 0; // no error + } + + m1() { + this.x = { bar: 0 }; // no error + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class A { + x: { [k: string]: number }; + m1() { + this.x = { bar: 0 };// no error + } + m2() { + this.x.foo = 0;// no error + } +} +class B { + x: { [k: string]: number }; + m2() { + this.x.foo = 0;// no error + } + m1() { + this.x = { bar: 0 };// no error + } +} + +" +`; + +exports[`test test.js 1`] = ` +"type Params = {count: number; [name: string]: string}; +type QueryFunction = (params: Params) => string; + +var o: { foo: QueryFunction } = { + foo(params) { + return params.count; // error, number ~/~ string + } +}; + +module.exports = o; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test_client.js 1`] = ` +"var o = require(\'./test\'); + +o.foo = function (params) { + return params.count; // error, number ~/~ string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = require(\"./test\"); +o.foo = function(params) { + return params.count;// error, number ~/~ string +}; + +" +`; diff --git a/tests/dictionary/any.js b/tests/dictionary/any.js new file mode 100644 index 000000000000..b8b846674dab --- /dev/null +++ b/tests/dictionary/any.js @@ -0,0 +1,5 @@ +/* @flow */ + +const dict: {[key: string]: number} = {} +const k: any = 'foo' +const val: string = dict[k] // error: number incompatible with string diff --git a/tests/dictionary/compatible.js b/tests/dictionary/compatible.js new file mode 100644 index 000000000000..87299c2ca1d9 --- /dev/null +++ b/tests/dictionary/compatible.js @@ -0,0 +1,15 @@ +/* @flow */ + +function foo0(x: Array<{[key: string]: mixed}>): Array<{[key: string]: mixed}> { + // this adds a fooBar property to the param type, which should NOT cause + // an error in the return type because it is a dictionary. + x[0].fooBar = 'foobar'; + return x; +} + +function foo2( + x: {[key: string]: number} +): {[key: string]: number, +toString: () => string} { + // x's prototype has a toString method + return x; +} diff --git a/tests/dictionary/dictionary.js b/tests/dictionary/dictionary.js new file mode 100644 index 000000000000..0a7150fa447a --- /dev/null +++ b/tests/dictionary/dictionary.js @@ -0,0 +1,320 @@ +/* Dictionary types are object types that include an indexer, which specifies a + * key type and a value type. The presence of an indexer makes the object type + * unsealed, but all added properties must be consistent with the indexer + * signature. + * + * Dictionaries can be used to represent the common idiom of objects used as + * maps. They can also be used to represent array-like objects, e.g., NodeList + * from the DOM API. + * + * A dictionary is assumed to have every property described by it's key type. + * This behavior is similar to the behavior of arrays, which are assumed to have + * a value at every index. + * + * @flow + */ + +// Some logic is variance-sensitive. +class A {} +class B extends A {} +class C extends B {} + +// Just a couple of short type names. Compare to string/number. +class X {} +class Y {} + +// Any property can be set on a dict with string keys. +function set_prop_to_string_key( + o: {[k:string]:any}, +) { + o.prop = "ok"; +} + +// **UNSOUND** +// This is allowed by design. We don't track get/set and we don't wrap the +// return type in a maybe. +function unsound_dict_has_every_key( + o: {[k:string]:X}, +) { + (o.p: X); // ok + (o["p"]: X); // ok +} + +// As with any object type, we can assign subtypes to properties. +function set_prop_covariant( + o: {[k:string]:B}, +) { + o.p = new A; // error, A ~> B + o.p = new B; // ok + o.p = new C; // ok +} + +// This isn't specific behavior to dictionaries, but for completeness... +function get_prop_contravariant( + o: {[k:string]:B}, +) { + (o.p: A); // ok + (o.p: B); // ok + (o.p: C); // error, C ~> B +} + +// Dot-notation can not be used to add properties to dictionaries with +// non-string keys, because keys are strings. +function add_prop_to_nonstring_key_dot( + o: {[k:number]:any}, +) { + o.prop = "err"; // error: string ~> number +} + +// Bracket notation can be used to add properties to dictionaries with +// non-string keys, even though all keys are strings. This is a convenient +// affordance. +function add_prop_to_nonstring_key_bracket( + o: {[k:number]:any}, +) { + o[0] = "ok"; +} + +// Objects can be part dict, part not by mixing an indexer with declared props. +function mix_with_declared_props( + o: {[k:number]:X,p:Y}, + x: X, + y: Y, +) { + (o[0]: X); // ok + (o.p: Y); // ok + o[0] = x; // ok + o.p = y; // ok +} + +// Indeed, dict types are still Objects and have Object.prototype stuff +function object_prototype( + o: {[k:string]:number}, +): {[k:string]:number, +toString: () => string} { + (o.toString(): boolean); // error: string ~> boolean + return o; // ok +} + +// **UNSOUND** +// Because we support non-string props w/ bracket notation, it's possible to +// write into a declared prop unsoundly. +function unsound_string_conversion_alias_declared_prop( + o: {[k:number]:any, "0":X}, +) { + o[0] = "not-x"; // a["0"] no longer X +} + +function unification_dict_values_invariant( + x: Array<{[k:string]:B}>, +) { + let a: Array<{[k:string]:A}> = x; // error + a[0].p = new A; // in[0].p no longer B + + let b: Array<{[k:string]:B}> = x; // ok + + let c: Array<{[k:string]:C}> = x; // error + (x[0].p: C); // not true +} + +function subtype_dict_values_invariant( + x: {[k:string]:B}, +) { + let a: {[k:string]:A} = x; // error + a.p = new A; // x[0].p no longer B + + let b: {[k:string]:B} = x; // ok + + let c: {[k:string]:C} = x; // error + (x.p: C); // not true +} + +function subtype_dict_values_fresh_exception() { + let a: {[k:string]:A} = { + a: new A, // ok, A == A + b: new B, // ok, B <: A + c: new C, // ok, C <: A + }; + + let b: {[k:string]:B} = { + a: new A, // error, A not <: B + b: new B, // ok, B == B + c: new C, // ok, C <: A + }; + + let c: {[k:string]:C} = { + a: new A, // error, A not <: C + b: new B, // error, A not <: C + c: new C, // ok, C == C + }; +} + +// Actually, unsound_string_conversion_alias_declared_prop behavior makes an +// argument that we shouldn't really care about this, since we ignore the fact +// that coercing values to string keys can cause unintended aliasing in general. +// Barring some compelling use case for that in this context, though, we choose +// to be strict. +function unification_dict_keys_invariant( + x: Array<{[k:B]:any}>, +) { + let a: Array<{[k:A]:any}> = x; // error + let b: Array<{[k:B]:any}> = x; // ok + let c: Array<{[k:C]:any}> = x; // error +} + +function subtype_dict_keys_invariant( + x: {[k:B]:any}, +) { + let a: {[k:A]:any} = x; // error + let b: {[k:B]:any} = x; // ok + let c: {[k:C]:any} = x; // error +} + +function unification_mix_with_declared_props_invariant_l( + x: Array<{[k:string]:B}>, +) { + let a: Array<{[k:string]:B, p:A}> = x; // error: A ~> B + a[0].p = new A; // x[0].p no longer B + + let b: Array<{[k:string]:B, p:B}> = x; // ok + + let c: Array<{[k:string]:B, p:C}> = x; // error + (x[0].p: C); // not true +} + +function unification_mix_with_declared_props_invariant_r( + xa: Array<{[k:string]:A, p:B}>, + xb: Array<{[k:string]:B, p:B}>, + xc: Array<{[k:string]:C, p:B}>, +) { + let a: Array<{[k:string]:A}> = xa; // error + a[0].p = new A; // xa[0].p no longer B + + let b: Array<{[k:string]:B}> = xb; // ok + + let c: Array<{[k:string]:C}> = xc; // error + (xc[0].p: C); // not true +} + +function subtype_mix_with_declared_props_invariant_l( + x: {[k:string]:B}, +) { + let a: {[k:string]:B, p:A} = x; // error: A ~> B + a.p = new A; // x.p no longer B + + let b: {[k:string]:B, p:B} = x; // ok + + let c: {[k:string]:B, p:C} = x; // error + (x.p: C); // not true +} + +function subtype_mix_with_declared_props_invariant_r( + xa: {[k:string]:A, p:B}, + xb: {[k:string]:B, p:B}, + xc: {[k:string]:C, p:B}, +) { + let a: {[k:string]:A} = xa; // error + a.p = new A; // xa.p no longer B + + let b: {[k:string]:B} = xb; // ok + + let c: {[k:string]:C} = xc; // error + (xc.p: C); // not true +} + +function unification_dict_to_obj( + x: Array<{[k:string]:X}>, +): Array<{p:X}> { + return x; // error: if allowed, could write {p:X,q:Y} into `x` +} + +function unification_obj_to_dict( + x: Array<{p:X}>, +): Array<{[k:string]:X}> { + return x; // error: if allowed, could write {p:X,q:Y} into returned array +} + +function subtype_dict_to_obj( + x: {[k:string]:B}, +) { + let a: {p:A} = x; // error + a.p = new A; // x.p no longer B + + let b: {p:B} = x; // ok + + let c: {p:C} = x; // error + (x.p: C); // not true +} + +function subtype_obj_to_dict( + x: {p:B}, +) { + let a: {[k:string]:A} = x; // error + a.p = new A; // x.p no longer B + + let b: {[k:string]:B} = x; + + let c: {[k:string]:C} = x; // error + (x.p: C); // not true +} + +// Only props in l which are not in u must match indexer, but must do so +// exactly. +function subtype_obj_to_mixed( + x: {p:B, x:X}, +) { + let a: {[k:string]:A,x:X} = x; // error (as above), but exclusive of x + let b: {[k:string]:B,x:X} = x; // ok, + let c: {[k:string]:C,x:X} = x; // error (as above), but exclusive of x +} + +function unification_dict_to_mixed( + x: Array<{[k:string]:B}>, +) { + let a: Array<{[k:string]:B, p:A}> = x; // error + let b: Array<{[k:string]:B, p:B}> = x; // ok + let c: Array<{[k:string]:B, p:C}> = x; // error +} + +function subtype_dict_to_mixed( + x: {[k:string]:B}, +) { + let a: {[k:string]:B, p:A} = x; // error + let b: {[k:string]:B, p:B} = x; // ok + let c: {[k:string]:B, p:C} = x; // error +} + +function subtype_dict_to_optional_a( + x: {[k:string]:B}, +) { + let a: {p?:A} = x; // error +} + +function subtype_dict_to_optional_b( + x: {[k:string]:B}, +) { + let b: {p?:B} = x; // ok +} + +function subtype_dict_to_optional_c( + x: {[k:string]:B}, +) { + let c: {p?:C} = x; // error +} + +function subtype_optional_a_to_dict( + x: {p?:A}, +): {[k:string]:B} { // error: A ~> B + return x; +} + +function subtype_optional_b_to_dict( + x: {p?:B}, +): {[k:string]:B} { // ok + return x; +} + +function subtype_optional_c_to_dict( + x: {p?:C}, +): {[k:string]:B} { // error: C ~> B + return x; +} diff --git a/tests/dictionary/incompatible.js b/tests/dictionary/incompatible.js new file mode 100644 index 000000000000..dc73b7e71422 --- /dev/null +++ b/tests/dictionary/incompatible.js @@ -0,0 +1,57 @@ +/* @flow */ + +var x : {[key: string]: string} = {}; +var y : {[key: string]: number} = x; // 2 errors, number !~> string & vice versa +var z : {[key: number]: string} = x; // 2 errors, string !~> number & vice versa + +var a : {[key: string]: ?string} = {}; +var b : {[key: string]: string} = a; // 2 errors (null & undefined) +var c : {[key: string]: ?string} = b; // 2 errors, since c['x'] = null updates b + +// 2 errors (number !~> string, string !~> number) +function foo0(x: Array<{[key: string]: number}>): Array<{[key: string]: string}> { + return x; +} + +// error, fooBar:string !~> number (x's dictionary) +function foo1( + x: Array<{[key: string]: number}> +): Array<{[key: string]: number, fooBar: string}> { + return x; +} + +function foo2( + x: Array<{[key: string]: mixed}> +): Array<{[key: string]: mixed, fooBar: string}> { + x[0].fooBar = 123; // OK, since number ~> mixed (x elem's dictionary) + return x; // error: mixed ~> string +} + +// OK, since we assume dictionaries have every key +function foo3(x: {[key: string]: number}): {foo: number} { + return x; +} + +// error: foo can't exist in x +function foo4(x: {[key: string]: number}): {[key: string]: number, foo: string} { + return x; +} + +// error, some prop in x could be incompatible (covariance) +function foo5(x: Array<{[key: string]: number}>): Array<{foo: number}> { + return x; +} + +// error, some prop in return could be incompatible +function foo6(x: Array<{foo: number}>): Array<{[key: string]: number}> { + return x; +} + +function foo7(x: {bar: string, [key: string]: number}) { + (x.bar: string); +} + +function foo8(x: {[key: string]: number}) { + (x.foo: string); // error + (x.foo: number); +} diff --git a/tests/dictionary/issue-1745.js b/tests/dictionary/issue-1745.js new file mode 100644 index 000000000000..cef88e22aa47 --- /dev/null +++ b/tests/dictionary/issue-1745.js @@ -0,0 +1,25 @@ +/* @flow */ + +class A { + x: {[k:string]: number}; + + m1() { + this.x = { bar: 0 }; // no error + } + + m2() { + this.x.foo = 0; // no error + } +} + +class B { + x: {[k:string]: number}; + + m2() { + this.x.foo = 0; // no error + } + + m1() { + this.x = { bar: 0 }; // no error + } +} diff --git a/tests/dictionary/jsfmt.spec.js b/tests/dictionary/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/dictionary/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/dictionary/test.js b/tests/dictionary/test.js new file mode 100644 index 000000000000..8b2b99223b98 --- /dev/null +++ b/tests/dictionary/test.js @@ -0,0 +1,10 @@ +type Params = {count: number; [name: string]: string}; +type QueryFunction = (params: Params) => string; + +var o: { foo: QueryFunction } = { + foo(params) { + return params.count; // error, number ~/~ string + } +}; + +module.exports = o; diff --git a/tests/dictionary/test_client.js b/tests/dictionary/test_client.js new file mode 100644 index 000000000000..28e9c5808816 --- /dev/null +++ b/tests/dictionary/test_client.js @@ -0,0 +1,5 @@ +var o = require('./test'); + +o.foo = function (params) { + return params.count; // error, number ~/~ string +} diff --git a/tests/disjoint-union-perf/__snapshots__/jsfmt.spec.js.snap b/tests/disjoint-union-perf/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2afb93d5ec39 --- /dev/null +++ b/tests/disjoint-union-perf/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,840 @@ +exports[`test ast.js 1`] = ` +"/** + * @flow + */ + +export type InferredType = + | \'unknown\' + | \'gender\' + | \'enum\' + | \'number-or-string\' + | \'number\' + | \'string\' + | \'error\' +; + +export type Pos = { + firstLine: number, + firstColumn: number, + lastLine: number, + lastColumn: number, +}; + +export type TypedBinaryOpNode = { + exprNodeType: \'binary_op\', + binaryOp: \'plus\' | \'multiply\' | \'divide\' | \'minus\', + lhs: TypedNode, + rhs: TypedNode, + pos: Pos, + exprType: InferredType, + typed: true, +} + +export type TypedUnaryMinusNode = { + exprNodeType: \'unary_minus\', + op: TypedNode, + pos: Pos, + exprType: InferredType, + typed: true, +} + +export type TypedNumberNode = { + exprNodeType: \'number\', + value: number, + pos: Pos, + exprType: \'number\', + typed: true, +} + +export type TypedStringLiteralNode = { + exprNodeType: \'string_literal\', + value: string, + pos: Pos, + exprType: \'string\', + typed: true, +} + +export type TypedVariableNode = { + exprNodeType: \'variable\', + name: string, + pos: Pos, + exprType: InferredType, + typed: true, +}; + +export type TypedFunctionInvocationNode = { + exprNodeType: \'function_invocation\', + name: string, + parameters: TypedNode[], + pos: Pos, + exprType: \'error\' | \'string\', + typed: true, +} + +export type TypedNode = + | TypedBinaryOpNode + | TypedUnaryMinusNode + | TypedNumberNode + | TypedStringLiteralNode + | TypedVariableNode + | TypedFunctionInvocationNode +; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test emit.js 1`] = ` +"/** + * @flow + */ +import * as t from \'./jsAst\'; + +const b = t.builders; + +import type { + TypedNode +} from \'./ast\'; + +function getBinaryOp(op: \'plus\' | \'minus\' | \'divide\' | \'multiply\') : \'+\' | \'-\' | \'*\' | \'/\' { + switch (op) { + case \'plus\': + return \'+\'; + case \'minus\': + return \'-\'; + case \'divide\': + return \'/\'; + case \'multiply\': + return \'*\'; + default: + throw new Error(\'Invalid binary operator: \' + op); + } +} + +export function emitExpression(node: TypedNode) : t.Expression { + switch (node.exprNodeType) { + case \'string_literal\': // FALLTHROUGH + case \'number\': + return b.literal(node.value); + case \'variable\': + return b.memberExpression( + b.identifier(\'vars\'), + b.identifier(node.name), + false + ); + case \'binary_op\': { + const lhs = emitExpression(node.lhs); + const rhs = emitExpression(node.rhs); + + const op = getBinaryOp(node.binaryOp); + return b.binaryExpression(op, lhs, rhs); + } + case \'unary_minus\': { + const operand = emitExpression(node.op); + return b.unaryExpression(\'-\', operand, true); + } + case \'function_invocation\': { + const callee = b.memberExpression( + b.identifier(\'fns\'), + b.identifier(node.name), + false + ); + + const args = node.parameters.map( + (n) => emitExpression(n) + ); + + return b.callExpression(callee, args); + } + default: + throw new Error(\'Unknown expression type: \' + node.type); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test jsAst.js 1`] = ` +"/** + * @flow + */ +export type Comment = { + loc: ?SourceLocation, + value: string, + leading: boolean, + trailing: boolean, +}; + +export type SourceLocation = { + start: SourcePosition, + end: SourcePosition, + source: ?string, +}; + +export type SourcePosition = { + line: number, + column: number, +}; + +export type File = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'File\', + program: Program, +} + +export type Program = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'Program\', + body: Statement[], +} + +export type BinaryOperator = + |\'==\' + | \'!=\' + | \'===\' + | \'!==\' + | \'<\' + | \'<=\' + | \'>\' + | \'>=\' + | \'<<\' + | \'>>\' + | \'>>>\' + | \'+\' + | \'-\' + | \'*\' + | \'/\' + | \'%\' + | \'&\' // TODO Missing from the Parser API. + | \'|\' + | \'^\' + | \'in\' + | \'instanceof\' + | \'..\' +; + +export type UnaryOperator = + | \'-\' + | \'+\' + | \'!\' + | \'~\' + | \'typeof\' + | \'void\' + | \'delete\' +; + +export type AssignmentOperator = + | \'=\' + | \'+=\' + | \'-=\' + | \'*=\' + | \'/=\' + | \'%=\' + | \'<<=\' + | \'>>=\' + | \'>>>=\' + | \'|=\' + | \'^=\' + | \'&=\' +; + +export type UpdateOperator = + | \'++\' + | \'--\' +; + +export type LogicalOperator = + | \'&&\' + | \'||\' +; + +export type Node = + | EmptyStatement + | BlockStatement + | ExpressionStatement + | IfStatement + | BreakStatement + | ContinueStatement + | ReturnStatement + | ThrowStatement + | WhileStatement + | ForStatement + | ForInStatement + | TryStatement + | CatchClause + | Identifier + | Literal + | ThisExpression + | ArrayExpression + | ObjectExpreession + | Property + | FunctionExpression + | BinaryExpression + | UnaryExpression + | AssignmentExpression + | UpdateExpression + | LogicalExpression + | ConditionalExpression + | NewExpression + | CallExpression + | MemberExpression + | VariableDeclaration + | FunctionDeclaration + | VariableDeclarator +; + +export type Statement = + | BlockStatement + | EmptyStatement + | ExpressionStatement + | IfStatement + | BreakStatement + | ContinueStatement + | ReturnStatement + | ThrowStatement + | WhileStatement + | ForStatement + | ForInStatement + | TryStatement + | Declaration +; + +export type EmptyStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'EmptyStatement\', +} + +export type BlockStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'BlockStatement\', + body: Statement[], +} + +export type ExpressionStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ExpressionStatement\', + expression: Expression, +} + +export type IfStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'IfStatement\', + test: Expression, + consequent: Statement, + alternate: ?Statement, +} + +export type BreakStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'BreakStatement\', + label: ?Identifier, +} + +export type ContinueStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ContinueStatement\', + label: ?Identifier, +} + +export type ReturnStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ReturnStatement\', + argument: ?Expression, +} + +export type ThrowStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ThrowStatement\', + argument: ?Expression, +} + +export type WhileStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'WhileStatement\', + test: Expression, + body: Statement, +} + +export type ForStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ForStatement\', + init: ?(VariableDeclaration | Expression), + test: ?Expression, + update: ?Expression, + body: Statement, +} + +export type ForInStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ForInStatement\', + left: VariableDeclaration | Expression, + right: Expression, + body: Statement, +} + +export type TryStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'TryStatement\', + block: BlockStatement, + handler: ?CatchClause, + handlers: CatchClause[], + finalizer: ?BlockStatement, +}; + +export type CatchClause = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'CatchClause\', + param: Pattern, + guard: ?Expression, + body: BlockStatement, +}; + +export type Expression = + | Identifier + | ThisExpression + | Literal + | FunctionExpression + | BinaryExpression + | UnaryExpression + | AssignmentExpression + | UpdateExpression + | LogicalExpression + | ConditionalExpression + | NewExpression + | CallExpression + | MemberExpression + | ArrayExpression + | ObjectExpreession +; + +export type Identifier = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'Identifier\', + name: string, +} + +export type Literal = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'Literal\', + value: ?(string | boolean | number | RegExp), + regex: ?{ pattern: string, flags: string }, +} + +export type ThisExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ThisExpression\', +} + +export type ArrayExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ArrayExpression\', + elements: Expression[], +} + +export type ObjectExpreession = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ObjectExpression\', + properties: Property[], +} + +export type Property = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'Property\', + kind: \'init\' | \'get\' | \'set\', + key: Literal | Identifier, + value: Expression, +}; + +export type FunctionExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'FunctionExpression\', + id: ?Identifier, + params: Pattern[], + body: BlockStatement, +} + +export type BinaryExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'BinaryExpression\', + operator: BinaryOperator, + left: Expression, + right: Expression, +} + +export type UnaryExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'UnaryExpression\', + operator: UnaryOperator, + argument: Expression, + prefix: boolean, +}; + +export type AssignmentExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'AssignmentExpression\', + operator: AssignmentOperator, + left: Pattern, + right: Expression, +}; + +export type UpdateExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'UpdateExpression\', + operator: UpdateOperator, + argument: Expression, + prefix: boolean, +}; + +export type LogicalExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'LogicalExpression\', + operator: LogicalOperator, + left: Expression, + right: Expression, +}; + +export type ConditionalExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'ConditionalExpression\', + test: Expression, + consequent: Expression, + alternate: Expression, +}; + +export type NewExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'NewExpression\', + callee: Expression, + arguments: Expression[], +}; + +export type CallExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'CallExpression\', + callee: Expression, + arguments: Expression[], +}; + +export type MemberExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'MemberExpression\', + object: Expression, + property: Identifier | Expression, + computed: bool, +} +// ast-types exports all expressions as patterns. +// That seems not like it was intended. +export type Pattern = + | Identifier +; + +export type Declaration = + | VariableDeclaration + | FunctionDeclaration +; + +export type VariableDeclaration = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'VariableDeclaration\', + kind: \'var\' | \'let\' | \'const\', + declarations: VariableDeclarator[], +} + +export type FunctionDeclaration = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'FunctionDeclaration\', + id: Identifier, + body: BlockStatement, + params: Pattern[], +} + +export type VariableDeclarator = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: \'VariableDeclarator\', + id: Pattern, + init: ?Expression, +} + +const a : any = null; + +export const builders : { + emptyStatement() : EmptyStatement, + blockStatement( + body: Statement[] + ) : BlockStatement, + expressionStatement( + expression: Expression + ) : ExpressionStatement, + ifStatement( + test: Expression, + consequent: Statement, + alternate?: Statement + ) : IfStatement, + breakStatement( + label?: Identifier + ) : BreakStatement, + continueStatement( + label?: Identifier + ) : ContinueStatement, + returnStatement( + argument: ?Expression + ) : ReturnStatement, + throwStatement( + argument: ?Expression + ) : ThrowStatement, + whileStatement( + test: Expression, + body: Statement + ) : WhileStatement, + forStatement( + init: ?(VariableDeclaration | Expression), + test: ?Expression, + update: ?Expression, + body: Statement + ) : ForStatement, + forInStatement( + left: VariableDeclaration | Expression, + right: Expression, + body: Statement + ) : ForInStatement, + tryStatement( + block: BlockStatement, + handler: ?CatchClause, + handlers: CatchClause[], + finalizer?: BlockStatement + ) : TryStatement, + catchClause( + param: Pattern, + guard: ?Expression, + body: BlockStatement + ) : CatchClause, + identifier( + name: string + ) : Identifier, + literal( + value: ?(string | boolean | number | RegExp), + regex?: { pattern: string, flags: string } + ) : Literal, + thisExpression() : ThisExpression, + arrayExpression( + elements: Expression[] + ) : ArrayExpression, + objectExpreession( + properties: Property[] + ) : ObjectExpreession, + property( + kind: \'init\' | \'get\' | \'set\', + key: Literal | Identifier, + value: Expression + ) : Property, + functionExpression( + id: ?Identifier, + params: Pattern[], + body: BlockStatement + ) : FunctionExpression, + binaryExpression( + operator: BinaryOperator, + left: Expression, + right: Expression + ) : BinaryExpression, + unaryExpression( + operator: UnaryOperator, + argument: Expression, + prefix: boolean + ) : UnaryExpression, + assignmentExpression( + operator: AssignmentOperator, + left: Pattern, + right: Expression + ) : AssignmentExpression, + updateExpression( + operator: UpdateOperator, + argument: Expression, + prefix: boolean + ) : UpdateExpression, + logicalExpression( + operator: LogicalOperator, + left: Expression, + right: Expression + ) : LogicalExpression, + conditionalExpression( + test: Expression, + consequent: Expression, + alternate: Expression + ) : ConditionalExpression, + newExpression( + callee: Expression, + arguments: Expression[] + ) : NewExpression, + callExpression( + callee: Expression, + arguments: Expression[] + ) : CallExpression, + memberExpression( + object: Expression, + property: Identifier | Expression, + computed: bool + ) : MemberExpression, + variableDeclaration( + kind: \'var\' | \'let\' | \'const\', + declarations: VariableDeclarator[] + ) : VariableDeclaration, + functionDeclaration( + id: Identifier, + body: BlockStatement, + params: Pattern[] + ) : FunctionDeclaration, + variableDeclarator( + id: Pattern, + init?: Expression + ) : VariableDeclarator, +} = a; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/disjoint-union-perf/ast.js b/tests/disjoint-union-perf/ast.js new file mode 100644 index 000000000000..8705bde03415 --- /dev/null +++ b/tests/disjoint-union-perf/ast.js @@ -0,0 +1,80 @@ +/** + * @flow + */ + +export type InferredType = + | 'unknown' + | 'gender' + | 'enum' + | 'number-or-string' + | 'number' + | 'string' + | 'error' +; + +export type Pos = { + firstLine: number, + firstColumn: number, + lastLine: number, + lastColumn: number, +}; + +export type TypedBinaryOpNode = { + exprNodeType: 'binary_op', + binaryOp: 'plus' | 'multiply' | 'divide' | 'minus', + lhs: TypedNode, + rhs: TypedNode, + pos: Pos, + exprType: InferredType, + typed: true, +} + +export type TypedUnaryMinusNode = { + exprNodeType: 'unary_minus', + op: TypedNode, + pos: Pos, + exprType: InferredType, + typed: true, +} + +export type TypedNumberNode = { + exprNodeType: 'number', + value: number, + pos: Pos, + exprType: 'number', + typed: true, +} + +export type TypedStringLiteralNode = { + exprNodeType: 'string_literal', + value: string, + pos: Pos, + exprType: 'string', + typed: true, +} + +export type TypedVariableNode = { + exprNodeType: 'variable', + name: string, + pos: Pos, + exprType: InferredType, + typed: true, +}; + +export type TypedFunctionInvocationNode = { + exprNodeType: 'function_invocation', + name: string, + parameters: TypedNode[], + pos: Pos, + exprType: 'error' | 'string', + typed: true, +} + +export type TypedNode = + | TypedBinaryOpNode + | TypedUnaryMinusNode + | TypedNumberNode + | TypedStringLiteralNode + | TypedVariableNode + | TypedFunctionInvocationNode +; diff --git a/tests/disjoint-union-perf/emit.js b/tests/disjoint-union-perf/emit.js new file mode 100644 index 000000000000..49bef648e63c --- /dev/null +++ b/tests/disjoint-union-perf/emit.js @@ -0,0 +1,65 @@ +/** + * @flow + */ +import * as t from './jsAst'; + +const b = t.builders; + +import type { + TypedNode +} from './ast'; + +function getBinaryOp(op: 'plus' | 'minus' | 'divide' | 'multiply') : '+' | '-' | '*' | '/' { + switch (op) { + case 'plus': + return '+'; + case 'minus': + return '-'; + case 'divide': + return '/'; + case 'multiply': + return '*'; + default: + throw new Error('Invalid binary operator: ' + op); + } +} + +export function emitExpression(node: TypedNode) : t.Expression { + switch (node.exprNodeType) { + case 'string_literal': // FALLTHROUGH + case 'number': + return b.literal(node.value); + case 'variable': + return b.memberExpression( + b.identifier('vars'), + b.identifier(node.name), + false + ); + case 'binary_op': { + const lhs = emitExpression(node.lhs); + const rhs = emitExpression(node.rhs); + + const op = getBinaryOp(node.binaryOp); + return b.binaryExpression(op, lhs, rhs); + } + case 'unary_minus': { + const operand = emitExpression(node.op); + return b.unaryExpression('-', operand, true); + } + case 'function_invocation': { + const callee = b.memberExpression( + b.identifier('fns'), + b.identifier(node.name), + false + ); + + const args = node.parameters.map( + (n) => emitExpression(n) + ); + + return b.callExpression(callee, args); + } + default: + throw new Error('Unknown expression type: ' + node.type); + } +} diff --git a/tests/disjoint-union-perf/jsAst.js b/tests/disjoint-union-perf/jsAst.js new file mode 100644 index 000000000000..4ca78a03e62d --- /dev/null +++ b/tests/disjoint-union-perf/jsAst.js @@ -0,0 +1,636 @@ +/** + * @flow + */ +export type Comment = { + loc: ?SourceLocation, + value: string, + leading: boolean, + trailing: boolean, +}; + +export type SourceLocation = { + start: SourcePosition, + end: SourcePosition, + source: ?string, +}; + +export type SourcePosition = { + line: number, + column: number, +}; + +export type File = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'File', + program: Program, +} + +export type Program = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'Program', + body: Statement[], +} + +export type BinaryOperator = + |'==' + | '!=' + | '===' + | '!==' + | '<' + | '<=' + | '>' + | '>=' + | '<<' + | '>>' + | '>>>' + | '+' + | '-' + | '*' + | '/' + | '%' + | '&' // TODO Missing from the Parser API. + | '|' + | '^' + | 'in' + | 'instanceof' + | '..' +; + +export type UnaryOperator = + | '-' + | '+' + | '!' + | '~' + | 'typeof' + | 'void' + | 'delete' +; + +export type AssignmentOperator = + | '=' + | '+=' + | '-=' + | '*=' + | '/=' + | '%=' + | '<<=' + | '>>=' + | '>>>=' + | '|=' + | '^=' + | '&=' +; + +export type UpdateOperator = + | '++' + | '--' +; + +export type LogicalOperator = + | '&&' + | '||' +; + +export type Node = + | EmptyStatement + | BlockStatement + | ExpressionStatement + | IfStatement + | BreakStatement + | ContinueStatement + | ReturnStatement + | ThrowStatement + | WhileStatement + | ForStatement + | ForInStatement + | TryStatement + | CatchClause + | Identifier + | Literal + | ThisExpression + | ArrayExpression + | ObjectExpreession + | Property + | FunctionExpression + | BinaryExpression + | UnaryExpression + | AssignmentExpression + | UpdateExpression + | LogicalExpression + | ConditionalExpression + | NewExpression + | CallExpression + | MemberExpression + | VariableDeclaration + | FunctionDeclaration + | VariableDeclarator +; + +export type Statement = + | BlockStatement + | EmptyStatement + | ExpressionStatement + | IfStatement + | BreakStatement + | ContinueStatement + | ReturnStatement + | ThrowStatement + | WhileStatement + | ForStatement + | ForInStatement + | TryStatement + | Declaration +; + +export type EmptyStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'EmptyStatement', +} + +export type BlockStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'BlockStatement', + body: Statement[], +} + +export type ExpressionStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ExpressionStatement', + expression: Expression, +} + +export type IfStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'IfStatement', + test: Expression, + consequent: Statement, + alternate: ?Statement, +} + +export type BreakStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'BreakStatement', + label: ?Identifier, +} + +export type ContinueStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ContinueStatement', + label: ?Identifier, +} + +export type ReturnStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ReturnStatement', + argument: ?Expression, +} + +export type ThrowStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ThrowStatement', + argument: ?Expression, +} + +export type WhileStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'WhileStatement', + test: Expression, + body: Statement, +} + +export type ForStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ForStatement', + init: ?(VariableDeclaration | Expression), + test: ?Expression, + update: ?Expression, + body: Statement, +} + +export type ForInStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ForInStatement', + left: VariableDeclaration | Expression, + right: Expression, + body: Statement, +} + +export type TryStatement = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'TryStatement', + block: BlockStatement, + handler: ?CatchClause, + handlers: CatchClause[], + finalizer: ?BlockStatement, +}; + +export type CatchClause = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'CatchClause', + param: Pattern, + guard: ?Expression, + body: BlockStatement, +}; + +export type Expression = + | Identifier + | ThisExpression + | Literal + | FunctionExpression + | BinaryExpression + | UnaryExpression + | AssignmentExpression + | UpdateExpression + | LogicalExpression + | ConditionalExpression + | NewExpression + | CallExpression + | MemberExpression + | ArrayExpression + | ObjectExpreession +; + +export type Identifier = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'Identifier', + name: string, +} + +export type Literal = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'Literal', + value: ?(string | boolean | number | RegExp), + regex: ?{ pattern: string, flags: string }, +} + +export type ThisExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ThisExpression', +} + +export type ArrayExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ArrayExpression', + elements: Expression[], +} + +export type ObjectExpreession = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ObjectExpression', + properties: Property[], +} + +export type Property = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'Property', + kind: 'init' | 'get' | 'set', + key: Literal | Identifier, + value: Expression, +}; + +export type FunctionExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'FunctionExpression', + id: ?Identifier, + params: Pattern[], + body: BlockStatement, +} + +export type BinaryExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'BinaryExpression', + operator: BinaryOperator, + left: Expression, + right: Expression, +} + +export type UnaryExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'UnaryExpression', + operator: UnaryOperator, + argument: Expression, + prefix: boolean, +}; + +export type AssignmentExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'AssignmentExpression', + operator: AssignmentOperator, + left: Pattern, + right: Expression, +}; + +export type UpdateExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'UpdateExpression', + operator: UpdateOperator, + argument: Expression, + prefix: boolean, +}; + +export type LogicalExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'LogicalExpression', + operator: LogicalOperator, + left: Expression, + right: Expression, +}; + +export type ConditionalExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'ConditionalExpression', + test: Expression, + consequent: Expression, + alternate: Expression, +}; + +export type NewExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'NewExpression', + callee: Expression, + arguments: Expression[], +}; + +export type CallExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'CallExpression', + callee: Expression, + arguments: Expression[], +}; + +export type MemberExpression = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'MemberExpression', + object: Expression, + property: Identifier | Expression, + computed: bool, +} +// ast-types exports all expressions as patterns. +// That seems not like it was intended. +export type Pattern = + | Identifier +; + +export type Declaration = + | VariableDeclaration + | FunctionDeclaration +; + +export type VariableDeclaration = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'VariableDeclaration', + kind: 'var' | 'let' | 'const', + declarations: VariableDeclarator[], +} + +export type FunctionDeclaration = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'FunctionDeclaration', + id: Identifier, + body: BlockStatement, + params: Pattern[], +} + +export type VariableDeclarator = { + source: ?string, + start: SourcePosition, + end: SourcePosition, + comments: ?Array, + type: 'VariableDeclarator', + id: Pattern, + init: ?Expression, +} + +const a : any = null; + +export const builders : { + emptyStatement() : EmptyStatement, + blockStatement( + body: Statement[] + ) : BlockStatement, + expressionStatement( + expression: Expression + ) : ExpressionStatement, + ifStatement( + test: Expression, + consequent: Statement, + alternate?: Statement + ) : IfStatement, + breakStatement( + label?: Identifier + ) : BreakStatement, + continueStatement( + label?: Identifier + ) : ContinueStatement, + returnStatement( + argument: ?Expression + ) : ReturnStatement, + throwStatement( + argument: ?Expression + ) : ThrowStatement, + whileStatement( + test: Expression, + body: Statement + ) : WhileStatement, + forStatement( + init: ?(VariableDeclaration | Expression), + test: ?Expression, + update: ?Expression, + body: Statement + ) : ForStatement, + forInStatement( + left: VariableDeclaration | Expression, + right: Expression, + body: Statement + ) : ForInStatement, + tryStatement( + block: BlockStatement, + handler: ?CatchClause, + handlers: CatchClause[], + finalizer?: BlockStatement + ) : TryStatement, + catchClause( + param: Pattern, + guard: ?Expression, + body: BlockStatement + ) : CatchClause, + identifier( + name: string + ) : Identifier, + literal( + value: ?(string | boolean | number | RegExp), + regex?: { pattern: string, flags: string } + ) : Literal, + thisExpression() : ThisExpression, + arrayExpression( + elements: Expression[] + ) : ArrayExpression, + objectExpreession( + properties: Property[] + ) : ObjectExpreession, + property( + kind: 'init' | 'get' | 'set', + key: Literal | Identifier, + value: Expression + ) : Property, + functionExpression( + id: ?Identifier, + params: Pattern[], + body: BlockStatement + ) : FunctionExpression, + binaryExpression( + operator: BinaryOperator, + left: Expression, + right: Expression + ) : BinaryExpression, + unaryExpression( + operator: UnaryOperator, + argument: Expression, + prefix: boolean + ) : UnaryExpression, + assignmentExpression( + operator: AssignmentOperator, + left: Pattern, + right: Expression + ) : AssignmentExpression, + updateExpression( + operator: UpdateOperator, + argument: Expression, + prefix: boolean + ) : UpdateExpression, + logicalExpression( + operator: LogicalOperator, + left: Expression, + right: Expression + ) : LogicalExpression, + conditionalExpression( + test: Expression, + consequent: Expression, + alternate: Expression + ) : ConditionalExpression, + newExpression( + callee: Expression, + arguments: Expression[] + ) : NewExpression, + callExpression( + callee: Expression, + arguments: Expression[] + ) : CallExpression, + memberExpression( + object: Expression, + property: Identifier | Expression, + computed: bool + ) : MemberExpression, + variableDeclaration( + kind: 'var' | 'let' | 'const', + declarations: VariableDeclarator[] + ) : VariableDeclaration, + functionDeclaration( + id: Identifier, + body: BlockStatement, + params: Pattern[] + ) : FunctionDeclaration, + variableDeclarator( + id: Pattern, + init?: Expression + ) : VariableDeclarator, +} = a; diff --git a/tests/disjoint-union-perf/jsfmt.spec.js b/tests/disjoint-union-perf/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/disjoint-union-perf/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/docblock_flow/__snapshots__/jsfmt.spec.js.snap b/tests/docblock_flow/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3994c269287c --- /dev/null +++ b/tests/docblock_flow/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,108 @@ +exports[`test license_with_flow.js 1`] = ` +"/* Copyright example */ +/* @flow */ + +("": void); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* Copyright example */ +/* @flow */ +("": void);// error + +" +`; + +exports[`test max_header_tokens.js 1`] = ` +"/* @flow */ +/* second token */ +/* third token */ +/** + * After max_header_tokens (in .flowconfig), we no longer care: + * + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test multiple_flows_1.js 1`] = ` +"/* @flow */ +/* @flow */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test multiple_flows_2.js 1`] = ` +"/** + * @flow + * @noflow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test multiple_providesModule_1.js 1`] = ` +"/** + * @providesModule Foo + * @providesModule Bar + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test multiple_providesModule_2.js 1`] = ` +"/** + * @providesModule Foo + * @flow + */ +/** + * @providesModule Bar + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test use_strict_with_flow.js 1`] = ` +""use strict"; +/* @flow */ + +("": void); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +"use strict"; +/* @flow */ +("": void);// error + +" +`; + +exports[`test with_flow.js 1`] = ` +"/* @flow */ + +("": void); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +("": void);// error + +" +`; + +exports[`test without_flow.js 1`] = ` +"/* some other comment */ + +("": void); // no error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* some other comment */ +("": void);// no error + +" +`; diff --git a/tests/docblock_flow/jsfmt.spec.js b/tests/docblock_flow/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/docblock_flow/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/docblock_flow/license_with_flow.js b/tests/docblock_flow/license_with_flow.js new file mode 100644 index 000000000000..8b3cd6be2a8d --- /dev/null +++ b/tests/docblock_flow/license_with_flow.js @@ -0,0 +1,4 @@ +/* Copyright example */ +/* @flow */ + +("": void); // error diff --git a/tests/docblock_flow/max_header_tokens.js b/tests/docblock_flow/max_header_tokens.js new file mode 100644 index 000000000000..c8eb64fe8886 --- /dev/null +++ b/tests/docblock_flow/max_header_tokens.js @@ -0,0 +1,8 @@ +/* @flow */ +/* second token */ +/* third token */ +/** + * After max_header_tokens (in .flowconfig), we no longer care: + * + * @flow + */ diff --git a/tests/docblock_flow/multiple_flows_1.js b/tests/docblock_flow/multiple_flows_1.js new file mode 100644 index 000000000000..205d73fd152c --- /dev/null +++ b/tests/docblock_flow/multiple_flows_1.js @@ -0,0 +1,2 @@ +/* @flow */ +/* @flow */ diff --git a/tests/docblock_flow/multiple_flows_2.js b/tests/docblock_flow/multiple_flows_2.js new file mode 100644 index 000000000000..421903b00b29 --- /dev/null +++ b/tests/docblock_flow/multiple_flows_2.js @@ -0,0 +1,4 @@ +/** + * @flow + * @noflow + */ diff --git a/tests/docblock_flow/multiple_providesModule_1.js b/tests/docblock_flow/multiple_providesModule_1.js new file mode 100644 index 000000000000..5d78d1deb91c --- /dev/null +++ b/tests/docblock_flow/multiple_providesModule_1.js @@ -0,0 +1,5 @@ +/** + * @providesModule Foo + * @providesModule Bar + * @flow + */ diff --git a/tests/docblock_flow/multiple_providesModule_2.js b/tests/docblock_flow/multiple_providesModule_2.js new file mode 100644 index 000000000000..01b86e701744 --- /dev/null +++ b/tests/docblock_flow/multiple_providesModule_2.js @@ -0,0 +1,7 @@ +/** + * @providesModule Foo + * @flow + */ +/** + * @providesModule Bar + */ diff --git a/tests/docblock_flow/use_strict_with_flow.js b/tests/docblock_flow/use_strict_with_flow.js new file mode 100644 index 000000000000..5d065b6a9452 --- /dev/null +++ b/tests/docblock_flow/use_strict_with_flow.js @@ -0,0 +1,4 @@ +"use strict"; +/* @flow */ + +("": void); // error diff --git a/tests/docblock_flow/with_flow.js b/tests/docblock_flow/with_flow.js new file mode 100644 index 000000000000..83ee2f86af06 --- /dev/null +++ b/tests/docblock_flow/with_flow.js @@ -0,0 +1,3 @@ +/* @flow */ + +("": void); // error diff --git a/tests/docblock_flow/without_flow.js b/tests/docblock_flow/without_flow.js new file mode 100644 index 000000000000..d8ba64110515 --- /dev/null +++ b/tests/docblock_flow/without_flow.js @@ -0,0 +1,3 @@ +/* some other comment */ + +("": void); // no error diff --git a/tests/dom/CanvasRenderingContext2D.js b/tests/dom/CanvasRenderingContext2D.js new file mode 100644 index 000000000000..f6af4fc4f579 --- /dev/null +++ b/tests/dom/CanvasRenderingContext2D.js @@ -0,0 +1,13 @@ +// @flow + +let tests = [ + // fillRect + function(ctx: CanvasRenderingContext2D) { + ctx.fillRect(0, 0, 200, 100); + }, + + // moveTo + function(ctx: CanvasRenderingContext2D) { + ctx.moveTo('0', '1'); // error: should be numbers + }, +]; diff --git a/tests/dom/CustomEvent.js b/tests/dom/CustomEvent.js new file mode 100644 index 000000000000..4c73a4d8f5bb --- /dev/null +++ b/tests/dom/CustomEvent.js @@ -0,0 +1,9 @@ +// @flow + +let tests = [ + // CustomEvent + function(document: Document) { + const event = document.createEvent('CustomEvent'); + event.initCustomEvent('butts', true, false, { nice: 42 }); + } +]; diff --git a/tests/dom/Document.js b/tests/dom/Document.js new file mode 100644 index 000000000000..7bf234607fe1 --- /dev/null +++ b/tests/dom/Document.js @@ -0,0 +1,11 @@ +// @flow + +let tests = [ + // createElement + function(document: Document) { + (document.createElement('canvas'): HTMLCanvasElement); + (document.createElement('link'): HTMLLinkElement); + (document.createElement('option'): HTMLOptionElement); + (document.createElement('select'): HTMLSelectElement); + } +]; diff --git a/tests/dom/Element.js b/tests/dom/Element.js new file mode 100644 index 000000000000..9f8c65c2fc6e --- /dev/null +++ b/tests/dom/Element.js @@ -0,0 +1,18 @@ +// @flow + +let tests = [ + // scrollIntoView + function(element: Element) { + element.scrollIntoView(); + element.scrollIntoView(false); + element.scrollIntoView({}); + element.scrollIntoView({ behavior: 'smooth', block: 'end' }); + element.scrollIntoView({ block: 'end' }); + element.scrollIntoView({ behavior: 'smooth' }); + + // fails + element.scrollIntoView({ behavior: 'invalid' }); + element.scrollIntoView({ block: 'invalid' }); + element.scrollIntoView(1); + } +]; diff --git a/tests/dom/HTMLCanvasElement.js b/tests/dom/HTMLCanvasElement.js new file mode 100644 index 000000000000..1bad9066f73e --- /dev/null +++ b/tests/dom/HTMLCanvasElement.js @@ -0,0 +1,8 @@ +// @flow + +let tests = [ + // getContext + function(el: HTMLCanvasElement) { + (el.getContext('2d'): ?CanvasRenderingContext2D); + } +]; diff --git a/tests/dom/HTMLElement.js b/tests/dom/HTMLElement.js new file mode 100644 index 000000000000..d3942a275710 --- /dev/null +++ b/tests/dom/HTMLElement.js @@ -0,0 +1,18 @@ +// @flow + +let tests = [ + // scrollIntoView + function(element: HTMLElement) { + element.scrollIntoView(); + element.scrollIntoView(false); + element.scrollIntoView({}); + element.scrollIntoView({ behavior: 'smooth', block: 'end' }); + element.scrollIntoView({ block: 'end' }); + element.scrollIntoView({ behavior: 'smooth' }); + + // fails + element.scrollIntoView({ behavior: 'invalid' }); + element.scrollIntoView({ block: 'invalid' }); + element.scrollIntoView(1); + } +]; diff --git a/tests/dom/HTMLInputElement.js b/tests/dom/HTMLInputElement.js new file mode 100644 index 000000000000..48f1413addc9 --- /dev/null +++ b/tests/dom/HTMLInputElement.js @@ -0,0 +1,12 @@ +// @flow + +let tests = [ + // setRangeText + function(el: HTMLInputElement) { + el.setRangeText('foo'); + el.setRangeText('foo', 123); // end is required + el.setRangeText('foo', 123, 234); + el.setRangeText('foo', 123, 234, 'select'); + el.setRangeText('foo', 123, 234, 'bogus'); // invalid value + } +]; diff --git a/tests/dom/URL.js b/tests/dom/URL.js new file mode 100644 index 000000000000..ecba845d56da --- /dev/null +++ b/tests/dom/URL.js @@ -0,0 +1,20 @@ +/* @flow */ + +const a = new URL('http://flowtype.org/'); // correct +const b = new URL('/docs', a); // correct +const c = new URL('/docs', 'http://flowtype.org/'); // correct + +const d: URLSearchParams = c.searchParams; // correct +const e: string = c.path; // not correct +const f: string = c.pathname; // correct +const g: string = c.hash; // correct +const h: string = c.host; // correct +const i: string = c.hostname; // correct +const j: string = c.href; // correct +const l: string = c.origin; // correct +const m: string = c.password; // correct +const n: string = c.pathname; // correct +const o: string = c.port; // correct +const p: string = c.protocol; // correct +const q: string = c.search; // correct +const r: string = c.username; // correct diff --git a/tests/dom/__snapshots__/jsfmt.spec.js.snap b/tests/dom/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9e1cc90c0e46 --- /dev/null +++ b/tests/dom/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,700 @@ +exports[`test CanvasRenderingContext2D.js 1`] = ` +"// @flow + +let tests = [ + // fillRect + function(ctx: CanvasRenderingContext2D) { + ctx.fillRect(0, 0, 200, 100); + }, + + // moveTo + function(ctx: CanvasRenderingContext2D) { + ctx.moveTo(\'0\', \'1\'); // error: should be numbers + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // fillRect + function(ctx: CanvasRenderingContext2D) { + ctx.fillRect(0, 0, 200, 100); + }, + // moveTo + function(ctx: CanvasRenderingContext2D) { + ctx.moveTo(\"0\", \"1\");// error: should be numbers + } +]; + +" +`; + +exports[`test CustomEvent.js 1`] = ` +"// @flow + +let tests = [ + // CustomEvent + function(document: Document) { + const event = document.createEvent(\'CustomEvent\'); + event.initCustomEvent(\'butts\', true, false, { nice: 42 }); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // CustomEvent + function(document: Document) { + const event = document.createEvent(\"CustomEvent\"); + event.initCustomEvent(\"butts\", true, false, { nice: 42 }); + } +]; + +" +`; + +exports[`test Document.js 1`] = ` +"// @flow + +let tests = [ + // createElement + function(document: Document) { + (document.createElement(\'canvas\'): HTMLCanvasElement); + (document.createElement(\'link\'): HTMLLinkElement); + (document.createElement(\'option\'): HTMLOptionElement); + (document.createElement(\'select\'): HTMLSelectElement); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // createElement + function(document: Document) { + (document.createElement(\"canvas\"): HTMLCanvasElement); + (document.createElement(\"link\"): HTMLLinkElement); + (document.createElement(\"option\"): HTMLOptionElement); + (document.createElement(\"select\"): HTMLSelectElement); + } +]; + +" +`; + +exports[`test Element.js 1`] = ` +"// @flow + +let tests = [ + // scrollIntoView + function(element: Element) { + element.scrollIntoView(); + element.scrollIntoView(false); + element.scrollIntoView({}); + element.scrollIntoView({ behavior: \'smooth\', block: \'end\' }); + element.scrollIntoView({ block: \'end\' }); + element.scrollIntoView({ behavior: \'smooth\' }); + + // fails + element.scrollIntoView({ behavior: \'invalid\' }); + element.scrollIntoView({ block: \'invalid\' }); + element.scrollIntoView(1); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // scrollIntoView + function(element: Element) { + element.scrollIntoView(); + element.scrollIntoView(false); + element.scrollIntoView({}); + element.scrollIntoView({ behavior: \"smooth\", block: \"end\" }); + element.scrollIntoView({ block: \"end\" }); + element.scrollIntoView({ behavior: \"smooth\" }); + // fails + element.scrollIntoView({ behavior: \"invalid\" }); + element.scrollIntoView({ block: \"invalid\" }); + element.scrollIntoView(1); + } +]; + +" +`; + +exports[`test HTMLCanvasElement.js 1`] = ` +"// @flow + +let tests = [ + // getContext + function(el: HTMLCanvasElement) { + (el.getContext(\'2d\'): ?CanvasRenderingContext2D); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // getContext + function(el: HTMLCanvasElement) { + (el.getContext(\"2d\"): ?CanvasRenderingContext2D); + } +]; + +" +`; + +exports[`test HTMLElement.js 1`] = ` +"// @flow + +let tests = [ + // scrollIntoView + function(element: HTMLElement) { + element.scrollIntoView(); + element.scrollIntoView(false); + element.scrollIntoView({}); + element.scrollIntoView({ behavior: \'smooth\', block: \'end\' }); + element.scrollIntoView({ block: \'end\' }); + element.scrollIntoView({ behavior: \'smooth\' }); + + // fails + element.scrollIntoView({ behavior: \'invalid\' }); + element.scrollIntoView({ block: \'invalid\' }); + element.scrollIntoView(1); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // scrollIntoView + function(element: HTMLElement) { + element.scrollIntoView(); + element.scrollIntoView(false); + element.scrollIntoView({}); + element.scrollIntoView({ behavior: \"smooth\", block: \"end\" }); + element.scrollIntoView({ block: \"end\" }); + element.scrollIntoView({ behavior: \"smooth\" }); + // fails + element.scrollIntoView({ behavior: \"invalid\" }); + element.scrollIntoView({ block: \"invalid\" }); + element.scrollIntoView(1); + } +]; + +" +`; + +exports[`test HTMLInputElement.js 1`] = ` +"// @flow + +let tests = [ + // setRangeText + function(el: HTMLInputElement) { + el.setRangeText(\'foo\'); + el.setRangeText(\'foo\', 123); // end is required + el.setRangeText(\'foo\', 123, 234); + el.setRangeText(\'foo\', 123, 234, \'select\'); + el.setRangeText(\'foo\', 123, 234, \'bogus\'); // invalid value + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // setRangeText + function(el: HTMLInputElement) { + el.setRangeText(\"foo\"); + el.setRangeText(\"foo\", 123);// end is required + el.setRangeText(\"foo\", 123, 234); + el.setRangeText(\"foo\", 123, 234, \"select\"); + el.setRangeText(\"foo\", 123, 234, \"bogus\");// invalid value + } +]; + +" +`; + +exports[`test URL.js 1`] = ` +"/* @flow */ + +const a = new URL(\'http://flowtype.org/\'); // correct +const b = new URL(\'/docs\', a); // correct +const c = new URL(\'/docs\', \'http://flowtype.org/\'); // correct + +const d: URLSearchParams = c.searchParams; // correct +const e: string = c.path; // not correct +const f: string = c.pathname; // correct +const g: string = c.hash; // correct +const h: string = c.host; // correct +const i: string = c.hostname; // correct +const j: string = c.href; // correct +const l: string = c.origin; // correct +const m: string = c.password; // correct +const n: string = c.pathname; // correct +const o: string = c.port; // correct +const p: string = c.protocol; // correct +const q: string = c.search; // correct +const r: string = c.username; // correct +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +const a = new URL(\"http://flowtype.org/\");// correct +const b = new URL(\"/docs\", a);// correct +const c = new URL(\"/docs\", \"http://flowtype.org/\");// correct +const d: URLSearchParams = c.searchParams;// correct +const e: string = c.path;// not correct +const f: string = c.pathname;// correct +const g: string = c.hash;// correct +const h: string = c.host;// correct +const i: string = c.hostname;// correct +const j: string = c.href;// correct +const l: string = c.origin;// correct +const m: string = c.password;// correct +const n: string = c.pathname;// correct +const o: string = c.port;// correct +const p: string = c.protocol;// correct +const q: string = c.search;// correct +const r: string = c.username;// correct + +" +`; + +exports[`test eventtarget.js 1`] = ` +"// @flow + +let listener: EventListener = function (event: Event) :void {}; + +let tests = [ + // attachEvent + function() { + let target = new EventTarget(); + (target.attachEvent(\'foo\', listener): void); // invalid, may be undefined + (target.attachEvent && target.attachEvent(\'foo\', listener): void); // valid + }, + + // detachEvent + function() { + let target = new EventTarget(); + (target.detachEvent(\'foo\', listener): void); // invalid, may be undefined + (target.detachEvent && target.detachEvent(\'foo\', listener): void); // valid + }, + + function() { + window.onmessage = (event: MessageEvent) => { + (event.target: window); + }; + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let listener: EventListener = function(event: Event): void { + +}; +let tests = [ + // attachEvent + function() { + let target = new EventTarget(); + (target.attachEvent(\"foo\", listener): void);// invalid, may be undefined + (target.attachEvent && target.attachEvent(\"foo\", listener): void);// valid + }, + // detachEvent + function() { + let target = new EventTarget(); + (target.detachEvent(\"foo\", listener): void);// invalid, may be undefined + (target.detachEvent && target.detachEvent(\"foo\", listener): void);// valid + }, + function() { + window.onmessage = (event: MessageEvent) => { + (event.target: window); + }; + } +]; + +" +`; + +exports[`test path2d.js 1`] = ` +"// @flow + +let tests = [ + // arcTo + function() { + let path = new Path2D(); + (path.arcTo(0, 0, 0, 0, 10): void); // valid + (path.arcTo(0, 0, 0, 0, 10, 20, 5): void); // valid + (path.arcTo(0, 0, 0, 0, 10, \'20\', 5): void); // invalid + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // arcTo + function() { + let path = new Path2D(); + (path.arcTo(0, 0, 0, 0, 10): void);// valid + (path.arcTo(0, 0, 0, 0, 10, 20, 5): void);// valid + (path.arcTo(0, 0, 0, 0, 10, \"20\", 5): void);// invalid + } +]; + +" +`; + +exports[`test registerElement.js 1`] = ` +"// @flow + +let tests = [ + // should work with Object.create() + function() { + document.registerElement(\'custom-element\', { + prototype: Object.create(HTMLElement.prototype, { + createdCallback: { value: function createdCallback () { + }}, + attachedCallback: { value: function attachedCallback () { + }}, + detachedCallback: { value: function detachedCallback () { + }}, + attributeChangedCallback: { + value: function attributeChangedCallback ( + attributeLocalName, + oldAttributeValue, + newAttributeValue, + attributeNamespace + ) { + } + } + }) + }) + }, + // or with Object.assign() + function() { + document.registerElement(\'custom-element\', { + prototype: Object.assign(Object.create(HTMLElement.prototype), { + createdCallback () { + }, + attachedCallback () { + }, + detachedCallback () { + }, + attributeChangedCallback ( + attributeLocalName, + oldAttributeValue, + newAttributeValue, + attributeNamespace + ) { + } + }) + }) + }, + // should complain about invalid callback parameters + function() { + document.registerElement(\'custom-element\', { + prototype: { + attributeChangedCallback( + localName: string, + oldVal: string, // Error: This might be null + newVal: string, // Error: This might be null + namespace: string) {} + }, + }); + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // should work with Object.create() + function() { + document.registerElement( + \"custom-element\", + { + prototype: Object.create( + HTMLElement.prototype, + { + createdCallback: { + value: function createdCallback() { + + } + }, + attachedCallback: { + value: function attachedCallback() { + + } + }, + detachedCallback: { + value: function detachedCallback() { + + } + }, + attributeChangedCallback: { + value: function attributeChangedCallback( + attributeLocalName, + oldAttributeValue, + newAttributeValue, + attributeNamespace + ) { + + } + } + } + ) + } + ); + }, + // or with Object.assign() + function() { + document.registerElement( + \"custom-element\", + { + prototype: Object.assign( + Object.create(HTMLElement.prototype), + { + createdCallback() { + + }, + attachedCallback() { + + }, + detachedCallback() { + + }, + attributeChangedCallback(attributeLocalName, + oldAttributeValue, + newAttributeValue, + attributeNamespace) { + + } + } + ) + } + ); + }, + // should complain about invalid callback parameters + function() { + document.registerElement( + \"custom-element\", + { + prototype: { + attributeChangedCallback(localName: string, + // Error: This might be null + oldVal: string, + // Error: This might be null + newVal: string, + namespace: string) { + + } + } + } + ); + } +]; + +" +`; + +exports[`test traversal.js 1`] = ` +"// @flow + +let tests = [ + // basic functionality + function() { + const i: NodeIterator<*,*> = document.createNodeIterator(document.body); + const filter: NodeFilter = i.filter; + const response: + typeof NodeFilter.FILTER_ACCEPT | + typeof NodeFilter.FILTER_REJECT | + typeof NodeFilter.FILTER_SKIP = + filter.acceptNode(document.body); + }, + function() { + const w: TreeWalker<*,*> = document.createTreeWalker(document.body); + const filter: NodeFilter = w.filter; + const response: + typeof NodeFilter.FILTER_ACCEPT | + typeof NodeFilter.FILTER_REJECT | + typeof NodeFilter.FILTER_SKIP = + filter.acceptNode(document.body); + }, + // rootNode must be a Node + function() { + document.createNodeIterator(document.body); // valid + document.createNodeIterator({}); // invalid + }, + function() { + document.createTreeWalker(document.body); + document.createTreeWalker({}); // invalid + }, + // Type Parameters + function() { + const _root = document.body; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_ELEMENT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Element = i.referenceNode; + const previousNode: Element | null = i.previousNode(); + const nextNode: Element | null = i.nextNode(); + }, + function() { + const _root = document.body.attributes[0]; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_ATTRIBUTE); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Attr = i.referenceNode + const previousNode: Attr | null = i.previousNode(); + const nextNode: Attr | null = i.nextNode(); + }, + function() { + const _root = document.body; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_TEXT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Text = i.referenceNode; + const previousNode: Text | null = i.previousNode(); + const nextNode: Text | null = i.nextNode(); + }, + function() { + const _root = document; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_DOCUMENT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Document = i.referenceNode; + const previousNode: Document | null = i.previousNode(); + const nextNode: Document | null = i.nextNode(); + }, + function() { + const _root = document; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_DOCUMENT_TYPE); + const root: typeof _root = i.root; + const referenceNode: typeof _root | DocumentType = i.referenceNode; + const previousNode: DocumentType | null = i.previousNode(); + const nextNode: DocumentType | null = i.nextNode(); + }, + function() { + const _root = document.createDocumentFragment(); + const i = document.createNodeIterator(_root, NodeFilter.SHOW_DOCUMENT_FRAGMENT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | DocumentFragment = i.referenceNode; + const previousNode: DocumentFragment | null = i.previousNode(); + const nextNode: DocumentFragment | null = i.nextNode(); + }, + function() { + const _root = document.body; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_ALL); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Node = i.referenceNode; + const previousNode: Node | null = i.previousNode(); + const nextNode: Node | null = i.nextNode(); + }, + function() { + const _root = document.body; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_ELEMENT); + const root: typeof _root = w.root; + const currentNode: typeof _root | Element = w.currentNode; + const parentNode: Element | null = w.parentNode(); + const firstChild: Element | null = w.firstChild(); + const lastChild: Element | null = w.lastChild(); + const previousSibling: Element | null = w.previousSibling(); + const nextSibling: Element | null = w.nextSibling(); + const previousNode: Element | null = w.previousNode(); + const nextNode: Element | null = w.nextNode(); + }, + function() { + const _root = document.body.attributes[0]; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_ATTRIBUTE); + const root: typeof _root = w.root; + const currentNode: typeof _root | Attr = w.currentNode; + const parentNode: Attr | null = w.parentNode(); + const firstChild: Attr | null = w.firstChild(); + const lastChild: Attr | null = w.lastChild(); + const previousSibling: Attr | null = w.previousSibling(); + const nextSibling: Attr | null = w.nextSibling(); + const previousNode: Attr | null = w.previousNode(); + const nextNode: Attr | null = w.nextNode(); + }, + function() { + const _root = document.body; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_TEXT); + const root: typeof _root = w.root; + const currentNode: typeof _root | Text = w.currentNode; + const parentNode: Text | null = w.parentNode(); + const firstChild: Text | null = w.firstChild(); + const lastChild: Text | null = w.lastChild(); + const previousSibling: Text | null = w.previousSibling(); + const nextSibling: Text | null = w.nextSibling(); + const previousNode: Text | null = w.previousNode(); + const nextNode: Text | null = w.nextNode(); + }, + function() { + const _root = document; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_DOCUMENT); + const root: typeof _root = w.root; + const currentNode: typeof _root | Document = w.currentNode; + const parentNode: Document | null = w.parentNode(); + const firstChild: Document | null = w.firstChild(); + const lastChild: Document | null = w.lastChild(); + const previousSibling: Document | null = w.previousSibling(); + const nextSibling: Document | null = w.nextSibling(); + const previousNode: Document | null = w.previousNode(); + const nextNode: Document | null = w.nextNode(); + }, + function() { + const _root = document; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_DOCUMENT_TYPE); + const root: typeof _root = w.root; + const currentNode: typeof _root | DocumentType = w.currentNode; + const parentNode: DocumentType | null = w.parentNode(); + const firstChild: DocumentType | null = w.firstChild(); + const lastChild: DocumentType | null = w.lastChild(); + const previousSibling: DocumentType | null = w.previousSibling(); + const nextSibling: DocumentType | null = w.nextSibling(); + const previousNode: DocumentType | null = w.previousNode(); + const nextNode: DocumentType | null = w.nextNode(); + }, + function() { + const _root = document.createDocumentFragment(); + const w = document.createTreeWalker(_root, NodeFilter.SHOW_DOCUMENT_FRAGMENT); + const root: typeof _root = w.root; + const currentNode: typeof _root | DocumentFragment = w.currentNode; + const parentNode: DocumentFragment | null = w.parentNode(); + const firstChild: DocumentFragment | null = w.firstChild(); + const lastChild: DocumentFragment | null = w.lastChild(); + const previousSibling: DocumentFragment | null = w.previousSibling(); + const nextSibling: DocumentFragment | null = w.nextSibling(); + const previousNode: DocumentFragment | null = w.previousNode(); + const nextNode: DocumentFragment | null = w.nextNode(); + }, + function() { + const _root = document.body; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_ALL); + const root: typeof _root = w.root; + const currentNode: typeof _root | Node = w.currentNode; + const parentNode: Node | null = w.parentNode(); + const firstChild: Node | null = w.firstChild(); + const lastChild: Node | null = w.lastChild(); + const previousSibling: Node | null = w.previousSibling(); + const nextSibling: Node | null = w.nextSibling(); + const previousNode: Node | null = w.previousNode(); + const nextNode: Node | null = w.nextNode(); + }, + // NodeFilterInterface + function() { + document.createNodeIterator(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid + document.createNodeIterator(document.body, -1, node => \'accept\'); // invalid + document.createNodeIterator(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid + document.createNodeIterator(document.body, -1, { accept: node => \'accept\' }); // invalid + document.createNodeIterator(document.body, -1, {}); // invalid + }, + function() { + document.createTreeWalker(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid + document.createTreeWalker(document.body, -1, node => \'accept\'); // invalid + document.createTreeWalker(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid + document.createTreeWalker(document.body, -1, { accept: node => \'accept\' }); // invalid + document.createTreeWalker(document.body, -1, {}); // invalid + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/dom/eventtarget.js b/tests/dom/eventtarget.js new file mode 100644 index 000000000000..42a732475a6b --- /dev/null +++ b/tests/dom/eventtarget.js @@ -0,0 +1,25 @@ +// @flow + +let listener: EventListener = function (event: Event) :void {}; + +let tests = [ + // attachEvent + function() { + let target = new EventTarget(); + (target.attachEvent('foo', listener): void); // invalid, may be undefined + (target.attachEvent && target.attachEvent('foo', listener): void); // valid + }, + + // detachEvent + function() { + let target = new EventTarget(); + (target.detachEvent('foo', listener): void); // invalid, may be undefined + (target.detachEvent && target.detachEvent('foo', listener): void); // valid + }, + + function() { + window.onmessage = (event: MessageEvent) => { + (event.target: window); + }; + }, +]; diff --git a/tests/dom/jsfmt.spec.js b/tests/dom/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/dom/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/dom/path2d.js b/tests/dom/path2d.js new file mode 100644 index 000000000000..5610e88c5343 --- /dev/null +++ b/tests/dom/path2d.js @@ -0,0 +1,11 @@ +// @flow + +let tests = [ + // arcTo + function() { + let path = new Path2D(); + (path.arcTo(0, 0, 0, 0, 10): void); // valid + (path.arcTo(0, 0, 0, 0, 10, 20, 5): void); // valid + (path.arcTo(0, 0, 0, 0, 10, '20', 5): void); // invalid + }, +]; diff --git a/tests/dom/registerElement.js b/tests/dom/registerElement.js new file mode 100644 index 000000000000..f42bec596fce --- /dev/null +++ b/tests/dom/registerElement.js @@ -0,0 +1,58 @@ +// @flow + +let tests = [ + // should work with Object.create() + function() { + document.registerElement('custom-element', { + prototype: Object.create(HTMLElement.prototype, { + createdCallback: { value: function createdCallback () { + }}, + attachedCallback: { value: function attachedCallback () { + }}, + detachedCallback: { value: function detachedCallback () { + }}, + attributeChangedCallback: { + value: function attributeChangedCallback ( + attributeLocalName, + oldAttributeValue, + newAttributeValue, + attributeNamespace + ) { + } + } + }) + }) + }, + // or with Object.assign() + function() { + document.registerElement('custom-element', { + prototype: Object.assign(Object.create(HTMLElement.prototype), { + createdCallback () { + }, + attachedCallback () { + }, + detachedCallback () { + }, + attributeChangedCallback ( + attributeLocalName, + oldAttributeValue, + newAttributeValue, + attributeNamespace + ) { + } + }) + }) + }, + // should complain about invalid callback parameters + function() { + document.registerElement('custom-element', { + prototype: { + attributeChangedCallback( + localName: string, + oldVal: string, // Error: This might be null + newVal: string, // Error: This might be null + namespace: string) {} + }, + }); + }, +]; diff --git a/tests/dom/traversal.js b/tests/dom/traversal.js new file mode 100644 index 000000000000..a78ae27468e3 --- /dev/null +++ b/tests/dom/traversal.js @@ -0,0 +1,195 @@ +// @flow + +let tests = [ + // basic functionality + function() { + const i: NodeIterator<*,*> = document.createNodeIterator(document.body); + const filter: NodeFilter = i.filter; + const response: + typeof NodeFilter.FILTER_ACCEPT | + typeof NodeFilter.FILTER_REJECT | + typeof NodeFilter.FILTER_SKIP = + filter.acceptNode(document.body); + }, + function() { + const w: TreeWalker<*,*> = document.createTreeWalker(document.body); + const filter: NodeFilter = w.filter; + const response: + typeof NodeFilter.FILTER_ACCEPT | + typeof NodeFilter.FILTER_REJECT | + typeof NodeFilter.FILTER_SKIP = + filter.acceptNode(document.body); + }, + // rootNode must be a Node + function() { + document.createNodeIterator(document.body); // valid + document.createNodeIterator({}); // invalid + }, + function() { + document.createTreeWalker(document.body); + document.createTreeWalker({}); // invalid + }, + // Type Parameters + function() { + const _root = document.body; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_ELEMENT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Element = i.referenceNode; + const previousNode: Element | null = i.previousNode(); + const nextNode: Element | null = i.nextNode(); + }, + function() { + const _root = document.body.attributes[0]; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_ATTRIBUTE); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Attr = i.referenceNode + const previousNode: Attr | null = i.previousNode(); + const nextNode: Attr | null = i.nextNode(); + }, + function() { + const _root = document.body; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_TEXT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Text = i.referenceNode; + const previousNode: Text | null = i.previousNode(); + const nextNode: Text | null = i.nextNode(); + }, + function() { + const _root = document; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_DOCUMENT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Document = i.referenceNode; + const previousNode: Document | null = i.previousNode(); + const nextNode: Document | null = i.nextNode(); + }, + function() { + const _root = document; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_DOCUMENT_TYPE); + const root: typeof _root = i.root; + const referenceNode: typeof _root | DocumentType = i.referenceNode; + const previousNode: DocumentType | null = i.previousNode(); + const nextNode: DocumentType | null = i.nextNode(); + }, + function() { + const _root = document.createDocumentFragment(); + const i = document.createNodeIterator(_root, NodeFilter.SHOW_DOCUMENT_FRAGMENT); + const root: typeof _root = i.root; + const referenceNode: typeof _root | DocumentFragment = i.referenceNode; + const previousNode: DocumentFragment | null = i.previousNode(); + const nextNode: DocumentFragment | null = i.nextNode(); + }, + function() { + const _root = document.body; + const i = document.createNodeIterator(_root, NodeFilter.SHOW_ALL); + const root: typeof _root = i.root; + const referenceNode: typeof _root | Node = i.referenceNode; + const previousNode: Node | null = i.previousNode(); + const nextNode: Node | null = i.nextNode(); + }, + function() { + const _root = document.body; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_ELEMENT); + const root: typeof _root = w.root; + const currentNode: typeof _root | Element = w.currentNode; + const parentNode: Element | null = w.parentNode(); + const firstChild: Element | null = w.firstChild(); + const lastChild: Element | null = w.lastChild(); + const previousSibling: Element | null = w.previousSibling(); + const nextSibling: Element | null = w.nextSibling(); + const previousNode: Element | null = w.previousNode(); + const nextNode: Element | null = w.nextNode(); + }, + function() { + const _root = document.body.attributes[0]; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_ATTRIBUTE); + const root: typeof _root = w.root; + const currentNode: typeof _root | Attr = w.currentNode; + const parentNode: Attr | null = w.parentNode(); + const firstChild: Attr | null = w.firstChild(); + const lastChild: Attr | null = w.lastChild(); + const previousSibling: Attr | null = w.previousSibling(); + const nextSibling: Attr | null = w.nextSibling(); + const previousNode: Attr | null = w.previousNode(); + const nextNode: Attr | null = w.nextNode(); + }, + function() { + const _root = document.body; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_TEXT); + const root: typeof _root = w.root; + const currentNode: typeof _root | Text = w.currentNode; + const parentNode: Text | null = w.parentNode(); + const firstChild: Text | null = w.firstChild(); + const lastChild: Text | null = w.lastChild(); + const previousSibling: Text | null = w.previousSibling(); + const nextSibling: Text | null = w.nextSibling(); + const previousNode: Text | null = w.previousNode(); + const nextNode: Text | null = w.nextNode(); + }, + function() { + const _root = document; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_DOCUMENT); + const root: typeof _root = w.root; + const currentNode: typeof _root | Document = w.currentNode; + const parentNode: Document | null = w.parentNode(); + const firstChild: Document | null = w.firstChild(); + const lastChild: Document | null = w.lastChild(); + const previousSibling: Document | null = w.previousSibling(); + const nextSibling: Document | null = w.nextSibling(); + const previousNode: Document | null = w.previousNode(); + const nextNode: Document | null = w.nextNode(); + }, + function() { + const _root = document; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_DOCUMENT_TYPE); + const root: typeof _root = w.root; + const currentNode: typeof _root | DocumentType = w.currentNode; + const parentNode: DocumentType | null = w.parentNode(); + const firstChild: DocumentType | null = w.firstChild(); + const lastChild: DocumentType | null = w.lastChild(); + const previousSibling: DocumentType | null = w.previousSibling(); + const nextSibling: DocumentType | null = w.nextSibling(); + const previousNode: DocumentType | null = w.previousNode(); + const nextNode: DocumentType | null = w.nextNode(); + }, + function() { + const _root = document.createDocumentFragment(); + const w = document.createTreeWalker(_root, NodeFilter.SHOW_DOCUMENT_FRAGMENT); + const root: typeof _root = w.root; + const currentNode: typeof _root | DocumentFragment = w.currentNode; + const parentNode: DocumentFragment | null = w.parentNode(); + const firstChild: DocumentFragment | null = w.firstChild(); + const lastChild: DocumentFragment | null = w.lastChild(); + const previousSibling: DocumentFragment | null = w.previousSibling(); + const nextSibling: DocumentFragment | null = w.nextSibling(); + const previousNode: DocumentFragment | null = w.previousNode(); + const nextNode: DocumentFragment | null = w.nextNode(); + }, + function() { + const _root = document.body; + const w = document.createTreeWalker(_root, NodeFilter.SHOW_ALL); + const root: typeof _root = w.root; + const currentNode: typeof _root | Node = w.currentNode; + const parentNode: Node | null = w.parentNode(); + const firstChild: Node | null = w.firstChild(); + const lastChild: Node | null = w.lastChild(); + const previousSibling: Node | null = w.previousSibling(); + const nextSibling: Node | null = w.nextSibling(); + const previousNode: Node | null = w.previousNode(); + const nextNode: Node | null = w.nextNode(); + }, + // NodeFilterInterface + function() { + document.createNodeIterator(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid + document.createNodeIterator(document.body, -1, node => 'accept'); // invalid + document.createNodeIterator(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid + document.createNodeIterator(document.body, -1, { accept: node => 'accept' }); // invalid + document.createNodeIterator(document.body, -1, {}); // invalid + }, + function() { + document.createTreeWalker(document.body, -1, node => NodeFilter.FILTER_ACCEPT); // valid + document.createTreeWalker(document.body, -1, node => 'accept'); // invalid + document.createTreeWalker(document.body, -1, { accept: node => NodeFilter.FILTER_ACCEPT }); // valid + document.createTreeWalker(document.body, -1, { accept: node => 'accept' }); // invalid + document.createTreeWalker(document.body, -1, {}); // invalid + }, +]; diff --git a/tests/dump-types/__snapshots__/jsfmt.spec.js.snap b/tests/dump-types/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..56a9c6930a86 --- /dev/null +++ b/tests/dump-types/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,58 @@ +exports[`test import.js 1`] = ` +"// @flow +var num = 42; +function bar() { } +bar(); +module.exports = num; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var num = 42; +function bar() { + +} +bar(); +module.exports = num; + +" +`; + +exports[`test test.js 1`] = ` +"// @flow +var num = require(\'./import\'); +function foo(x) { } +foo(0); +var a:string = num; + +function unannotated(x) { + return x; +} + +// test deduping of inferred types +const nullToUndefined = val => val === null ? undefined : val; + +function f0(x: ?Object) { return nullToUndefined(x); } +function f1(x: ?Object) { return nullToUndefined(x); } +function f2(x: ?string) { return nullToUndefined(x); } +function f3(x: ?string) { return nullToUndefined(x); } + +declare var idx: $Facebookism$Idx; +declare var obj: {a?: {b: ?{c: null | {d: number}}}}; +const idxResult = idx(obj, obj => obj.a.b.c.d); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/dump-types/import.js b/tests/dump-types/import.js new file mode 100644 index 000000000000..9a49778fd59d --- /dev/null +++ b/tests/dump-types/import.js @@ -0,0 +1,5 @@ +// @flow +var num = 42; +function bar() { } +bar(); +module.exports = num; diff --git a/tests/dump-types/jsfmt.spec.js b/tests/dump-types/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/dump-types/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/dump-types/test.js b/tests/dump-types/test.js new file mode 100644 index 000000000000..579402b464c0 --- /dev/null +++ b/tests/dump-types/test.js @@ -0,0 +1,21 @@ +// @flow +var num = require('./import'); +function foo(x) { } +foo(0); +var a:string = num; + +function unannotated(x) { + return x; +} + +// test deduping of inferred types +const nullToUndefined = val => val === null ? undefined : val; + +function f0(x: ?Object) { return nullToUndefined(x); } +function f1(x: ?Object) { return nullToUndefined(x); } +function f2(x: ?string) { return nullToUndefined(x); } +function f3(x: ?string) { return nullToUndefined(x); } + +declare var idx: $Facebookism$Idx; +declare var obj: {a?: {b: ?{c: null | {d: number}}}}; +const idxResult = idx(obj, obj => obj.a.b.c.d); diff --git a/tests/duplicate_methods/__snapshots__/jsfmt.spec.js.snap b/tests/duplicate_methods/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..01ab603de59f --- /dev/null +++ b/tests/duplicate_methods/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,88 @@ +exports[`test test.js 1`] = ` +"class C1 { + m() { } + m() { } +} + +new C1().m(); + +class C2 { + get m() { return 42; } + m() { } +} + +new C2().m(); + +class C3 { + set m(x) { } + m() { } +} + +new C3().m(); + +class C4 { + get m() { return 42; } + set m(x: number) { } +} + +new C4().m = new C4().m - 42; + +class C5 { + m() { } + get m() { return 42; } + set m(x: number) { } +} + +new C5().m = new C5().m - 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C1 { + m() { + + } + m() { + + } +} +new C1().m(); +class C2 { + get m() { + return 42; + } + m() { + + } +} +new C2().m(); +class C3 { + set m(x) { + + } + m() { + + } +} +new C3().m(); +class C4 { + get m() { + return 42; + } + set m(x: number) { + + } +} +new C4().m = new C4().m - 42; +class C5 { + m() { + + } + get m() { + return 42; + } + set m(x: number) { + + } +} +new C5().m = new C5().m - 42; + +" +`; diff --git a/tests/duplicate_methods/jsfmt.spec.js b/tests/duplicate_methods/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/duplicate_methods/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/duplicate_methods/test.js b/tests/duplicate_methods/test.js new file mode 100644 index 000000000000..3c2aa61999b7 --- /dev/null +++ b/tests/duplicate_methods/test.js @@ -0,0 +1,35 @@ +class C1 { + m() { } + m() { } +} + +new C1().m(); + +class C2 { + get m() { return 42; } + m() { } +} + +new C2().m(); + +class C3 { + set m(x) { } + m() { } +} + +new C3().m(); + +class C4 { + get m() { return 42; } + set m(x: number) { } +} + +new C4().m = new C4().m - 42; + +class C5 { + m() { } + get m() { return 42; } + set m(x: number) { } +} + +new C5().m = new C5().m - 42; diff --git a/tests/encaps/__snapshots__/jsfmt.spec.js.snap b/tests/encaps/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3277d93da996 --- /dev/null +++ b/tests/encaps/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,34 @@ +exports[`test encaps.js 1`] = ` +"class A { } +var a = new A(); +var s1 = \`l\${a.x}r\`; // error: no prop x in A + +function tag(strings,...values) { + var x:number = strings[0]; // error: string ~> number + return x; +} +var s2 = tag \`l\${42}r\`; + +function tag2(strings,...values) { + return { foo: "" }; // ok: tagged templates can return whatever +} + +var s3 = tag2 \`la la la\`; +(s3.foo: number); // error: string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A {} +var a = new A(); +var s1 = \`l\${a.x}r\`;// error: no prop x in A +function tag(strings, ...values) { + var x: number = strings[0];// error: string ~> number + return x; +} +var s2 = tag\`l\${42}r\`; +function tag2(strings, ...values) { + return { foo: "" };// ok: tagged templates can return whatever +} +var s3 = tag2\`la la la\`; +(s3.foo: number);// error: string ~> number + +" +`; diff --git a/tests/encaps/encaps.js b/tests/encaps/encaps.js new file mode 100644 index 000000000000..1f1127b42137 --- /dev/null +++ b/tests/encaps/encaps.js @@ -0,0 +1,16 @@ +class A { } +var a = new A(); +var s1 = `l${a.x}r`; // error: no prop x in A + +function tag(strings,...values) { + var x:number = strings[0]; // error: string ~> number + return x; +} +var s2 = tag `l${42}r`; + +function tag2(strings,...values) { + return { foo: "" }; // ok: tagged templates can return whatever +} + +var s3 = tag2 `la la la`; +(s3.foo: number); // error: string ~> number diff --git a/tests/encaps/jsfmt.spec.js b/tests/encaps/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/encaps/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/enumerror/__snapshots__/jsfmt.spec.js.snap b/tests/enumerror/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..77a0f8471311 --- /dev/null +++ b/tests/enumerror/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,45 @@ +exports[`test enumerror.js 1`] = ` +"/** @flow */ + +function isActive(ad: {state: $Keys<{ + PAUSED: string; + ACTIVE: string; + DELETED: string; +}>}): boolean { + return ad.state === \'ACTIVE\'; +}; +isActive({state: \'PAUSE\'}); + +var MyStates = { + PAUSED: \'PAUSED\', + ACTIVE: \'ACTIVE\', + DELETED: \'DELETED\', +}; +function isActive2(ad: {state: $Keys}): boolean { + return ad.state === MyStates.ACTIVE; +}; +isActive2({state: \'PAUSE\'}); + +type Keys = $Keys<{ x: any, y: any }>; +type Union = \"x\" | \"y\" + +function keys2union(s: Keys): Union { return s; } // ok +function union2keys(s: Union): Keys { return s; } // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/enumerror/enumerror.js b/tests/enumerror/enumerror.js new file mode 100644 index 000000000000..ea4d96907a0e --- /dev/null +++ b/tests/enumerror/enumerror.js @@ -0,0 +1,26 @@ +/** @flow */ + +function isActive(ad: {state: $Keys<{ + PAUSED: string; + ACTIVE: string; + DELETED: string; +}>}): boolean { + return ad.state === 'ACTIVE'; +}; +isActive({state: 'PAUSE'}); + +var MyStates = { + PAUSED: 'PAUSED', + ACTIVE: 'ACTIVE', + DELETED: 'DELETED', +}; +function isActive2(ad: {state: $Keys}): boolean { + return ad.state === MyStates.ACTIVE; +}; +isActive2({state: 'PAUSE'}); + +type Keys = $Keys<{ x: any, y: any }>; +type Union = "x" | "y" + +function keys2union(s: Keys): Union { return s; } // ok +function union2keys(s: Union): Keys { return s; } // ok diff --git a/tests/enumerror/jsfmt.spec.js b/tests/enumerror/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/enumerror/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/equals/__snapshots__/jsfmt.spec.js.snap b/tests/equals/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..450ed18fa059 --- /dev/null +++ b/tests/equals/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test equals.js 1`] = ` +"/* @flow */ + +(1 == 1); +("foo" == "bar"); +(1 == null); +(null == 1); +(1 == ""); // error +("" == 1); // error + +var x = (null : ?number); +(x == 1); +(1 == x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +1 == 1; +"foo" == "bar"; +1 == null; +null == 1; +1 == "";// error +"" == 1;// error +var x = (null: ?number); +x == 1; +1 == x; + +" +`; diff --git a/tests/equals/equals.js b/tests/equals/equals.js new file mode 100644 index 000000000000..0e1f7297cce6 --- /dev/null +++ b/tests/equals/equals.js @@ -0,0 +1,12 @@ +/* @flow */ + +(1 == 1); +("foo" == "bar"); +(1 == null); +(null == 1); +(1 == ""); // error +("" == 1); // error + +var x = (null : ?number); +(x == 1); +(1 == x); diff --git a/tests/equals/jsfmt.spec.js b/tests/equals/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/equals/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/error_messages/__snapshots__/jsfmt.spec.js.snap b/tests/error_messages/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..68bde87c7fcd --- /dev/null +++ b/tests/error_messages/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test errors.js 1`] = ` +"if (typeof define === 'function' && define.amd) { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +if (typeof define === "function" && define.amd) { + +} + +" +`; diff --git a/tests/error_messages/errors.js b/tests/error_messages/errors.js new file mode 100644 index 000000000000..6d1c725fc570 --- /dev/null +++ b/tests/error_messages/errors.js @@ -0,0 +1 @@ +if (typeof define === 'function' && define.amd) { } diff --git a/tests/error_messages/jsfmt.spec.js b/tests/error_messages/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/error_messages/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/es6modules/B.js b/tests/es6modules/B.js new file mode 100644 index 000000000000..e4d0f1b41f44 --- /dev/null +++ b/tests/es6modules/B.js @@ -0,0 +1,3 @@ +/* @flow */ + +exports.numberValue = 42; diff --git a/tests/es6modules/C.js b/tests/es6modules/C.js new file mode 100644 index 000000000000..e667c4717b69 --- /dev/null +++ b/tests/es6modules/C.js @@ -0,0 +1 @@ +/* @flow */ diff --git a/tests/es6modules/CommonJS_Clobbering_Class.js b/tests/es6modules/CommonJS_Clobbering_Class.js new file mode 100644 index 000000000000..4fbd96118432 --- /dev/null +++ b/tests/es6modules/CommonJS_Clobbering_Class.js @@ -0,0 +1,21 @@ +/** + * @providesModule CommonJS_Clobbering_Class + * @flow + */ + +class Base { + static baseProp: number; +} + +class Test extends Base { + static childProp: number; + + static staticNumber1():number { return 1; } + static staticNumber2():number { return 2; } + static staticNumber3():number { return 3; } + + instNumber1():number { return 1; } + instNumber2():number { return 2; } +}; + +module.exports = Test; diff --git a/tests/es6modules/CommonJS_Clobbering_Frozen.js b/tests/es6modules/CommonJS_Clobbering_Frozen.js new file mode 100644 index 000000000000..322f60abeee2 --- /dev/null +++ b/tests/es6modules/CommonJS_Clobbering_Frozen.js @@ -0,0 +1,8 @@ +/** + * @providesModule CommonJS_Clobbering_Frozen + * @flow + */ + +module.exports = Object.freeze({ + numberValue1: 1, +}); diff --git a/tests/es6modules/CommonJS_Clobbering_Lit.js b/tests/es6modules/CommonJS_Clobbering_Lit.js new file mode 100644 index 000000000000..991b7bc37c12 --- /dev/null +++ b/tests/es6modules/CommonJS_Clobbering_Lit.js @@ -0,0 +1,12 @@ +/** + * @providesModule CommonJS_Clobbering_Lit + * @flow + */ + +module.exports = { + numberValue1: 1, + numberValue2: 2, + numberValue3: 3, + numberValue4: 4, + numberValue5: 5 +}; diff --git a/tests/es6modules/CommonJS_Named.js b/tests/es6modules/CommonJS_Named.js new file mode 100644 index 000000000000..698ec4f05276 --- /dev/null +++ b/tests/es6modules/CommonJS_Named.js @@ -0,0 +1,10 @@ +/** + * @providesModule CommonJS_Named + * @flow + */ + +exports.numberValue1 = 1; +exports.numberValue2 = 2; +exports.numberValue3 = 3; +exports.numberValue4 = 4; +exports.numberValue5 = 5; diff --git a/tests/es6modules/ES6_DefaultAndNamed.js b/tests/es6modules/ES6_DefaultAndNamed.js new file mode 100644 index 000000000000..82df6c20aaa8 --- /dev/null +++ b/tests/es6modules/ES6_DefaultAndNamed.js @@ -0,0 +1,4 @@ +/* @flow */ + +export default 42; +export var str = 'asdf'; diff --git a/tests/es6modules/ES6_Default_AnonClass1.js b/tests/es6modules/ES6_Default_AnonClass1.js new file mode 100644 index 000000000000..2890acbb2843 --- /dev/null +++ b/tests/es6modules/ES6_Default_AnonClass1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_AnonClass1 + * @flow + */ + +export default class { givesANum(): number { return 42; }}; diff --git a/tests/es6modules/ES6_Default_AnonClass2.js b/tests/es6modules/ES6_Default_AnonClass2.js new file mode 100644 index 000000000000..1debca797b18 --- /dev/null +++ b/tests/es6modules/ES6_Default_AnonClass2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_AnonClass2 + * @flow + */ + +export default class { givesANum(): number { return 42; }}; diff --git a/tests/es6modules/ES6_Default_AnonFunction1.js b/tests/es6modules/ES6_Default_AnonFunction1.js new file mode 100644 index 000000000000..ab2e1bbd8721 --- /dev/null +++ b/tests/es6modules/ES6_Default_AnonFunction1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_AnonFunction1 + * @flow + */ + +export default function():number { return 42; } diff --git a/tests/es6modules/ES6_Default_AnonFunction2.js b/tests/es6modules/ES6_Default_AnonFunction2.js new file mode 100644 index 000000000000..2c60dbbe7c5c --- /dev/null +++ b/tests/es6modules/ES6_Default_AnonFunction2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_AnonFunction2 + * @flow + */ + +export default function():number { return 42; } diff --git a/tests/es6modules/ES6_Default_NamedClass1.js b/tests/es6modules/ES6_Default_NamedClass1.js new file mode 100644 index 000000000000..d903c252bca6 --- /dev/null +++ b/tests/es6modules/ES6_Default_NamedClass1.js @@ -0,0 +1,11 @@ +/** + * @providesModule ES6_Default_NamedClass1 + * @flow + */ + +export default class Foo { givesANum(): number { return 42; }}; + +// Regression test for https://github.com/facebook/flow/issues/511 +// +// Default-exported class should also be available in local scope +new Foo(); diff --git a/tests/es6modules/ES6_Default_NamedClass2.js b/tests/es6modules/ES6_Default_NamedClass2.js new file mode 100644 index 000000000000..a42af92016a6 --- /dev/null +++ b/tests/es6modules/ES6_Default_NamedClass2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_NamedClass2 + * @flow + */ + +export default class Foo { givesANum(): number { return 42; }}; diff --git a/tests/es6modules/ES6_Default_NamedFunction1.js b/tests/es6modules/ES6_Default_NamedFunction1.js new file mode 100644 index 000000000000..40fb4f30dda7 --- /dev/null +++ b/tests/es6modules/ES6_Default_NamedFunction1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_NamedFunction1 + * @flow + */ + +export default function foo():number { return 42; } diff --git a/tests/es6modules/ES6_Default_NamedFunction2.js b/tests/es6modules/ES6_Default_NamedFunction2.js new file mode 100644 index 000000000000..5f3b5e9e03e0 --- /dev/null +++ b/tests/es6modules/ES6_Default_NamedFunction2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_Default_NamedFunction2 + * @flow + */ + +export default function foo():number { return 42; } diff --git a/tests/es6modules/ES6_ExportAllFromMulti.js b/tests/es6modules/ES6_ExportAllFromMulti.js new file mode 100644 index 000000000000..9153402a64d5 --- /dev/null +++ b/tests/es6modules/ES6_ExportAllFromMulti.js @@ -0,0 +1,4 @@ +// @flow + +export * from "./ES6_ExportAllFrom_Source1"; +export * from "./ES6_ExportAllFrom_Source2"; diff --git a/tests/es6modules/ES6_ExportAllFrom_Intermediary1.js b/tests/es6modules/ES6_ExportAllFrom_Intermediary1.js new file mode 100644 index 000000000000..8d2469c08c42 --- /dev/null +++ b/tests/es6modules/ES6_ExportAllFrom_Intermediary1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Intermediary1 + * @flow + */ + +export * from "ES6_ExportAllFrom_Source1"; diff --git a/tests/es6modules/ES6_ExportAllFrom_Intermediary2.js b/tests/es6modules/ES6_ExportAllFrom_Intermediary2.js new file mode 100644 index 000000000000..fcd626b9f811 --- /dev/null +++ b/tests/es6modules/ES6_ExportAllFrom_Intermediary2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Intermediary2 + * @flow + */ + +export * from "ES6_ExportAllFrom_Source2"; diff --git a/tests/es6modules/ES6_ExportAllFrom_Source1.js b/tests/es6modules/ES6_ExportAllFrom_Source1.js new file mode 100644 index 000000000000..4eb8683774cf --- /dev/null +++ b/tests/es6modules/ES6_ExportAllFrom_Source1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Source1 + * @flow + */ + +export var numberValue1 = 1; diff --git a/tests/es6modules/ES6_ExportAllFrom_Source2.js b/tests/es6modules/ES6_ExportAllFrom_Source2.js new file mode 100644 index 000000000000..5616a706ecea --- /dev/null +++ b/tests/es6modules/ES6_ExportAllFrom_Source2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportAllFrom_Source2 + * @flow + */ + +export var numberValue2 = 1; diff --git a/tests/es6modules/ES6_ExportFrom_Intermediary1.js b/tests/es6modules/ES6_ExportFrom_Intermediary1.js new file mode 100644 index 000000000000..568cf963529e --- /dev/null +++ b/tests/es6modules/ES6_ExportFrom_Intermediary1.js @@ -0,0 +1,9 @@ +/** + * @providesModule ES6_ExportFrom_Intermediary1 + * @flow + */ + +export { + numberValue1, + numberValue2 as numberValue2_renamed +} from "ES6_ExportFrom_Source1"; diff --git a/tests/es6modules/ES6_ExportFrom_Intermediary2.js b/tests/es6modules/ES6_ExportFrom_Intermediary2.js new file mode 100644 index 000000000000..f4f62e4821e1 --- /dev/null +++ b/tests/es6modules/ES6_ExportFrom_Intermediary2.js @@ -0,0 +1,9 @@ +/** + * @providesModule ES6_ExportFrom_Intermediary2 + * @flow + */ + +export { + numberValue1, + numberValue2 as numberValue2_renamed2 +} from "ES6_ExportFrom_Source2"; diff --git a/tests/es6modules/ES6_ExportFrom_Source1.js b/tests/es6modules/ES6_ExportFrom_Source1.js new file mode 100644 index 000000000000..f41da3c58823 --- /dev/null +++ b/tests/es6modules/ES6_ExportFrom_Source1.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportFrom_Source1 + * @flow + */ + +export var numberValue1 = 1, numberValue2 = 2; diff --git a/tests/es6modules/ES6_ExportFrom_Source2.js b/tests/es6modules/ES6_ExportFrom_Source2.js new file mode 100644 index 000000000000..fd7541549551 --- /dev/null +++ b/tests/es6modules/ES6_ExportFrom_Source2.js @@ -0,0 +1,6 @@ +/** + * @providesModule ES6_ExportFrom_Source2 + * @flow + */ + +export var numberValue1 = 1, numberValue2 = 2; diff --git a/tests/es6modules/ES6_Named1.js b/tests/es6modules/ES6_Named1.js new file mode 100644 index 000000000000..2e71f0b72589 --- /dev/null +++ b/tests/es6modules/ES6_Named1.js @@ -0,0 +1,22 @@ +/** + * @providesModule ES6_Named1 + * @flow + */ + +var specifierNumber1 = 1; +var specifierNumber2 = 2; +var specifierNumber3 = 3; +var groupedSpecifierNumber1 = 1; +var groupedSpecifierNumber2 = 2; + +export {specifierNumber1}; +export {specifierNumber2 as specifierNumber2Renamed}; +export {specifierNumber3}; +export {groupedSpecifierNumber1, groupedSpecifierNumber2}; + +export function givesANumber(): number { return 42; }; +export class NumberGenerator { givesANumber(): number { return 42; }}; + +export var varDeclNumber1 = 1, varDeclNumber2 = 2; +export var {destructuredObjNumber} = {destructuredObjNumber: 1}; +export var [destructuredArrNumber] = [1] diff --git a/tests/es6modules/ES6_Named2.js b/tests/es6modules/ES6_Named2.js new file mode 100644 index 000000000000..4abc37e137ca --- /dev/null +++ b/tests/es6modules/ES6_Named2.js @@ -0,0 +1,20 @@ +/** + * @providesModule ES6_Named2 + * @flow + */ + +var specifierNumber4 = 1; +var specifierNumber5 = 2; +var groupedSpecifierNumber3 = 1; +var groupedSpecifierNumber4 = 2; + +export {specifierNumber4}; +export {specifierNumber5 as specifierNumber5Renamed}; +export {groupedSpecifierNumber3, groupedSpecifierNumber4}; + +export function givesANumber2(): number { return 42; }; +export class NumberGenerator2 { givesANumber(): number { return 42; }}; + +export var varDeclNumber3 = 1, varDeclNumber4 = 2; +export var {destructuredObjNumber2} = {destructuredObjNumber2: 1}; +export var [destructuredArrNumber2] = [1] diff --git a/tests/es6modules/ExportType.js b/tests/es6modules/ExportType.js new file mode 100644 index 000000000000..3949a39d32bf --- /dev/null +++ b/tests/es6modules/ExportType.js @@ -0,0 +1,3 @@ +// @flow + +export type typeAlias = number; diff --git a/tests/es6modules/ProvidesModuleA.js b/tests/es6modules/ProvidesModuleA.js new file mode 100644 index 000000000000..f2cbd52ce005 --- /dev/null +++ b/tests/es6modules/ProvidesModuleA.js @@ -0,0 +1,10 @@ +/** + * @providesModule A + * @flow + */ + +exports.numberValue1 = 42; +exports.numberValue2 = 42; +exports.numberValue3 = 42; +exports.numberValue4 = 42; +exports.stringValue = "str"; diff --git a/tests/es6modules/ProvidesModuleCJSDefault.js b/tests/es6modules/ProvidesModuleCJSDefault.js new file mode 100644 index 000000000000..a3d9c135a2c1 --- /dev/null +++ b/tests/es6modules/ProvidesModuleCJSDefault.js @@ -0,0 +1,8 @@ +/** + * @providesModule CJSDefault + * @flow + */ + +module.exports = { + numberValue: 42 +}; diff --git a/tests/es6modules/ProvidesModuleD.js b/tests/es6modules/ProvidesModuleD.js new file mode 100644 index 000000000000..a4d5ee842062 --- /dev/null +++ b/tests/es6modules/ProvidesModuleD.js @@ -0,0 +1,4 @@ +/** + * @providesModule D + * @flow + */ diff --git a/tests/es6modules/ProvidesModuleES6Default.js b/tests/es6modules/ProvidesModuleES6Default.js new file mode 100644 index 000000000000..636a1946109c --- /dev/null +++ b/tests/es6modules/ProvidesModuleES6Default.js @@ -0,0 +1,10 @@ +/** + * @providesModule ES6Default + * @flow + */ + +/* +export default { + numberValue: 42, +}; +*/ diff --git a/tests/es6modules/SideEffects.js b/tests/es6modules/SideEffects.js new file mode 100644 index 000000000000..e667c4717b69 --- /dev/null +++ b/tests/es6modules/SideEffects.js @@ -0,0 +1 @@ +/* @flow */ diff --git a/tests/es6modules/__snapshots__/jsfmt.spec.js.snap b/tests/es6modules/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7e854f72ac46 --- /dev/null +++ b/tests/es6modules/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,1297 @@ +exports[`test B.js 1`] = ` +"/* @flow */ + +exports.numberValue = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +exports.numberValue = 42; + +" +`; + +exports[`test C.js 1`] = ` +"/* @flow */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test CommonJS_Clobbering_Class.js 1`] = ` +"/** + * @providesModule CommonJS_Clobbering_Class + * @flow + */ + +class Base { + static baseProp: number; +} + +class Test extends Base { + static childProp: number; + + static staticNumber1():number { return 1; } + static staticNumber2():number { return 2; } + static staticNumber3():number { return 3; } + + instNumber1():number { return 1; } + instNumber2():number { return 2; } +}; + +module.exports = Test; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Clobbering_Class + * @flow + */ +class Base { + static baseProp: number; +} +class Test extends Base { + static childProp: number; + staticNumber1(): number { + return 1; + } + staticNumber2(): number { + return 2; + } + staticNumber3(): number { + return 3; + } + instNumber1(): number { + return 1; + } + instNumber2(): number { + return 2; + } +} +module.exports = Test; + +" +`; + +exports[`test CommonJS_Clobbering_Frozen.js 1`] = ` +"/** + * @providesModule CommonJS_Clobbering_Frozen + * @flow + */ + +module.exports = Object.freeze({ + numberValue1: 1, +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Clobbering_Frozen + * @flow + */ +module.exports = Object.freeze({ numberValue1: 1 }); + +" +`; + +exports[`test CommonJS_Clobbering_Lit.js 1`] = ` +"/** + * @providesModule CommonJS_Clobbering_Lit + * @flow + */ + +module.exports = { + numberValue1: 1, + numberValue2: 2, + numberValue3: 3, + numberValue4: 4, + numberValue5: 5 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Clobbering_Lit + * @flow + */ +module.exports = { + numberValue1: 1, + numberValue2: 2, + numberValue3: 3, + numberValue4: 4, + numberValue5: 5 +}; + +" +`; + +exports[`test CommonJS_Named.js 1`] = ` +"/** + * @providesModule CommonJS_Named + * @flow + */ + +exports.numberValue1 = 1; +exports.numberValue2 = 2; +exports.numberValue3 = 3; +exports.numberValue4 = 4; +exports.numberValue5 = 5; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CommonJS_Named + * @flow + */ +exports.numberValue1 = 1; +exports.numberValue2 = 2; +exports.numberValue3 = 3; +exports.numberValue4 = 4; +exports.numberValue5 = 5; + +" +`; + +exports[`test ES6_Default_AnonClass1.js 1`] = ` +"/** + * @providesModule ES6_Default_AnonClass1 + * @flow + */ + +export default class { givesANum(): number { return 42; }}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_AnonClass1 + * @flow + */ +export default class { + givesANum(): number { + return 42; + } +} + +" +`; + +exports[`test ES6_Default_AnonClass2.js 1`] = ` +"/** + * @providesModule ES6_Default_AnonClass2 + * @flow + */ + +export default class { givesANum(): number { return 42; }}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_AnonClass2 + * @flow + */ +export default class { + givesANum(): number { + return 42; + } +} + +" +`; + +exports[`test ES6_Default_AnonFunction1.js 1`] = ` +"/** + * @providesModule ES6_Default_AnonFunction1 + * @flow + */ + +export default function():number { return 42; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_AnonFunction1 + * @flow + */ +export default function(): number { + return 42; +} + +" +`; + +exports[`test ES6_Default_AnonFunction2.js 1`] = ` +"/** + * @providesModule ES6_Default_AnonFunction2 + * @flow + */ + +export default function():number { return 42; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_AnonFunction2 + * @flow + */ +export default function(): number { + return 42; +} + +" +`; + +exports[`test ES6_Default_NamedClass1.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedClass1 + * @flow + */ + +export default class Foo { givesANum(): number { return 42; }}; + +// Regression test for https://github.com/facebook/flow/issues/511 +// +// Default-exported class should also be available in local scope +new Foo(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_NamedClass1 + * @flow + */ +export default class Foo { + givesANum(): number { + return 42; + } +} +// Regression test for https://github.com/facebook/flow/issues/511 +// +// Default-exported class should also be available in local scope +new Foo(); + +" +`; + +exports[`test ES6_Default_NamedClass2.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedClass2 + * @flow + */ + +export default class Foo { givesANum(): number { return 42; }}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_NamedClass2 + * @flow + */ +export default class Foo { + givesANum(): number { + return 42; + } +} + +" +`; + +exports[`test ES6_Default_NamedFunction1.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedFunction1 + * @flow + */ + +export default function foo():number { return 42; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_NamedFunction1 + * @flow + */ +export default function foo(): number { + return 42; +} + +" +`; + +exports[`test ES6_Default_NamedFunction2.js 1`] = ` +"/** + * @providesModule ES6_Default_NamedFunction2 + * @flow + */ + +export default function foo():number { return 42; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_Default_NamedFunction2 + * @flow + */ +export default function foo(): number { + return 42; +} + +" +`; + +exports[`test ES6_DefaultAndNamed.js 1`] = ` +"/* @flow */ + +export default 42; +export var str = \'asdf\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +export default 42 +export var str = \"asdf\"; + +" +`; + +exports[`test ES6_ExportAllFrom_Intermediary1.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Intermediary1 + * @flow + */ + +export * from \"ES6_ExportAllFrom_Source1\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_ExportAllFrom_Intermediary1 + * @flow + */ +export * from \"ES6_ExportAllFrom_Source1\" + +" +`; + +exports[`test ES6_ExportAllFrom_Intermediary2.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Intermediary2 + * @flow + */ + +export * from \"ES6_ExportAllFrom_Source2\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_ExportAllFrom_Intermediary2 + * @flow + */ +export * from \"ES6_ExportAllFrom_Source2\" + +" +`; + +exports[`test ES6_ExportAllFrom_Source1.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Source1 + * @flow + */ + +export var numberValue1 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_ExportAllFrom_Source1 + * @flow + */ +export var numberValue1 = 1; + +" +`; + +exports[`test ES6_ExportAllFrom_Source2.js 1`] = ` +"/** + * @providesModule ES6_ExportAllFrom_Source2 + * @flow + */ + +export var numberValue2 = 1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_ExportAllFrom_Source2 + * @flow + */ +export var numberValue2 = 1; + +" +`; + +exports[`test ES6_ExportAllFromMulti.js 1`] = ` +"// @flow + +export * from \"./ES6_ExportAllFrom_Source1\"; +export * from \"./ES6_ExportAllFrom_Source2\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export * from \"./ES6_ExportAllFrom_Source1\" +export * from \"./ES6_ExportAllFrom_Source2\" + +" +`; + +exports[`test ES6_ExportFrom_Intermediary1.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Intermediary1 + * @flow + */ + +export { + numberValue1, + numberValue2 as numberValue2_renamed +} from \"ES6_ExportFrom_Source1\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test ES6_ExportFrom_Intermediary2.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Intermediary2 + * @flow + */ + +export { + numberValue1, + numberValue2 as numberValue2_renamed2 +} from \"ES6_ExportFrom_Source2\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test ES6_ExportFrom_Source1.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Source1 + * @flow + */ + +export var numberValue1 = 1, numberValue2 = 2; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_ExportFrom_Source1 + * @flow + */ +export var numberValue1 = 1numberValue2 = 2; + +" +`; + +exports[`test ES6_ExportFrom_Source2.js 1`] = ` +"/** + * @providesModule ES6_ExportFrom_Source2 + * @flow + */ + +export var numberValue1 = 1, numberValue2 = 2; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule ES6_ExportFrom_Source2 + * @flow + */ +export var numberValue1 = 1numberValue2 = 2; + +" +`; + +exports[`test ES6_Named1.js 1`] = ` +"/** + * @providesModule ES6_Named1 + * @flow + */ + +var specifierNumber1 = 1; +var specifierNumber2 = 2; +var specifierNumber3 = 3; +var groupedSpecifierNumber1 = 1; +var groupedSpecifierNumber2 = 2; + +export {specifierNumber1}; +export {specifierNumber2 as specifierNumber2Renamed}; +export {specifierNumber3}; +export {groupedSpecifierNumber1, groupedSpecifierNumber2}; + +export function givesANumber(): number { return 42; }; +export class NumberGenerator { givesANumber(): number { return 42; }}; + +export var varDeclNumber1 = 1, varDeclNumber2 = 2; +export var {destructuredObjNumber} = {destructuredObjNumber: 1}; +export var [destructuredArrNumber] = [1] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test ES6_Named2.js 1`] = ` +"/** + * @providesModule ES6_Named2 + * @flow + */ + +var specifierNumber4 = 1; +var specifierNumber5 = 2; +var groupedSpecifierNumber3 = 1; +var groupedSpecifierNumber4 = 2; + +export {specifierNumber4}; +export {specifierNumber5 as specifierNumber5Renamed}; +export {groupedSpecifierNumber3, groupedSpecifierNumber4}; + +export function givesANumber2(): number { return 42; }; +export class NumberGenerator2 { givesANumber(): number { return 42; }}; + +export var varDeclNumber3 = 1, varDeclNumber4 = 2; +export var {destructuredObjNumber2} = {destructuredObjNumber2: 1}; +export var [destructuredArrNumber2] = [1] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test ExportType.js 1`] = ` +"// @flow + +export type typeAlias = number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export type typeAlias = number; + +" +`; + +exports[`test ProvidesModuleA.js 1`] = ` +"/** + * @providesModule A + * @flow + */ + +exports.numberValue1 = 42; +exports.numberValue2 = 42; +exports.numberValue3 = 42; +exports.numberValue4 = 42; +exports.stringValue = \"str\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule A + * @flow + */ +exports.numberValue1 = 42; +exports.numberValue2 = 42; +exports.numberValue3 = 42; +exports.numberValue4 = 42; +exports.stringValue = \"str\"; + +" +`; + +exports[`test ProvidesModuleCJSDefault.js 1`] = ` +"/** + * @providesModule CJSDefault + * @flow + */ + +module.exports = { + numberValue: 42 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule CJSDefault + * @flow + */ +module.exports = { numberValue: 42 }; + +" +`; + +exports[`test ProvidesModuleD.js 1`] = ` +"/** + * @providesModule D + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test ProvidesModuleES6Default.js 1`] = ` +"/** + * @providesModule ES6Default + * @flow + */ + +/* +export default { + numberValue: 42, +}; +*/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test SideEffects.js 1`] = ` +"/* @flow */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test es6modules.js 1`] = ` +"/* @flow */ + +// ===================== // +// == Path Resolution == // +// ===================== // + +// @providesModule +import * as DefaultA from \"A\"; +var a1: number = DefaultA.numberValue1; +var a2: string = DefaultA.numberValue1; // Error: number ~> string + +// File path +import * as DefaultB from \"./B\"; +var b1: number = DefaultB.numberValue; +var b2: string = DefaultB.numberValue; // Error: number ~> string + +// C.js exists, but not as a providesModule +import DefaultC from \"C\"; // Error: No such module + +// @providesModule D exists, but not as a filename +import DefaultD from \"./D\"; // Error: No such module + +// ================================================ // +// == CommonJS Clobbering Literal Exports -> ES6 == // +// ================================================ // + +import {doesntExist1} from \"CommonJS_Clobbering_Lit\"; // Error: Not an exported binding + +import {numberValue1} from \"CommonJS_Clobbering_Lit\"; +var c1: number = numberValue1; +var c2: string = numberValue1; // Error: number ~> string + +import {numberValue2 as numVal1} from \"CommonJS_Clobbering_Lit\"; +var d1: number = numVal1; +var d2: string = numVal1; // Error: number ~> string + +import CJS_Clobb_Lit from \"CommonJS_Clobbering_Lit\"; +var e1: number = CJS_Clobb_Lit.numberValue3; +var e2: string = CJS_Clobb_Lit.numberValue3; // Error: number ~> string +CJS_Clobb_Lit.doesntExist; // Error: doesntExist isn\'t a property + +import * as CJS_Clobb_Lit_NS from \"CommonJS_Clobbering_Lit\"; +var f1: number = CJS_Clobb_Lit_NS.numberValue4; +var f2: number = CJS_Clobb_Lit_NS.default.numberValue4; +CJS_Clobb_Lit_NS.default.default; // Error: No \'default\' property on the exported obj +var f3: string = CJS_Clobb_Lit_NS.numberValue4; // Error: number ~> string +var f4: string = CJS_Clobb_Lit_NS.default.numberValue5; // Error: number ~> string + +// ============================================== // +// == CommonJS Clobbering Class Exports -> ES6 == // +// ============================================== // + +import {doesntExist2} from \"CommonJS_Clobbering_Class\"; // Error: Not an exported binding + +// The following import should error because class statics are not turned into +// named exports for now. This avoids complexities with polymorphic static +// members (where the polymophism is defined on the class itself rather than the +// method). +import {staticNumber1, baseProp, childProp} from \"CommonJS_Clobbering_Class\"; // Error + +import CJS_Clobb_Class from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class(); +new CJS_Clobb_Class().doesntExist; // Error: Class has no \`doesntExist\` property +var h1: number = CJS_Clobb_Class.staticNumber2(); +var h2: string = CJS_Clobb_Class.staticNumber2(); // Error: number ~> string +var h3: number = new CJS_Clobb_Class().instNumber1(); +var h4: string = new CJS_Clobb_Class().instNumber1(); // Error: number ~> string + +import * as CJS_Clobb_Class_NS from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class_NS(); // Error: Namespace object isn\'t constructable +var i1: number = CJS_Clobb_Class_NS.staticNumber3(); // Error: Class statics not copied to Namespace object +var i2: number = new CJS_Clobb_Class_NS.default().instNumber2(); +var i3: string = new CJS_Clobb_Class_NS.default().instNumber2(); // Error: number ~> string + +// =================================== // +// == CommonJS Named Exports -> ES6 == // +// =================================== // + +import {doesntExist3} from \"CommonJS_Named\"; // Error: Not an exported binding + +import {numberValue2} from \"CommonJS_Named\"; +var j1: number = numberValue2; +var j2: string = numberValue2; // Error: number ~> string + +import {numberValue3 as numVal3} from \"CommonJS_Named\"; +var k1: number = numVal3; +var k2: string = numVal3; // Error: number ~> string + +import * as CJS_Named from \"CommonJS_Named\"; +var l1: number = CJS_Named.numberValue1; +var l2: string = CJS_Named.numberValue1; // Error: number ~> string +CJS_Named.doesntExist; // Error: doesntExist isn\'t a property + +import * as CJS_Named_NS from \"CommonJS_Named\"; +var m1: number = CJS_Named_NS.numberValue4; +var m2: string = CJS_Named_NS.default.numberValue4; // Error: CommonJS_Named has no default export +var m3: string = CJS_Named_NS.numberValue4; // Error: number ~> string + +////////////////////////////// +// == ES6 Default -> ES6 == // +////////////////////////////// + +import {doesntExist4} from \"ES6_Default_AnonFunction1\"; // Error: Not an exported binding + +import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\"; +var n1: number = ES6_Def_AnonFunc1(); +var n2: string = ES6_Def_AnonFunc1(); // Error: number ~> string + +import ES6_Def_NamedFunc1 from \"ES6_Default_NamedFunction1\"; +var o1: number = ES6_Def_NamedFunc1(); +var o2: string = ES6_Def_NamedFunc1(); // Error: number ~> string + +import ES6_Def_AnonClass1 from \"ES6_Default_AnonClass1\"; +var p1: number = new ES6_Def_AnonClass1().givesANum(); +var p2: string = new ES6_Def_AnonClass1().givesANum(); // Error: number ~> string + +import ES6_Def_NamedClass1 from \"ES6_Default_NamedClass1\"; +var q1: number = new ES6_Def_NamedClass1().givesANum(); +var q2: string = new ES6_Def_NamedClass1().givesANum(); // Error: number ~> string + +//////////////////////////// +// == ES6 Named -> ES6 == // +//////////////////////////// + +import doesntExist5 from \"ES6_Named1\"; // Error: Not an exported binding + +import {specifierNumber1 as specifierNumber1_1} from \"ES6_Named1\"; +var r1: number = specifierNumber1_1; +var r2: string = specifierNumber1_1; // Error: number ~> string + +import {specifierNumber2Renamed} from \"ES6_Named1\"; +var s1: number = specifierNumber2Renamed; +var s2: string = specifierNumber2Renamed; // Error: number ~> string + +import {specifierNumber3 as specifierNumber3Renamed} from \"ES6_Named1\"; +var t1: number = specifierNumber3Renamed; +var t2: string = specifierNumber3Renamed; // Error: number ~> string + +import {groupedSpecifierNumber1, groupedSpecifierNumber2} from \"ES6_Named1\"; +var u1: number = groupedSpecifierNumber1; +var u2: number = groupedSpecifierNumber2; +var u3: string = groupedSpecifierNumber1; // Error: number ~> string +var u4: string = groupedSpecifierNumber2; // Error: number ~> string + +import {givesANumber} from \"ES6_Named1\"; +var v1: number = givesANumber(); +var v2: string = givesANumber(); // Error: number ~> string + +import {NumberGenerator} from \"ES6_Named1\"; +var w1: number = new NumberGenerator().givesANumber(); +var w2: string = new NumberGenerator().givesANumber(); // Error: number ~> string + +import {varDeclNumber1, varDeclNumber2} from \"ES6_Named1\"; +var x1: number = varDeclNumber1; +var x2: number = varDeclNumber2; +var x3: string = varDeclNumber1; // Error: number ~> string +var x4: string = varDeclNumber2; // Error: number ~> string + +import {destructuredObjNumber} from \"ES6_Named1\"; +var y1: number = destructuredObjNumber; +var y2: string = destructuredObjNumber; // Error: number ~> string + +import {destructuredArrNumber} from \"ES6_Named1\"; +var z1: number = destructuredArrNumber; +var z2: string = destructuredArrNumber; // Error: number ~> string + +import {numberValue1 as numberValue4} from \"ES6_ExportFrom_Intermediary1\"; +var aa1: number = numberValue4; +var aa2: string = numberValue4; // Error: number ~> string + +import {numberValue2_renamed} from \"ES6_ExportFrom_Intermediary1\"; +var ab1: number = numberValue2_renamed; +var ab2: string = numberValue2_renamed; // Error: number ~> string + +import {numberValue1 as numberValue5} from \"ES6_ExportAllFrom_Intermediary1\"; +var ac1: number = numberValue5; +var ac2: string = numberValue5; // Error: number ~> string + +/////////////////////////////////// +// == ES6 Default -> CommonJS == // +/////////////////////////////////// + +require(\'ES6_Default_AnonFunction2\').doesntExist; // Error: \'doesntExist\' isn\'t an export + +var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default; +var ad1: number = ES6_Def_AnonFunc2(); +var ad2: string = ES6_Def_AnonFunc2(); // Error: number ~> string + +var ES6_Def_NamedFunc2 = require(\"ES6_Default_NamedFunction2\").default; +var ae1: number = ES6_Def_NamedFunc2(); +var ae2: string = ES6_Def_NamedFunc2(); // Error: number ~> string + +var ES6_Def_AnonClass2 = require(\"ES6_Default_AnonClass2\").default; +var af1: number = new ES6_Def_AnonClass2().givesANum(); +var af2: string = new ES6_Def_AnonClass2().givesANum(); // Error: number ~> string + +var ES6_Def_NamedClass2 = require(\"ES6_Default_NamedClass2\").default; +var ag1: number = new ES6_Def_NamedClass2().givesANum(); +var ag2: string = new ES6_Def_NamedClass2().givesANum(); // Error: number ~> string + +///////////////////////////////// +// == ES6 Named -> CommonJS == // +///////////////////////////////// + +var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4; +var ah1: number = specifierNumber4; +var ah2: string = specifierNumber4; // Error: number ~> string + +var specifierNumber5Renamed = require(\"ES6_Named2\").specifierNumber5Renamed; +var ai1: number = specifierNumber5Renamed; +var ai2: string = specifierNumber5Renamed; // Error: number ~> string + +var groupedSpecifierNumber3 = require(\"ES6_Named2\").groupedSpecifierNumber3; +var groupedSpecifierNumber4 = require(\"ES6_Named2\").groupedSpecifierNumber4; +var aj1: number = groupedSpecifierNumber3; +var aj2: number = groupedSpecifierNumber4; +var aj3: string = groupedSpecifierNumber3; // Error: number ~> string +var aj4: string = groupedSpecifierNumber4; // Error: number ~> string + +var givesANumber2 = require(\"ES6_Named2\").givesANumber2; +var ak1: number = givesANumber2(); +var ak2: string = givesANumber2(); // Error: number ~> string + +var NumberGenerator2 = require(\"ES6_Named2\").NumberGenerator2; +var al1: number = new NumberGenerator2().givesANumber(); +var al2: string = new NumberGenerator2().givesANumber(); // Error: number ~> string + +var varDeclNumber3 = require(\"ES6_Named2\").varDeclNumber3; +var varDeclNumber4 = require(\"ES6_Named2\").varDeclNumber4; +var am1: number = varDeclNumber3; +var am2: number = varDeclNumber4; +var am3: string = varDeclNumber3; // Error: number ~> string +var am4: string = varDeclNumber4; // Error: number ~> string + +var destructuredObjNumber2 = require(\"ES6_Named2\").destructuredObjNumber2; +var an1: number = destructuredObjNumber2; +var an2: string = destructuredObjNumber2; // Error: number ~> string + +var destructuredArrNumber2 = require(\"ES6_Named2\").destructuredArrNumber2; +var ao1: number = destructuredArrNumber2; +var ao2: string = destructuredArrNumber2; // Error: number ~> string + +var numberValue6 = require(\"ES6_ExportFrom_Intermediary2\").numberValue1; +var ap1: number = numberValue6; +var ap2: string = numberValue6; // Error: number ~> string + +var numberValue2_renamed2 = require(\"ES6_ExportFrom_Intermediary2\").numberValue2_renamed2; +var aq1: number = numberValue2_renamed2; +var aq2: string = numberValue2_renamed2; // Error: number ~> string + +var numberValue7 = require(\"ES6_ExportAllFrom_Intermediary2\").numberValue2; +var ar1: number = numberValue7; +var ar2: string = numberValue7; // Error: number ~> string + +//////////////////////////////////////////////////////// +// == ES6 Default+Named -> ES6 import Default+Named== // +//////////////////////////////////////////////////////// + +import defaultNum, {str as namedStr} from \"./ES6_DefaultAndNamed\"; + +var as1: number = defaultNum; +var as2: string = defaultNum; // Error: number ~> string + +var as3: string = namedStr; +var as4: number = namedStr; // Error: string ~> number + +//////////////////////////////////////// +// == Side-effect only ES6 imports == // +//////////////////////////////////////// + +import \"./SideEffects\"; + +////////////////////////////////////////////// +// == Suggest export name on likely typo == // +////////////////////////////////////////////// +import specifierNumber1 from \"ES6_Named1\"; // Error: Did you mean \`import {specifierNumber1} from ...\`? +import {specifierNumber} from \"ES6_Named1\"; // Error: Did you mean \`specifierNumber1\`? + +/////////////////////////////////////////////////// +// == Multi \`export *\` should combine exports == // +/////////////////////////////////////////////////// +import { + numberValue1 as numberValue8, + numberValue2 as numberValue9 +} from \"./ES6_ExportAllFromMulti\"; + +var at1: number = numberValue8; +var at2: string = numberValue8; // Error: number ~> string + +var at3: number = numberValue9; +var at4: string = numberValue9; // Error: number ~> string + +///////////////////////////////////////////////////////////// +// == Vanilla \`import\` cannot import a type-only export == // +///////////////////////////////////////////////////////////// +import {typeAlias} from \"./ExportType\"; // Error: Cannot vanilla-import a type alias! +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// ===================== // +// == Path Resolution == // +// ===================== // +// @providesModule +import * as DefaultA from \"A\"; +var a1: number = DefaultA.numberValue1; +var a2: string = DefaultA.numberValue1;// Error: number ~> string +// File path +import * as DefaultB from \"./B\"; +var b1: number = DefaultB.numberValue; +var b2: string = DefaultB.numberValue;// Error: number ~> string +// C.js exists, but not as a providesModule +import DefaultC from \"C\";// Error: No such module +// @providesModule D exists, but not as a filename +import DefaultD from \"./D\";// Error: No such module +// ================================================ // +// == CommonJS Clobbering Literal Exports -> ES6 == // +// ================================================ // +import { doesntExist1 } from \"CommonJS_Clobbering_Lit\";// Error: Not an exported binding +import { numberValue1 } from \"CommonJS_Clobbering_Lit\"; +var c1: number = numberValue1; +var c2: string = numberValue1;// Error: number ~> string +import { numberValue2 as numVal1 } from \"CommonJS_Clobbering_Lit\"; +var d1: number = numVal1; +var d2: string = numVal1;// Error: number ~> string +import CJS_Clobb_Lit from \"CommonJS_Clobbering_Lit\"; +var e1: number = CJS_Clobb_Lit.numberValue3; +var e2: string = CJS_Clobb_Lit.numberValue3;// Error: number ~> string +CJS_Clobb_Lit.doesntExist;// Error: doesntExist isn\'t a property +import * as CJS_Clobb_Lit_NS from \"CommonJS_Clobbering_Lit\"; +var f1: number = CJS_Clobb_Lit_NS.numberValue4; +var f2: number = CJS_Clobb_Lit_NS.default.numberValue4; +CJS_Clobb_Lit_NS.default.default;// Error: No \'default\' property on the exported obj +var f3: string = CJS_Clobb_Lit_NS.numberValue4;// Error: number ~> string +var f4: string = CJS_Clobb_Lit_NS.default.numberValue5;// Error: number ~> string +// ============================================== // +// == CommonJS Clobbering Class Exports -> ES6 == // +// ============================================== // +import { doesntExist2 } from \"CommonJS_Clobbering_Class\";// Error: Not an exported binding +// The following import should error because class statics are not turned into +// named exports for now. This avoids complexities with polymorphic static +// members (where the polymophism is defined on the class itself rather than the +// method). +import { staticNumber1, baseProp, childProp } from \"CommonJS_Clobbering_Class\";// Error +import CJS_Clobb_Class from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class(); +new CJS_Clobb_Class().doesntExist;// Error: Class has no \`doesntExist\` property +var h1: number = CJS_Clobb_Class.staticNumber2(); +var h2: string = CJS_Clobb_Class.staticNumber2();// Error: number ~> string +var h3: number = new CJS_Clobb_Class().instNumber1(); +var h4: string = new CJS_Clobb_Class().instNumber1();// Error: number ~> string +import * as CJS_Clobb_Class_NS from \"CommonJS_Clobbering_Class\"; +new CJS_Clobb_Class_NS();// Error: Namespace object isn\'t constructable +var i1: number = CJS_Clobb_Class_NS.staticNumber3();// Error: Class statics not copied to Namespace object +var i2: number = new CJS_Clobb_Class_NS.default().instNumber2(); +var i3: string = new CJS_Clobb_Class_NS.default().instNumber2();// Error: number ~> string +// =================================== // +// == CommonJS Named Exports -> ES6 == // +// =================================== // +import { doesntExist3 } from \"CommonJS_Named\";// Error: Not an exported binding +import { numberValue2 } from \"CommonJS_Named\"; +var j1: number = numberValue2; +var j2: string = numberValue2;// Error: number ~> string +import { numberValue3 as numVal3 } from \"CommonJS_Named\"; +var k1: number = numVal3; +var k2: string = numVal3;// Error: number ~> string +import * as CJS_Named from \"CommonJS_Named\"; +var l1: number = CJS_Named.numberValue1; +var l2: string = CJS_Named.numberValue1;// Error: number ~> string +CJS_Named.doesntExist;// Error: doesntExist isn\'t a property +import * as CJS_Named_NS from \"CommonJS_Named\"; +var m1: number = CJS_Named_NS.numberValue4; +var m2: string = CJS_Named_NS.default.numberValue4;// Error: CommonJS_Named has no default export +var m3: string = CJS_Named_NS.numberValue4;// Error: number ~> string +////////////////////////////// +// == ES6 Default -> ES6 == // +////////////////////////////// +import { doesntExist4 } from \"ES6_Default_AnonFunction1\";// Error: Not an exported binding +import ES6_Def_AnonFunc1 from \"ES6_Default_AnonFunction1\"; +var n1: number = ES6_Def_AnonFunc1(); +var n2: string = ES6_Def_AnonFunc1();// Error: number ~> string +import ES6_Def_NamedFunc1 from \"ES6_Default_NamedFunction1\"; +var o1: number = ES6_Def_NamedFunc1(); +var o2: string = ES6_Def_NamedFunc1();// Error: number ~> string +import ES6_Def_AnonClass1 from \"ES6_Default_AnonClass1\"; +var p1: number = new ES6_Def_AnonClass1().givesANum(); +var p2: string = new ES6_Def_AnonClass1().givesANum();// Error: number ~> string +import ES6_Def_NamedClass1 from \"ES6_Default_NamedClass1\"; +var q1: number = new ES6_Def_NamedClass1().givesANum(); +var q2: string = new ES6_Def_NamedClass1().givesANum();// Error: number ~> string +//////////////////////////// +// == ES6 Named -> ES6 == // +//////////////////////////// +import doesntExist5 from \"ES6_Named1\";// Error: Not an exported binding +import { specifierNumber1 as specifierNumber1_1 } from \"ES6_Named1\"; +var r1: number = specifierNumber1_1; +var r2: string = specifierNumber1_1;// Error: number ~> string +import { specifierNumber2Renamed } from \"ES6_Named1\"; +var s1: number = specifierNumber2Renamed; +var s2: string = specifierNumber2Renamed;// Error: number ~> string +import { specifierNumber3 as specifierNumber3Renamed } from \"ES6_Named1\"; +var t1: number = specifierNumber3Renamed; +var t2: string = specifierNumber3Renamed;// Error: number ~> string +import { groupedSpecifierNumber1, groupedSpecifierNumber2 } from \"ES6_Named1\"; +var u1: number = groupedSpecifierNumber1; +var u2: number = groupedSpecifierNumber2; +var u3: string = groupedSpecifierNumber1;// Error: number ~> string +var u4: string = groupedSpecifierNumber2;// Error: number ~> string +import { givesANumber } from \"ES6_Named1\"; +var v1: number = givesANumber(); +var v2: string = givesANumber();// Error: number ~> string +import { NumberGenerator } from \"ES6_Named1\"; +var w1: number = new NumberGenerator().givesANumber(); +var w2: string = new NumberGenerator().givesANumber();// Error: number ~> string +import { varDeclNumber1, varDeclNumber2 } from \"ES6_Named1\"; +var x1: number = varDeclNumber1; +var x2: number = varDeclNumber2; +var x3: string = varDeclNumber1;// Error: number ~> string +var x4: string = varDeclNumber2;// Error: number ~> string +import { destructuredObjNumber } from \"ES6_Named1\"; +var y1: number = destructuredObjNumber; +var y2: string = destructuredObjNumber;// Error: number ~> string +import { destructuredArrNumber } from \"ES6_Named1\"; +var z1: number = destructuredArrNumber; +var z2: string = destructuredArrNumber;// Error: number ~> string +import { numberValue1 as numberValue4 } from \"ES6_ExportFrom_Intermediary1\"; +var aa1: number = numberValue4; +var aa2: string = numberValue4;// Error: number ~> string +import { numberValue2_renamed } from \"ES6_ExportFrom_Intermediary1\"; +var ab1: number = numberValue2_renamed; +var ab2: string = numberValue2_renamed;// Error: number ~> string +import { numberValue1 as numberValue5 } from \"ES6_ExportAllFrom_Intermediary1\"; +var ac1: number = numberValue5; +var ac2: string = numberValue5;// Error: number ~> string +/////////////////////////////////// +// == ES6 Default -> CommonJS == // +/////////////////////////////////// +require( + \"ES6_Default_AnonFunction2\" +).doesntExist;// Error: \'doesntExist\' isn\'t an export +var ES6_Def_AnonFunc2 = require(\"ES6_Default_AnonFunction2\").default; +var ad1: number = ES6_Def_AnonFunc2(); +var ad2: string = ES6_Def_AnonFunc2();// Error: number ~> string +var ES6_Def_NamedFunc2 = require(\"ES6_Default_NamedFunction2\").default; +var ae1: number = ES6_Def_NamedFunc2(); +var ae2: string = ES6_Def_NamedFunc2();// Error: number ~> string +var ES6_Def_AnonClass2 = require(\"ES6_Default_AnonClass2\").default; +var af1: number = new ES6_Def_AnonClass2().givesANum(); +var af2: string = new ES6_Def_AnonClass2().givesANum();// Error: number ~> string +var ES6_Def_NamedClass2 = require(\"ES6_Default_NamedClass2\").default; +var ag1: number = new ES6_Def_NamedClass2().givesANum(); +var ag2: string = new ES6_Def_NamedClass2().givesANum();// Error: number ~> string +///////////////////////////////// +// == ES6 Named -> CommonJS == // +///////////////////////////////// +var specifierNumber4 = require(\"ES6_Named2\").specifierNumber4; +var ah1: number = specifierNumber4; +var ah2: string = specifierNumber4;// Error: number ~> string +var specifierNumber5Renamed = require(\"ES6_Named2\").specifierNumber5Renamed; +var ai1: number = specifierNumber5Renamed; +var ai2: string = specifierNumber5Renamed;// Error: number ~> string +var groupedSpecifierNumber3 = require(\"ES6_Named2\").groupedSpecifierNumber3; +var groupedSpecifierNumber4 = require(\"ES6_Named2\").groupedSpecifierNumber4; +var aj1: number = groupedSpecifierNumber3; +var aj2: number = groupedSpecifierNumber4; +var aj3: string = groupedSpecifierNumber3;// Error: number ~> string +var aj4: string = groupedSpecifierNumber4;// Error: number ~> string +var givesANumber2 = require(\"ES6_Named2\").givesANumber2; +var ak1: number = givesANumber2(); +var ak2: string = givesANumber2();// Error: number ~> string +var NumberGenerator2 = require(\"ES6_Named2\").NumberGenerator2; +var al1: number = new NumberGenerator2().givesANumber(); +var al2: string = new NumberGenerator2().givesANumber();// Error: number ~> string +var varDeclNumber3 = require(\"ES6_Named2\").varDeclNumber3; +var varDeclNumber4 = require(\"ES6_Named2\").varDeclNumber4; +var am1: number = varDeclNumber3; +var am2: number = varDeclNumber4; +var am3: string = varDeclNumber3;// Error: number ~> string +var am4: string = varDeclNumber4;// Error: number ~> string +var destructuredObjNumber2 = require(\"ES6_Named2\").destructuredObjNumber2; +var an1: number = destructuredObjNumber2; +var an2: string = destructuredObjNumber2;// Error: number ~> string +var destructuredArrNumber2 = require(\"ES6_Named2\").destructuredArrNumber2; +var ao1: number = destructuredArrNumber2; +var ao2: string = destructuredArrNumber2;// Error: number ~> string +var numberValue6 = require(\"ES6_ExportFrom_Intermediary2\").numberValue1; +var ap1: number = numberValue6; +var ap2: string = numberValue6;// Error: number ~> string +var numberValue2_renamed2 = require( + \"ES6_ExportFrom_Intermediary2\" +).numberValue2_renamed2; +var aq1: number = numberValue2_renamed2; +var aq2: string = numberValue2_renamed2;// Error: number ~> string +var numberValue7 = require(\"ES6_ExportAllFrom_Intermediary2\").numberValue2; +var ar1: number = numberValue7; +var ar2: string = numberValue7;// Error: number ~> string +//////////////////////////////////////////////////////// +// == ES6 Default+Named -> ES6 import Default+Named== // +//////////////////////////////////////////////////////// +import defaultNum, { str as namedStr } from \"./ES6_DefaultAndNamed\"; +var as1: number = defaultNum; +var as2: string = defaultNum;// Error: number ~> string +var as3: string = namedStr; +var as4: number = namedStr;// Error: string ~> number +//////////////////////////////////////// +// == Side-effect only ES6 imports == // +//////////////////////////////////////// +import \"./SideEffects\"; +////////////////////////////////////////////// +// == Suggest export name on likely typo == // +////////////////////////////////////////////// +import specifierNumber1 from \"ES6_Named1\";// Error: Did you mean \`import {specifierNumber1} from ...\`? +import { specifierNumber } from \"ES6_Named1\";// Error: Did you mean \`specifierNumber1\`? +/////////////////////////////////////////////////// +// == Multi \`export *\` should combine exports == // +/////////////////////////////////////////////////// +import { numberValue1 as numberValue8, numberValue2 as numberValue9 } from \"./ES6_ExportAllFromMulti\"; +var at1: number = numberValue8; +var at2: string = numberValue8;// Error: number ~> string +var at3: number = numberValue9; +var at4: string = numberValue9;// Error: number ~> string +///////////////////////////////////////////////////////////// +// == Vanilla \`import\` cannot import a type-only export == // +///////////////////////////////////////////////////////////// +import { typeAlias } from \"./ExportType\";// Error: Cannot vanilla-import a type alias! + +" +`; + +exports[`test test_imports_are_frozen.js 1`] = ` +"/* @flow */ + +// +// Imports +// + +// CommonJS module +import * as DefaultA from \"A\"; +DefaultA.numberValue1 = 123; // Error: DefaultA is frozen + +// ES6 module +import * as ES6_Named1 from \"ES6_Named1\"; +ES6_Named1.varDeclNumber1 = 123; // Error: ES6_Named1 is frozen + +// CommonJS module that clobbers module.exports +import * as CommonJS_Star from \"CommonJS_Clobbering_Lit\"; +CommonJS_Star.numberValue1 = 123; // Error: frozen +CommonJS_Star.default.numberValue1 = 123; // ok + +import CommonJS_Clobbering_Lit from \"CommonJS_Clobbering_Lit\"; +CommonJS_Clobbering_Lit.numberValue1 = 123; // ok + +// CommonJS module that clobbers module.exports with a frozen object +import * as CommonJS_Frozen_Star from \"CommonJS_Clobbering_Frozen\"; +CommonJS_Frozen_Star.numberValue1 = 123; // Error: frozen +CommonJS_Frozen_Star.default.numberValue1 = 123; // Error: frozen + +import CommonJS_Clobbering_Frozen from \"CommonJS_Clobbering_Frozen\"; +CommonJS_Clobbering_Frozen.numberValue1 = 123; // Error: exports are frozen + + +// +// Requires +// + +function testRequires() { + // CommonJS module + var DefaultA = require(\"A\"); + DefaultA.numberValue1 = 123; // ok, not frozen by default + + // ES6 module + var ES6_Named1 = require(\"ES6_Named1\"); + ES6_Named1.numberValue = 123; // error, es6 exports are frozen + + // CommonJS module that clobbers module.exports + var CommonJS_Star = require(\"CommonJS_Clobbering_Lit\"); + CommonJS_Star.numberValue1 = 123; // ok, not frozen by default + + // CommonJS module that clobbers module.exports with a frozen object + var CommonJS_Frozen_Star = require(\"CommonJS_Clobbering_Frozen\"); + CommonJS_Frozen_Star.numberValue1 = 123; // Error: frozen +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// +// Imports +// +// CommonJS module +import * as DefaultA from \"A\"; +DefaultA.numberValue1 = 123;// Error: DefaultA is frozen +// ES6 module +import * as ES6_Named1 from \"ES6_Named1\"; +ES6_Named1.varDeclNumber1 = 123;// Error: ES6_Named1 is frozen +// CommonJS module that clobbers module.exports +import * as CommonJS_Star from \"CommonJS_Clobbering_Lit\"; +CommonJS_Star.numberValue1 = 123;// Error: frozen +CommonJS_Star.default.numberValue1 = 123;// ok +import CommonJS_Clobbering_Lit from \"CommonJS_Clobbering_Lit\"; +CommonJS_Clobbering_Lit.numberValue1 = 123;// ok +// CommonJS module that clobbers module.exports with a frozen object +import * as CommonJS_Frozen_Star from \"CommonJS_Clobbering_Frozen\"; +CommonJS_Frozen_Star.numberValue1 = 123;// Error: frozen +CommonJS_Frozen_Star.default.numberValue1 = 123;// Error: frozen +import CommonJS_Clobbering_Frozen from \"CommonJS_Clobbering_Frozen\"; +CommonJS_Clobbering_Frozen.numberValue1 = 123;// Error: exports are frozen +// +// Requires +// +function testRequires() { + // CommonJS module + var DefaultA = require(\"A\"); + DefaultA.numberValue1 = 123;// ok, not frozen by default + // ES6 module + var ES6_Named1 = require(\"ES6_Named1\"); + ES6_Named1.numberValue = 123;// error, es6 exports are frozen + // CommonJS module that clobbers module.exports + var CommonJS_Star = require(\"CommonJS_Clobbering_Lit\"); + CommonJS_Star.numberValue1 = 123;// ok, not frozen by default + // CommonJS module that clobbers module.exports with a frozen object + var CommonJS_Frozen_Star = require(\"CommonJS_Clobbering_Frozen\"); + CommonJS_Frozen_Star.numberValue1 = 123;// Error: frozen +} + +" +`; diff --git a/tests/es6modules/es6modules.js b/tests/es6modules/es6modules.js new file mode 100644 index 000000000000..a43f876aa601 --- /dev/null +++ b/tests/es6modules/es6modules.js @@ -0,0 +1,296 @@ +/* @flow */ + +// ===================== // +// == Path Resolution == // +// ===================== // + +// @providesModule +import * as DefaultA from "A"; +var a1: number = DefaultA.numberValue1; +var a2: string = DefaultA.numberValue1; // Error: number ~> string + +// File path +import * as DefaultB from "./B"; +var b1: number = DefaultB.numberValue; +var b2: string = DefaultB.numberValue; // Error: number ~> string + +// C.js exists, but not as a providesModule +import DefaultC from "C"; // Error: No such module + +// @providesModule D exists, but not as a filename +import DefaultD from "./D"; // Error: No such module + +// ================================================ // +// == CommonJS Clobbering Literal Exports -> ES6 == // +// ================================================ // + +import {doesntExist1} from "CommonJS_Clobbering_Lit"; // Error: Not an exported binding + +import {numberValue1} from "CommonJS_Clobbering_Lit"; +var c1: number = numberValue1; +var c2: string = numberValue1; // Error: number ~> string + +import {numberValue2 as numVal1} from "CommonJS_Clobbering_Lit"; +var d1: number = numVal1; +var d2: string = numVal1; // Error: number ~> string + +import CJS_Clobb_Lit from "CommonJS_Clobbering_Lit"; +var e1: number = CJS_Clobb_Lit.numberValue3; +var e2: string = CJS_Clobb_Lit.numberValue3; // Error: number ~> string +CJS_Clobb_Lit.doesntExist; // Error: doesntExist isn't a property + +import * as CJS_Clobb_Lit_NS from "CommonJS_Clobbering_Lit"; +var f1: number = CJS_Clobb_Lit_NS.numberValue4; +var f2: number = CJS_Clobb_Lit_NS.default.numberValue4; +CJS_Clobb_Lit_NS.default.default; // Error: No 'default' property on the exported obj +var f3: string = CJS_Clobb_Lit_NS.numberValue4; // Error: number ~> string +var f4: string = CJS_Clobb_Lit_NS.default.numberValue5; // Error: number ~> string + +// ============================================== // +// == CommonJS Clobbering Class Exports -> ES6 == // +// ============================================== // + +import {doesntExist2} from "CommonJS_Clobbering_Class"; // Error: Not an exported binding + +// The following import should error because class statics are not turned into +// named exports for now. This avoids complexities with polymorphic static +// members (where the polymophism is defined on the class itself rather than the +// method). +import {staticNumber1, baseProp, childProp} from "CommonJS_Clobbering_Class"; // Error + +import CJS_Clobb_Class from "CommonJS_Clobbering_Class"; +new CJS_Clobb_Class(); +new CJS_Clobb_Class().doesntExist; // Error: Class has no `doesntExist` property +var h1: number = CJS_Clobb_Class.staticNumber2(); +var h2: string = CJS_Clobb_Class.staticNumber2(); // Error: number ~> string +var h3: number = new CJS_Clobb_Class().instNumber1(); +var h4: string = new CJS_Clobb_Class().instNumber1(); // Error: number ~> string + +import * as CJS_Clobb_Class_NS from "CommonJS_Clobbering_Class"; +new CJS_Clobb_Class_NS(); // Error: Namespace object isn't constructable +var i1: number = CJS_Clobb_Class_NS.staticNumber3(); // Error: Class statics not copied to Namespace object +var i2: number = new CJS_Clobb_Class_NS.default().instNumber2(); +var i3: string = new CJS_Clobb_Class_NS.default().instNumber2(); // Error: number ~> string + +// =================================== // +// == CommonJS Named Exports -> ES6 == // +// =================================== // + +import {doesntExist3} from "CommonJS_Named"; // Error: Not an exported binding + +import {numberValue2} from "CommonJS_Named"; +var j1: number = numberValue2; +var j2: string = numberValue2; // Error: number ~> string + +import {numberValue3 as numVal3} from "CommonJS_Named"; +var k1: number = numVal3; +var k2: string = numVal3; // Error: number ~> string + +import * as CJS_Named from "CommonJS_Named"; +var l1: number = CJS_Named.numberValue1; +var l2: string = CJS_Named.numberValue1; // Error: number ~> string +CJS_Named.doesntExist; // Error: doesntExist isn't a property + +import * as CJS_Named_NS from "CommonJS_Named"; +var m1: number = CJS_Named_NS.numberValue4; +var m2: string = CJS_Named_NS.default.numberValue4; // Error: CommonJS_Named has no default export +var m3: string = CJS_Named_NS.numberValue4; // Error: number ~> string + +////////////////////////////// +// == ES6 Default -> ES6 == // +////////////////////////////// + +import {doesntExist4} from "ES6_Default_AnonFunction1"; // Error: Not an exported binding + +import ES6_Def_AnonFunc1 from "ES6_Default_AnonFunction1"; +var n1: number = ES6_Def_AnonFunc1(); +var n2: string = ES6_Def_AnonFunc1(); // Error: number ~> string + +import ES6_Def_NamedFunc1 from "ES6_Default_NamedFunction1"; +var o1: number = ES6_Def_NamedFunc1(); +var o2: string = ES6_Def_NamedFunc1(); // Error: number ~> string + +import ES6_Def_AnonClass1 from "ES6_Default_AnonClass1"; +var p1: number = new ES6_Def_AnonClass1().givesANum(); +var p2: string = new ES6_Def_AnonClass1().givesANum(); // Error: number ~> string + +import ES6_Def_NamedClass1 from "ES6_Default_NamedClass1"; +var q1: number = new ES6_Def_NamedClass1().givesANum(); +var q2: string = new ES6_Def_NamedClass1().givesANum(); // Error: number ~> string + +//////////////////////////// +// == ES6 Named -> ES6 == // +//////////////////////////// + +import doesntExist5 from "ES6_Named1"; // Error: Not an exported binding + +import {specifierNumber1 as specifierNumber1_1} from "ES6_Named1"; +var r1: number = specifierNumber1_1; +var r2: string = specifierNumber1_1; // Error: number ~> string + +import {specifierNumber2Renamed} from "ES6_Named1"; +var s1: number = specifierNumber2Renamed; +var s2: string = specifierNumber2Renamed; // Error: number ~> string + +import {specifierNumber3 as specifierNumber3Renamed} from "ES6_Named1"; +var t1: number = specifierNumber3Renamed; +var t2: string = specifierNumber3Renamed; // Error: number ~> string + +import {groupedSpecifierNumber1, groupedSpecifierNumber2} from "ES6_Named1"; +var u1: number = groupedSpecifierNumber1; +var u2: number = groupedSpecifierNumber2; +var u3: string = groupedSpecifierNumber1; // Error: number ~> string +var u4: string = groupedSpecifierNumber2; // Error: number ~> string + +import {givesANumber} from "ES6_Named1"; +var v1: number = givesANumber(); +var v2: string = givesANumber(); // Error: number ~> string + +import {NumberGenerator} from "ES6_Named1"; +var w1: number = new NumberGenerator().givesANumber(); +var w2: string = new NumberGenerator().givesANumber(); // Error: number ~> string + +import {varDeclNumber1, varDeclNumber2} from "ES6_Named1"; +var x1: number = varDeclNumber1; +var x2: number = varDeclNumber2; +var x3: string = varDeclNumber1; // Error: number ~> string +var x4: string = varDeclNumber2; // Error: number ~> string + +import {destructuredObjNumber} from "ES6_Named1"; +var y1: number = destructuredObjNumber; +var y2: string = destructuredObjNumber; // Error: number ~> string + +import {destructuredArrNumber} from "ES6_Named1"; +var z1: number = destructuredArrNumber; +var z2: string = destructuredArrNumber; // Error: number ~> string + +import {numberValue1 as numberValue4} from "ES6_ExportFrom_Intermediary1"; +var aa1: number = numberValue4; +var aa2: string = numberValue4; // Error: number ~> string + +import {numberValue2_renamed} from "ES6_ExportFrom_Intermediary1"; +var ab1: number = numberValue2_renamed; +var ab2: string = numberValue2_renamed; // Error: number ~> string + +import {numberValue1 as numberValue5} from "ES6_ExportAllFrom_Intermediary1"; +var ac1: number = numberValue5; +var ac2: string = numberValue5; // Error: number ~> string + +/////////////////////////////////// +// == ES6 Default -> CommonJS == // +/////////////////////////////////// + +require('ES6_Default_AnonFunction2').doesntExist; // Error: 'doesntExist' isn't an export + +var ES6_Def_AnonFunc2 = require("ES6_Default_AnonFunction2").default; +var ad1: number = ES6_Def_AnonFunc2(); +var ad2: string = ES6_Def_AnonFunc2(); // Error: number ~> string + +var ES6_Def_NamedFunc2 = require("ES6_Default_NamedFunction2").default; +var ae1: number = ES6_Def_NamedFunc2(); +var ae2: string = ES6_Def_NamedFunc2(); // Error: number ~> string + +var ES6_Def_AnonClass2 = require("ES6_Default_AnonClass2").default; +var af1: number = new ES6_Def_AnonClass2().givesANum(); +var af2: string = new ES6_Def_AnonClass2().givesANum(); // Error: number ~> string + +var ES6_Def_NamedClass2 = require("ES6_Default_NamedClass2").default; +var ag1: number = new ES6_Def_NamedClass2().givesANum(); +var ag2: string = new ES6_Def_NamedClass2().givesANum(); // Error: number ~> string + +///////////////////////////////// +// == ES6 Named -> CommonJS == // +///////////////////////////////// + +var specifierNumber4 = require("ES6_Named2").specifierNumber4; +var ah1: number = specifierNumber4; +var ah2: string = specifierNumber4; // Error: number ~> string + +var specifierNumber5Renamed = require("ES6_Named2").specifierNumber5Renamed; +var ai1: number = specifierNumber5Renamed; +var ai2: string = specifierNumber5Renamed; // Error: number ~> string + +var groupedSpecifierNumber3 = require("ES6_Named2").groupedSpecifierNumber3; +var groupedSpecifierNumber4 = require("ES6_Named2").groupedSpecifierNumber4; +var aj1: number = groupedSpecifierNumber3; +var aj2: number = groupedSpecifierNumber4; +var aj3: string = groupedSpecifierNumber3; // Error: number ~> string +var aj4: string = groupedSpecifierNumber4; // Error: number ~> string + +var givesANumber2 = require("ES6_Named2").givesANumber2; +var ak1: number = givesANumber2(); +var ak2: string = givesANumber2(); // Error: number ~> string + +var NumberGenerator2 = require("ES6_Named2").NumberGenerator2; +var al1: number = new NumberGenerator2().givesANumber(); +var al2: string = new NumberGenerator2().givesANumber(); // Error: number ~> string + +var varDeclNumber3 = require("ES6_Named2").varDeclNumber3; +var varDeclNumber4 = require("ES6_Named2").varDeclNumber4; +var am1: number = varDeclNumber3; +var am2: number = varDeclNumber4; +var am3: string = varDeclNumber3; // Error: number ~> string +var am4: string = varDeclNumber4; // Error: number ~> string + +var destructuredObjNumber2 = require("ES6_Named2").destructuredObjNumber2; +var an1: number = destructuredObjNumber2; +var an2: string = destructuredObjNumber2; // Error: number ~> string + +var destructuredArrNumber2 = require("ES6_Named2").destructuredArrNumber2; +var ao1: number = destructuredArrNumber2; +var ao2: string = destructuredArrNumber2; // Error: number ~> string + +var numberValue6 = require("ES6_ExportFrom_Intermediary2").numberValue1; +var ap1: number = numberValue6; +var ap2: string = numberValue6; // Error: number ~> string + +var numberValue2_renamed2 = require("ES6_ExportFrom_Intermediary2").numberValue2_renamed2; +var aq1: number = numberValue2_renamed2; +var aq2: string = numberValue2_renamed2; // Error: number ~> string + +var numberValue7 = require("ES6_ExportAllFrom_Intermediary2").numberValue2; +var ar1: number = numberValue7; +var ar2: string = numberValue7; // Error: number ~> string + +//////////////////////////////////////////////////////// +// == ES6 Default+Named -> ES6 import Default+Named== // +//////////////////////////////////////////////////////// + +import defaultNum, {str as namedStr} from "./ES6_DefaultAndNamed"; + +var as1: number = defaultNum; +var as2: string = defaultNum; // Error: number ~> string + +var as3: string = namedStr; +var as4: number = namedStr; // Error: string ~> number + +//////////////////////////////////////// +// == Side-effect only ES6 imports == // +//////////////////////////////////////// + +import "./SideEffects"; + +////////////////////////////////////////////// +// == Suggest export name on likely typo == // +////////////////////////////////////////////// +import specifierNumber1 from "ES6_Named1"; // Error: Did you mean `import {specifierNumber1} from ...`? +import {specifierNumber} from "ES6_Named1"; // Error: Did you mean `specifierNumber1`? + +/////////////////////////////////////////////////// +// == Multi `export *` should combine exports == // +/////////////////////////////////////////////////// +import { + numberValue1 as numberValue8, + numberValue2 as numberValue9 +} from "./ES6_ExportAllFromMulti"; + +var at1: number = numberValue8; +var at2: string = numberValue8; // Error: number ~> string + +var at3: number = numberValue9; +var at4: string = numberValue9; // Error: number ~> string + +///////////////////////////////////////////////////////////// +// == Vanilla `import` cannot import a type-only export == // +///////////////////////////////////////////////////////////// +import {typeAlias} from "./ExportType"; // Error: Cannot vanilla-import a type alias! diff --git a/tests/es6modules/jsfmt.spec.js b/tests/es6modules/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/es6modules/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/es6modules/test_imports_are_frozen.js b/tests/es6modules/test_imports_are_frozen.js new file mode 100644 index 000000000000..7fd1e51490d5 --- /dev/null +++ b/tests/es6modules/test_imports_are_frozen.js @@ -0,0 +1,52 @@ +/* @flow */ + +// +// Imports +// + +// CommonJS module +import * as DefaultA from "A"; +DefaultA.numberValue1 = 123; // Error: DefaultA is frozen + +// ES6 module +import * as ES6_Named1 from "ES6_Named1"; +ES6_Named1.varDeclNumber1 = 123; // Error: ES6_Named1 is frozen + +// CommonJS module that clobbers module.exports +import * as CommonJS_Star from "CommonJS_Clobbering_Lit"; +CommonJS_Star.numberValue1 = 123; // Error: frozen +CommonJS_Star.default.numberValue1 = 123; // ok + +import CommonJS_Clobbering_Lit from "CommonJS_Clobbering_Lit"; +CommonJS_Clobbering_Lit.numberValue1 = 123; // ok + +// CommonJS module that clobbers module.exports with a frozen object +import * as CommonJS_Frozen_Star from "CommonJS_Clobbering_Frozen"; +CommonJS_Frozen_Star.numberValue1 = 123; // Error: frozen +CommonJS_Frozen_Star.default.numberValue1 = 123; // Error: frozen + +import CommonJS_Clobbering_Frozen from "CommonJS_Clobbering_Frozen"; +CommonJS_Clobbering_Frozen.numberValue1 = 123; // Error: exports are frozen + + +// +// Requires +// + +function testRequires() { + // CommonJS module + var DefaultA = require("A"); + DefaultA.numberValue1 = 123; // ok, not frozen by default + + // ES6 module + var ES6_Named1 = require("ES6_Named1"); + ES6_Named1.numberValue = 123; // error, es6 exports are frozen + + // CommonJS module that clobbers module.exports + var CommonJS_Star = require("CommonJS_Clobbering_Lit"); + CommonJS_Star.numberValue1 = 123; // ok, not frozen by default + + // CommonJS module that clobbers module.exports with a frozen object + var CommonJS_Frozen_Star = require("CommonJS_Clobbering_Frozen"); + CommonJS_Frozen_Star.numberValue1 = 123; // Error: frozen +} diff --git a/tests/es_declare_module/__snapshots__/jsfmt.spec.js.snap b/tests/es_declare_module/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..46041e8518a8 --- /dev/null +++ b/tests/es_declare_module/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,80 @@ +exports[`test es_declare_module.js 1`] = ` +"// @flow + +import {num1, str1} from "CJS_Named"; +import CJS_Named from "CJS_Named"; +(num1: number); +(num1: string); // Error: number ~> string +(str1: string); +(str1: number); // Error: string ~> number +(CJS_Named: {num1: number, str1: string}); +(CJS_Named: number); // Error: Module ~> number + +import {num2} from "CJS_Clobbered"; // Error: No such export! +import {numExport} from "CJS_Clobbered"; +(numExport: number); +(numExport: string); // Error: number ~> string +import type {numType} from "CJS_Clobbered"; +(42: numType); +('asdf': numType); // Error: string ~> number + +import {strHidden} from "ES"; // Error: No such export! +import {str3} from "ES"; +(str3: string); +(str3: number); // Error: string ~> number + +import {num3} from "ES"; +(num3: number); +(num3: string); // Error: number ~> string + +import {C} from "ES"; +import type {C as CType} from "ES"; +(new C(): C); +(42: C); // Error: number ~> C +(new C(): CType); +(42: CType); // Error: number ~> CType + +import {T} from "ES"; // Error: T is a type import, not a value +import type {T as T2} from "ES"; +(42: T2); +('asdf': T2); // Error: string ~> number + +import {exports as nope} from "ES"; // Error: Not an export +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { num1, str1 } from "CJS_Named"; +import CJS_Named from "CJS_Named"; +(num1: number); +(num1: string);// Error: number ~> string +(str1: string); +(str1: number);// Error: string ~> number +(CJS_Named: { num1: number, str1: string }); +(CJS_Named: number);// Error: Module ~> number +import { num2 } from "CJS_Clobbered";// Error: No such export! +import { numExport } from "CJS_Clobbered"; +(numExport: number); +(numExport: string);// Error: number ~> string +import type { numType } from "CJS_Clobbered"; +(42: numType); +("asdf": numType);// Error: string ~> number +import { strHidden } from "ES";// Error: No such export! +import { str3 } from "ES"; +(str3: string); +(str3: number);// Error: string ~> number +import { num3 } from "ES"; +(num3: number); +(num3: string);// Error: number ~> string +import { C } from "ES"; +import type { C as CType } from "ES"; +(new C(): C); +(42: C);// Error: number ~> C +(new C(): CType); +(42: CType);// Error: number ~> CType +import { T } from "ES";// Error: T is a type import, not a value +import type { T as T2 } from "ES"; +(42: T2); +("asdf": T2);// Error: string ~> number +import { exports as nope } from "ES";// Error: Not an export + +" +`; diff --git a/tests/es_declare_module/es_declare_module.js b/tests/es_declare_module/es_declare_module.js new file mode 100644 index 000000000000..6395bceca7d5 --- /dev/null +++ b/tests/es_declare_module/es_declare_module.js @@ -0,0 +1,41 @@ +// @flow + +import {num1, str1} from "CJS_Named"; +import CJS_Named from "CJS_Named"; +(num1: number); +(num1: string); // Error: number ~> string +(str1: string); +(str1: number); // Error: string ~> number +(CJS_Named: {num1: number, str1: string}); +(CJS_Named: number); // Error: Module ~> number + +import {num2} from "CJS_Clobbered"; // Error: No such export! +import {numExport} from "CJS_Clobbered"; +(numExport: number); +(numExport: string); // Error: number ~> string +import type {numType} from "CJS_Clobbered"; +(42: numType); +('asdf': numType); // Error: string ~> number + +import {strHidden} from "ES"; // Error: No such export! +import {str3} from "ES"; +(str3: string); +(str3: number); // Error: string ~> number + +import {num3} from "ES"; +(num3: number); +(num3: string); // Error: number ~> string + +import {C} from "ES"; +import type {C as CType} from "ES"; +(new C(): C); +(42: C); // Error: number ~> C +(new C(): CType); +(42: CType); // Error: number ~> CType + +import {T} from "ES"; // Error: T is a type import, not a value +import type {T as T2} from "ES"; +(42: T2); +('asdf': T2); // Error: string ~> number + +import {exports as nope} from "ES"; // Error: Not an export diff --git a/tests/es_declare_module/flow-typed/__snapshots__/jsfmt.spec.js.snap b/tests/es_declare_module/flow-typed/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4d0c81b089be --- /dev/null +++ b/tests/es_declare_module/flow-typed/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,40 @@ +exports[`test declares.js 1`] = ` +"declare module \"CJS_Named\" { + declare var num1: number; + declare var str1: string; +} + +declare module \"CJS_Clobbered\" { + declare var num2: number; + declare type numType = number; + declare var exports: { + numExport: number, + }; +} + +declare module \"ES\" { + declare var strHidden: string; + declare export {strHidden as str3}; + declare export var num3: number; + declare export class C {} + declare export type T = number; + declare var exports: number; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (16:10) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4490:10) + at Parser.pp$7.flowParseDeclareModule (/node_modules/babylon/lib/index.js:4518:20) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4483:19) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; diff --git a/tests/es_declare_module/flow-typed/declares.js b/tests/es_declare_module/flow-typed/declares.js new file mode 100644 index 000000000000..50198afb76c9 --- /dev/null +++ b/tests/es_declare_module/flow-typed/declares.js @@ -0,0 +1,21 @@ +declare module "CJS_Named" { + declare var num1: number; + declare var str1: string; +} + +declare module "CJS_Clobbered" { + declare var num2: number; + declare type numType = number; + declare var exports: { + numExport: number, + }; +} + +declare module "ES" { + declare var strHidden: string; + declare export {strHidden as str3}; + declare export var num3: number; + declare export class C {} + declare export type T = number; + declare var exports: number; +} diff --git a/tests/es_declare_module/flow-typed/jsfmt.spec.js b/tests/es_declare_module/flow-typed/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/es_declare_module/flow-typed/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/es_declare_module/jsfmt.spec.js b/tests/es_declare_module/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/es_declare_module/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_class_instance_fields.ignore/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_class_instance_fields.ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1f28115f0d5e --- /dev/null +++ b/tests/esproposal_class_instance_fields.ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +class Foo { + annotationOnly: string; + initOnly = 'asdf' + initWithAnnotation: string = 'asdf'; + [computed]: string; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class Foo { + annotationOnly: string; + initOnly = "asdf"; + initWithAnnotation: string = "asdf"; + [computed]: string; +} + +" +`; diff --git a/tests/esproposal_class_instance_fields.ignore/jsfmt.spec.js b/tests/esproposal_class_instance_fields.ignore/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_class_instance_fields.ignore/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_class_instance_fields.ignore/test.js b/tests/esproposal_class_instance_fields.ignore/test.js new file mode 100644 index 000000000000..7525cf355c95 --- /dev/null +++ b/tests/esproposal_class_instance_fields.ignore/test.js @@ -0,0 +1,8 @@ +/* @flow */ + +class Foo { + annotationOnly: string; + initOnly = 'asdf' + initWithAnnotation: string = 'asdf'; + [computed]: string; +} diff --git a/tests/esproposal_class_instance_fields.warn/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_class_instance_fields.warn/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c2c53423e3e9 --- /dev/null +++ b/tests/esproposal_class_instance_fields.warn/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +class Foo { + annotationOnly: string; + initOnly = 'asdf'; + initWithAnnotation: string = 'asdf'; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class Foo { + annotationOnly: string; + initOnly = "asdf"; + initWithAnnotation: string = "asdf"; +} + +" +`; diff --git a/tests/esproposal_class_instance_fields.warn/jsfmt.spec.js b/tests/esproposal_class_instance_fields.warn/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_class_instance_fields.warn/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_class_instance_fields.warn/test.js b/tests/esproposal_class_instance_fields.warn/test.js new file mode 100644 index 000000000000..ac74ba3e8d7f --- /dev/null +++ b/tests/esproposal_class_instance_fields.warn/test.js @@ -0,0 +1,7 @@ +/* @flow */ + +class Foo { + annotationOnly: string; + initOnly = 'asdf'; + initWithAnnotation: string = 'asdf'; +} diff --git a/tests/esproposal_class_static_fields.ignore/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_class_static_fields.ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1ce10796ca4c --- /dev/null +++ b/tests/esproposal_class_static_fields.ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +class Foo { + static annotationOnly: string; + static initOnly = 'asdf'; + static initWithAnnotation: string = 'asdf'; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class Foo { + static annotationOnly: string; + static initOnly = "asdf"; + static initWithAnnotation: string = "asdf"; +} + +" +`; diff --git a/tests/esproposal_class_static_fields.ignore/jsfmt.spec.js b/tests/esproposal_class_static_fields.ignore/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_class_static_fields.ignore/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_class_static_fields.ignore/test.js b/tests/esproposal_class_static_fields.ignore/test.js new file mode 100644 index 000000000000..f47f1b642f4f --- /dev/null +++ b/tests/esproposal_class_static_fields.ignore/test.js @@ -0,0 +1,7 @@ +/* @flow */ + +class Foo { + static annotationOnly: string; + static initOnly = 'asdf'; + static initWithAnnotation: string = 'asdf'; +} diff --git a/tests/esproposal_class_static_fields.warn/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_class_static_fields.warn/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1ce10796ca4c --- /dev/null +++ b/tests/esproposal_class_static_fields.warn/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +class Foo { + static annotationOnly: string; + static initOnly = 'asdf'; + static initWithAnnotation: string = 'asdf'; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class Foo { + static annotationOnly: string; + static initOnly = "asdf"; + static initWithAnnotation: string = "asdf"; +} + +" +`; diff --git a/tests/esproposal_class_static_fields.warn/jsfmt.spec.js b/tests/esproposal_class_static_fields.warn/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_class_static_fields.warn/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_class_static_fields.warn/test.js b/tests/esproposal_class_static_fields.warn/test.js new file mode 100644 index 000000000000..f47f1b642f4f --- /dev/null +++ b/tests/esproposal_class_static_fields.warn/test.js @@ -0,0 +1,7 @@ +/* @flow */ + +class Foo { + static annotationOnly: string; + static initOnly = 'asdf'; + static initWithAnnotation: string = 'asdf'; +} diff --git a/tests/esproposal_decorators.ignore/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_decorators.ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bc24fea44557 --- /dev/null +++ b/tests/esproposal_decorators.ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,29 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +@decorator4 +class Foo { + @decorator1 + method1() {} + + @decorator2 + @decorator3 + method2() {} +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +@decorator4 +class Foo { + @decorator1 + method1() { + + } + @decorator2 + @decorator3 + method2() { + + } +} + +" +`; diff --git a/tests/esproposal_decorators.ignore/jsfmt.spec.js b/tests/esproposal_decorators.ignore/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_decorators.ignore/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_decorators.ignore/test.js b/tests/esproposal_decorators.ignore/test.js new file mode 100644 index 000000000000..972036955184 --- /dev/null +++ b/tests/esproposal_decorators.ignore/test.js @@ -0,0 +1,11 @@ +/* @flow */ + +@decorator4 +class Foo { + @decorator1 + method1() {} + + @decorator2 + @decorator3 + method2() {} +} diff --git a/tests/esproposal_decorators.warn/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_decorators.warn/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bc24fea44557 --- /dev/null +++ b/tests/esproposal_decorators.warn/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,29 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +@decorator4 +class Foo { + @decorator1 + method1() {} + + @decorator2 + @decorator3 + method2() {} +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +@decorator4 +class Foo { + @decorator1 + method1() { + + } + @decorator2 + @decorator3 + method2() { + + } +} + +" +`; diff --git a/tests/esproposal_decorators.warn/jsfmt.spec.js b/tests/esproposal_decorators.warn/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_decorators.warn/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_decorators.warn/test.js b/tests/esproposal_decorators.warn/test.js new file mode 100644 index 000000000000..972036955184 --- /dev/null +++ b/tests/esproposal_decorators.warn/test.js @@ -0,0 +1,11 @@ +/* @flow */ + +@decorator4 +class Foo { + @decorator1 + method1() {} + + @decorator2 + @decorator3 + method2() {} +} diff --git a/tests/esproposal_export_star_as.enable/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_export_star_as.enable/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3b337efbf4b7 --- /dev/null +++ b/tests/esproposal_export_star_as.enable/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,56 @@ +exports[`test dest.js 1`] = ` +"// @flow + +import {source} from \"./test\"; + +var a: number = source.num; +var b: string = source.num; // Error: num ~> string + +var c: string = source.str; +var d: number = source.str; // Error: num ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { source } from \"./test\"; +var a: number = source.num; +var b: string = source.num;// Error: num ~> string +var c: string = source.str; +var d: number = source.str;// Error: num ~> string + +" +`; + +exports[`test source.js 1`] = ` +"// @flow + +export var str = \'asdf\'; +export var num = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export var str = \"asdf\"; +export var num = 42; + +" +`; + +exports[`test test.js 1`] = ` +"// @flow + +export * as source from \"./source\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; diff --git a/tests/esproposal_export_star_as.enable/dest.js b/tests/esproposal_export_star_as.enable/dest.js new file mode 100644 index 000000000000..99f558d3bd43 --- /dev/null +++ b/tests/esproposal_export_star_as.enable/dest.js @@ -0,0 +1,9 @@ +// @flow + +import {source} from "./test"; + +var a: number = source.num; +var b: string = source.num; // Error: num ~> string + +var c: string = source.str; +var d: number = source.str; // Error: num ~> string diff --git a/tests/esproposal_export_star_as.enable/jsfmt.spec.js b/tests/esproposal_export_star_as.enable/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_export_star_as.enable/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_export_star_as.enable/source.js b/tests/esproposal_export_star_as.enable/source.js new file mode 100644 index 000000000000..98d19df9fad7 --- /dev/null +++ b/tests/esproposal_export_star_as.enable/source.js @@ -0,0 +1,4 @@ +// @flow + +export var str = 'asdf'; +export var num = 42; diff --git a/tests/esproposal_export_star_as.enable/test.js b/tests/esproposal_export_star_as.enable/test.js new file mode 100644 index 000000000000..5fdc1272948f --- /dev/null +++ b/tests/esproposal_export_star_as.enable/test.js @@ -0,0 +1,3 @@ +// @flow + +export * as source from "./source"; diff --git a/tests/esproposal_export_star_as.ignore/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_export_star_as.ignore/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5e14073ad095 --- /dev/null +++ b/tests/esproposal_export_star_as.ignore/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,56 @@ +exports[`test dest.js 1`] = ` +"// @flow + +import {source} from \"./test\"; + +var a: number = source.num; +var b: string = source.num; // Error: num ~> string + +var c: string = source.str; +var d: number = source.str; // Ignored error: num ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { source } from \"./test\"; +var a: number = source.num; +var b: string = source.num;// Error: num ~> string +var c: string = source.str; +var d: number = source.str;// Ignored error: num ~> string + +" +`; + +exports[`test source.js 1`] = ` +"// @flow + +export var str = \'asdf\'; +export var num = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export var str = \"asdf\"; +export var num = 42; + +" +`; + +exports[`test test.js 1`] = ` +"// @flow + +export * as source from \"./source\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; diff --git a/tests/esproposal_export_star_as.ignore/dest.js b/tests/esproposal_export_star_as.ignore/dest.js new file mode 100644 index 000000000000..fa12f1ad78a9 --- /dev/null +++ b/tests/esproposal_export_star_as.ignore/dest.js @@ -0,0 +1,9 @@ +// @flow + +import {source} from "./test"; + +var a: number = source.num; +var b: string = source.num; // Error: num ~> string + +var c: string = source.str; +var d: number = source.str; // Ignored error: num ~> string diff --git a/tests/esproposal_export_star_as.ignore/jsfmt.spec.js b/tests/esproposal_export_star_as.ignore/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_export_star_as.ignore/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_export_star_as.ignore/source.js b/tests/esproposal_export_star_as.ignore/source.js new file mode 100644 index 000000000000..98d19df9fad7 --- /dev/null +++ b/tests/esproposal_export_star_as.ignore/source.js @@ -0,0 +1,4 @@ +// @flow + +export var str = 'asdf'; +export var num = 42; diff --git a/tests/esproposal_export_star_as.ignore/test.js b/tests/esproposal_export_star_as.ignore/test.js new file mode 100644 index 000000000000..5fdc1272948f --- /dev/null +++ b/tests/esproposal_export_star_as.ignore/test.js @@ -0,0 +1,3 @@ +// @flow + +export * as source from "./source"; diff --git a/tests/esproposal_export_star_as.warn/__snapshots__/jsfmt.spec.js.snap b/tests/esproposal_export_star_as.warn/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9fc286f9e3a6 --- /dev/null +++ b/tests/esproposal_export_star_as.warn/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +export * as foo from \"./test\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; diff --git a/tests/esproposal_export_star_as.warn/jsfmt.spec.js b/tests/esproposal_export_star_as.warn/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/esproposal_export_star_as.warn/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/esproposal_export_star_as.warn/test.js b/tests/esproposal_export_star_as.warn/test.js new file mode 100644 index 000000000000..ee71a9b8482e --- /dev/null +++ b/tests/esproposal_export_star_as.warn/test.js @@ -0,0 +1,3 @@ +/* @flow */ + +export * as foo from "./test"; diff --git a/tests/export_default/P.js b/tests/export_default/P.js new file mode 100644 index 000000000000..a0181c306670 --- /dev/null +++ b/tests/export_default/P.js @@ -0,0 +1 @@ +module.exports = require('M'); diff --git a/tests/export_default/__snapshots__/jsfmt.spec.js.snap b/tests/export_default/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..74c813571c86 --- /dev/null +++ b/tests/export_default/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test P.js 1`] = ` +"module.exports = require('M'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = require("M"); + +" +`; + +exports[`test test.js 1`] = ` +"var M = require('M'); +var N = require('N'); +N.x = M(N.x); +var P = require('./P'); // implementation of P redirects to module M +N.y = P(N.y); +var Q = require('Q'); // declaration of Q redirects to module M +N.z = Q(N.z); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var M = require("M"); +var N = require("N"); +N.x = M(N.x); +var P = require("./P");// implementation of P redirects to module M +N.y = P(N.y); +var Q = require("Q");// declaration of Q redirects to module M +N.z = Q(N.z); + +" +`; diff --git a/tests/export_default/jsfmt.spec.js b/tests/export_default/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/export_default/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/export_default/lib/__snapshots__/jsfmt.spec.js.snap b/tests/export_default/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c474b386925f --- /dev/null +++ b/tests/export_default/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,30 @@ +exports[`test lib.js 1`] = ` +"declare module M { + declare function exports(x:string): string; +} +declare module N { + declare var x: number; + declare var y: number; + declare var z: number; +} +declare module Q { + declare var exports: $Exports<\'M\'>; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/export_default/lib/jsfmt.spec.js b/tests/export_default/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/export_default/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/export_default/lib/lib.js b/tests/export_default/lib/lib.js new file mode 100644 index 000000000000..b2d466ba1831 --- /dev/null +++ b/tests/export_default/lib/lib.js @@ -0,0 +1,11 @@ +declare module M { + declare function exports(x:string): string; +} +declare module N { + declare var x: number; + declare var y: number; + declare var z: number; +} +declare module Q { + declare var exports: $Exports<'M'>; +} diff --git a/tests/export_default/test.js b/tests/export_default/test.js new file mode 100644 index 000000000000..be26514294ab --- /dev/null +++ b/tests/export_default/test.js @@ -0,0 +1,7 @@ +var M = require('M'); +var N = require('N'); +N.x = M(N.x); +var P = require('./P'); // implementation of P redirects to module M +N.y = P(N.y); +var Q = require('Q'); // declaration of Q redirects to module M +N.z = Q(N.z); diff --git a/tests/export_type/__snapshots__/jsfmt.spec.js.snap b/tests/export_type/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3e7a1e3fe947 --- /dev/null +++ b/tests/export_type/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,141 @@ +exports[`test cjs_with_types.js 1`] = ` +"/* @flow */ + +export type talias4 = number; +export interface IFoo { prop: number }; + +module.exports = {} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at printExportDeclaration (/src/printer.js:1774:21) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; + +exports[`test importer.js 1`] = ` +"/* @flow */ + +import type { + inlinedType1, + standaloneType1, + talias1, + talias3, +} from \"./types_only\"; + +var a: inlinedType1 = 42; +var b: inlinedType1 = \'asdf\'; // Error: string ~> number + +var c: standaloneType1 = 42; +var d: standaloneType1 = \'asdf\'; // Error: string ~> number + +var e: talias1 = 42; +var f: talias1 = \'asdf\'; // Error: string ~> number + +var g: talias3 = 42; +var h: talias3 = \'asdf\'; // Error: string ~> number + +import type {talias4} from \"./cjs_with_types\"; +var i: talias4 = 42; +var j: talias4 = \'asdf\'; // Error: string ~> number + +import {IFoo, IFoo2} from \"./types_only\"; + +var k: IFoo = {prop: 42}; +var l: IFoo = {prop: \'asdf\'}; // Error: {prop:string} ~> {prop:number} + +var m: IFoo2 = {prop: \'asdf\'}; +var n: IFoo2 = {prop: 42}; // Error: {prop:number} ~> {prop:string} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +import type { inlinedType1, standaloneType1, talias1, talias3 } from \"./types_only\"; +var a: inlinedType1 = 42; +var b: inlinedType1 = \"asdf\";// Error: string ~> number +var c: standaloneType1 = 42; +var d: standaloneType1 = \"asdf\";// Error: string ~> number +var e: talias1 = 42; +var f: talias1 = \"asdf\";// Error: string ~> number +var g: talias3 = 42; +var h: talias3 = \"asdf\";// Error: string ~> number +import type { talias4 } from \"./cjs_with_types\"; +var i: talias4 = 42; +var j: talias4 = \"asdf\";// Error: string ~> number +import { IFoo, IFoo2 } from \"./types_only\"; +var k: IFoo = { prop: 42 }; +var l: IFoo = { prop: \"asdf\" };// Error: {prop:string} ~> {prop:number} +var m: IFoo2 = { prop: \"asdf\" }; +var n: IFoo2 = { prop: 42 };// Error: {prop:number} ~> {prop:string} + +" +`; + +exports[`test types_only.js 1`] = ` +"/* @flow */ + +export type inlinedType1 = number; +var a: inlinedType1 = 42; +var b: inlinedType1 = \'asdf\'; // Error: string ~> number + +type standaloneType1 = number; +export type {standaloneType1}; + +type standaloneType2 = number; +export {standaloneType2}; // Error: Missing \`type\` keyword + +export type {talias1, talias2 as talias3, IFoo2} from \"./types_only2\"; + +export interface IFoo { prop: number }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test types_only2.js 1`] = ` +"/* @flow */ + +export type talias1 = number; +export type talias2 = number; +export interface IFoo2 { prop: string }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at printExportDeclaration (/src/printer.js:1774:21) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; diff --git a/tests/export_type/cjs_with_types.js b/tests/export_type/cjs_with_types.js new file mode 100644 index 000000000000..1b174f3ca346 --- /dev/null +++ b/tests/export_type/cjs_with_types.js @@ -0,0 +1,6 @@ +/* @flow */ + +export type talias4 = number; +export interface IFoo { prop: number }; + +module.exports = {} diff --git a/tests/export_type/importer.js b/tests/export_type/importer.js new file mode 100644 index 000000000000..cb35f910304f --- /dev/null +++ b/tests/export_type/importer.js @@ -0,0 +1,32 @@ +/* @flow */ + +import type { + inlinedType1, + standaloneType1, + talias1, + talias3, +} from "./types_only"; + +var a: inlinedType1 = 42; +var b: inlinedType1 = 'asdf'; // Error: string ~> number + +var c: standaloneType1 = 42; +var d: standaloneType1 = 'asdf'; // Error: string ~> number + +var e: talias1 = 42; +var f: talias1 = 'asdf'; // Error: string ~> number + +var g: talias3 = 42; +var h: talias3 = 'asdf'; // Error: string ~> number + +import type {talias4} from "./cjs_with_types"; +var i: talias4 = 42; +var j: talias4 = 'asdf'; // Error: string ~> number + +import {IFoo, IFoo2} from "./types_only"; + +var k: IFoo = {prop: 42}; +var l: IFoo = {prop: 'asdf'}; // Error: {prop:string} ~> {prop:number} + +var m: IFoo2 = {prop: 'asdf'}; +var n: IFoo2 = {prop: 42}; // Error: {prop:number} ~> {prop:string} diff --git a/tests/export_type/jsfmt.spec.js b/tests/export_type/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/export_type/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/export_type/types_only.js b/tests/export_type/types_only.js new file mode 100644 index 000000000000..315e7b6ff150 --- /dev/null +++ b/tests/export_type/types_only.js @@ -0,0 +1,15 @@ +/* @flow */ + +export type inlinedType1 = number; +var a: inlinedType1 = 42; +var b: inlinedType1 = 'asdf'; // Error: string ~> number + +type standaloneType1 = number; +export type {standaloneType1}; + +type standaloneType2 = number; +export {standaloneType2}; // Error: Missing `type` keyword + +export type {talias1, talias2 as talias3, IFoo2} from "./types_only2"; + +export interface IFoo { prop: number }; diff --git a/tests/export_type/types_only2.js b/tests/export_type/types_only2.js new file mode 100644 index 000000000000..4ef72006764c --- /dev/null +++ b/tests/export_type/types_only2.js @@ -0,0 +1,5 @@ +/* @flow */ + +export type talias1 = number; +export type talias2 = number; +export interface IFoo2 { prop: string }; diff --git a/tests/extensions/__snapshots__/jsfmt.spec.js.snap b/tests/extensions/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..27b381d5b26f --- /dev/null +++ b/tests/extensions/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var imp = require('./bar'); +imp(1337); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var imp = require("./bar"); +imp(1337); + +" +`; diff --git a/tests/extensions/foo.js b/tests/extensions/foo.js new file mode 100644 index 000000000000..66c9fcbe962d --- /dev/null +++ b/tests/extensions/foo.js @@ -0,0 +1,2 @@ +var imp = require('./bar'); +imp(1337); diff --git a/tests/extensions/jsfmt.spec.js b/tests/extensions/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/extensions/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/facebook_fbt_none/__snapshots__/jsfmt.spec.js.snap b/tests/facebook_fbt_none/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ca33925515bf --- /dev/null +++ b/tests/facebook_fbt_none/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,23 @@ +exports[`test main.js 1`] = ` +"// @flow +var React = require(\'react\'); +(: React.Element<*>); +(: number); // Error: ReactElement ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/facebook_fbt_none/jsfmt.spec.js b/tests/facebook_fbt_none/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/facebook_fbt_none/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/facebook_fbt_none/main.js b/tests/facebook_fbt_none/main.js new file mode 100644 index 000000000000..46a530d2b702 --- /dev/null +++ b/tests/facebook_fbt_none/main.js @@ -0,0 +1,4 @@ +// @flow +var React = require('react'); +(: React.Element<*>); +(: number); // Error: ReactElement ~> number diff --git a/tests/facebook_fbt_some/__snapshots__/jsfmt.spec.js.snap b/tests/facebook_fbt_some/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..72087bf26494 --- /dev/null +++ b/tests/facebook_fbt_some/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,12 @@ +exports[`test main.js 1`] = ` +"// @flow + +(: number); +(: string); // Error (the libdef in this test marks fbt as number) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +(: number); +(: string);// Error (the libdef in this test marks fbt as number) + +" +`; diff --git a/tests/facebook_fbt_some/flow-typed/__snapshots__/jsfmt.spec.js.snap b/tests/facebook_fbt_some/flow-typed/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..80e8f68130a3 --- /dev/null +++ b/tests/facebook_fbt_some/flow-typed/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test fbt.js 1`] = ` +"type Fbt = number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +type Fbt = number; + +" +`; diff --git a/tests/facebook_fbt_some/flow-typed/fbt.js b/tests/facebook_fbt_some/flow-typed/fbt.js new file mode 100644 index 000000000000..373058cd8684 --- /dev/null +++ b/tests/facebook_fbt_some/flow-typed/fbt.js @@ -0,0 +1 @@ +type Fbt = number diff --git a/tests/facebook_fbt_some/flow-typed/jsfmt.spec.js b/tests/facebook_fbt_some/flow-typed/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/facebook_fbt_some/flow-typed/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/facebook_fbt_some/jsfmt.spec.js b/tests/facebook_fbt_some/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/facebook_fbt_some/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/facebook_fbt_some/main.js b/tests/facebook_fbt_some/main.js new file mode 100644 index 000000000000..01900f6a68e2 --- /dev/null +++ b/tests/facebook_fbt_some/main.js @@ -0,0 +1,4 @@ +// @flow + +(: number); +(: string); // Error (the libdef in this test marks fbt as number) diff --git a/tests/facebookisms/Bar.js b/tests/facebookisms/Bar.js new file mode 100644 index 000000000000..fa9036afc162 --- /dev/null +++ b/tests/facebookisms/Bar.js @@ -0,0 +1,2 @@ +var Bar = { x: 0 }; +module.exports = Bar; diff --git a/tests/facebookisms/__snapshots__/jsfmt.spec.js.snap b/tests/facebookisms/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a92ab7b855eb --- /dev/null +++ b/tests/facebookisms/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,242 @@ +exports[`test Bar.js 1`] = ` +"var Bar = { x: 0 }; +module.exports = Bar; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var Bar = { x: 0 }; +module.exports = Bar; + +" +`; + +exports[`test copyProperties.js 1`] = ` +"// @flow + +let tests = [ + // global + function() { + (copyProperties()); // error, unknown global + }, + + // annotation + function(copyProperties: Object$Assign) { + let result = {}; + result.baz = false; + (copyProperties( + result, + { foo: 'a' }, + { bar: 123 } + ): { foo: string, bar: number, baz: boolean }); + }, + + // module from lib + function() { + const copyProperties = require('copyProperties'); + let x = { foo: 'a' }; + let y = { bar: 123 }; + (copyProperties({}, x, y): { foo: string, bar: number }); + }, + + // too few args + function(copyProperties: Object$Assign) { + copyProperties(); + (copyProperties({ foo: 'a' }): { foo: number }); // err, num !~> string + }, + + // passed as a function + function(copyProperties: Object$Assign) { + function x(cb: Function) {} + x(copyProperties); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // global + function() { + copyProperties();// error, unknown global + }, + // annotation + function(copyProperties: Object$Assign) { + let result = {}; + result.baz = false; + (copyProperties(result, { foo: "a" }, { bar: 123 }): { + foo: string, + bar: number, + baz: boolean + }); + }, + // module from lib + function() { + const copyProperties = require("copyProperties"); + let x = { foo: "a" }; + let y = { bar: 123 }; + (copyProperties({}, x, y): { foo: string, bar: number }); + }, + // too few args + function(copyProperties: Object$Assign) { + copyProperties(); + (copyProperties({ foo: "a" }): { foo: number });// err, num !~> string + }, + // passed as a function + function(copyProperties: Object$Assign) { + function x(cb: Function) { + + } + x(copyProperties); + } +]; + +" +`; + +exports[`test invariant.js 1`] = ` +"/* @flow */ + +let tests = [ + function() { + let x: ?string = null; + invariant(x, 'truthy only'); // error, forgot to require invariant + }, + + function(invariant: Function) { + let x: ?string = null; + invariant(x); + (x: string); + } +] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +let tests = [ + function() { + let x: ?string = null; + invariant(x, "truthy only");// error, forgot to require invariant + }, + function(invariant: Function) { + let x: ?string = null; + invariant(x); + (x: string); + } +]; + +" +`; + +exports[`test lib.js 1`] = ` +"declare module "copyProperties" { + declare var exports: Object$Assign; +} + +declare module "mergeInto" { + declare var exports: $Facebookism$MergeInto; +} + +declare module "mixin" { + declare var exports: $Facebookism$Mixin; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare module "copyProperties" { + declare var exports: Object$Assign; +} +declare module "mergeInto" { + declare var exports: $Facebookism$MergeInto; +} +declare module "mixin" { + declare var exports: $Facebookism$Mixin; +} + +" +`; + +exports[`test mergeInto.js 1`] = ` +"// @flow + +let tests = [ + // global + function() { + (mergeInto()); // error, unknown global + }, + + // annotation + function(mergeInto: $Facebookism$MergeInto) { + let result = {}; + result.baz = false; + (mergeInto(result, { foo: 'a' }, { bar: 123 }): void); + (result: { foo: string, bar: number, baz: boolean }); + }, + + // module from lib + function() { + const mergeInto = require('mergeInto'); + let result: { foo?: string, bar?: number, baz: boolean } = { baz: false }; + (mergeInto(result, { foo: 'a' }, { bar: 123 }): void); + }, + + // too few args + function(mergeInto: $Facebookism$MergeInto) { + mergeInto(); + }, + + // passed as a function + function(mergeInto: $Facebookism$MergeInto) { + function x(cb: Function) {} + x(mergeInto); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + // global + function() { + mergeInto();// error, unknown global + }, + // annotation + function(mergeInto: $Facebookism$MergeInto) { + let result = {}; + result.baz = false; + (mergeInto(result, { foo: "a" }, { bar: 123 }): void); + (result: { foo: string, bar: number, baz: boolean }); + }, + // module from lib + function() { + const mergeInto = require("mergeInto"); + let result: { foo?: string, bar?: number, baz: boolean } = { baz: false }; + (mergeInto(result, { foo: "a" }, { bar: 123 }): void); + }, + // too few args + function(mergeInto: $Facebookism$MergeInto) { + mergeInto(); + }, + // passed as a function + function(mergeInto: $Facebookism$MergeInto) { + function x(cb: Function) { + + } + x(mergeInto); + } +]; + +" +`; + +exports[`test test.js 1`] = ` +"var Bar = require('./Bar'); +var mixin = require('mixin'); + +class Foo extends mixin(Bar) { + m() { + var x: string = this.x; + this.y = ""; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var Bar = require("./Bar"); +var mixin = require("mixin"); +class Foo extends mixin(Bar) { + m() { + var x: string = this.x; + this.y = ""; + } +} + +" +`; diff --git a/tests/facebookisms/copyProperties.js b/tests/facebookisms/copyProperties.js new file mode 100644 index 000000000000..0f20e91b630e --- /dev/null +++ b/tests/facebookisms/copyProperties.js @@ -0,0 +1,39 @@ +// @flow + +let tests = [ + // global + function() { + (copyProperties()); // error, unknown global + }, + + // annotation + function(copyProperties: Object$Assign) { + let result = {}; + result.baz = false; + (copyProperties( + result, + { foo: 'a' }, + { bar: 123 } + ): { foo: string, bar: number, baz: boolean }); + }, + + // module from lib + function() { + const copyProperties = require('copyProperties'); + let x = { foo: 'a' }; + let y = { bar: 123 }; + (copyProperties({}, x, y): { foo: string, bar: number }); + }, + + // too few args + function(copyProperties: Object$Assign) { + copyProperties(); + (copyProperties({ foo: 'a' }): { foo: number }); // err, num !~> string + }, + + // passed as a function + function(copyProperties: Object$Assign) { + function x(cb: Function) {} + x(copyProperties); + } +]; diff --git a/tests/facebookisms/invariant.js b/tests/facebookisms/invariant.js new file mode 100644 index 000000000000..7474dd69d35f --- /dev/null +++ b/tests/facebookisms/invariant.js @@ -0,0 +1,14 @@ +/* @flow */ + +let tests = [ + function() { + let x: ?string = null; + invariant(x, 'truthy only'); // error, forgot to require invariant + }, + + function(invariant: Function) { + let x: ?string = null; + invariant(x); + (x: string); + } +] diff --git a/tests/facebookisms/jsfmt.spec.js b/tests/facebookisms/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/facebookisms/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/facebookisms/lib.js b/tests/facebookisms/lib.js new file mode 100644 index 000000000000..bc96320ec47d --- /dev/null +++ b/tests/facebookisms/lib.js @@ -0,0 +1,11 @@ +declare module "copyProperties" { + declare var exports: Object$Assign; +} + +declare module "mergeInto" { + declare var exports: $Facebookism$MergeInto; +} + +declare module "mixin" { + declare var exports: $Facebookism$Mixin; +} diff --git a/tests/facebookisms/mergeInto.js b/tests/facebookisms/mergeInto.js new file mode 100644 index 000000000000..9b1d08df751a --- /dev/null +++ b/tests/facebookisms/mergeInto.js @@ -0,0 +1,34 @@ +// @flow + +let tests = [ + // global + function() { + (mergeInto()); // error, unknown global + }, + + // annotation + function(mergeInto: $Facebookism$MergeInto) { + let result = {}; + result.baz = false; + (mergeInto(result, { foo: 'a' }, { bar: 123 }): void); + (result: { foo: string, bar: number, baz: boolean }); + }, + + // module from lib + function() { + const mergeInto = require('mergeInto'); + let result: { foo?: string, bar?: number, baz: boolean } = { baz: false }; + (mergeInto(result, { foo: 'a' }, { bar: 123 }): void); + }, + + // too few args + function(mergeInto: $Facebookism$MergeInto) { + mergeInto(); + }, + + // passed as a function + function(mergeInto: $Facebookism$MergeInto) { + function x(cb: Function) {} + x(mergeInto); + } +]; diff --git a/tests/facebookisms/test.js b/tests/facebookisms/test.js new file mode 100644 index 000000000000..5d484ac096fa --- /dev/null +++ b/tests/facebookisms/test.js @@ -0,0 +1,9 @@ +var Bar = require('./Bar'); +var mixin = require('mixin'); + +class Foo extends mixin(Bar) { + m() { + var x: string = this.x; + this.y = ""; + } +} diff --git a/tests/fetch/__snapshots__/jsfmt.spec.js.snap b/tests/fetch/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6c8225a8ddec --- /dev/null +++ b/tests/fetch/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,329 @@ +exports[`test fetch.js 1`] = ` +"/* @flow */ + +// most of the details are tested in the separate file +// here I test the basic usage + +const myRequest = new Request(\'http://google.com\'); + +const a: Promise = + fetch(myRequest) + .then(response => response.text()); + +const b: Promise = fetch(myRequest); // incorrect + +var myInit = { method: \'GET\', + headers: { + \'Content-Type\': \'image/jpeg\' + }, + mode: \'cors\', + cache: \'default\' }; + +const c: Promise = + fetch(\'image.png\') + .then(response => response.blob()); // correct + +const d: Promise = fetch(\'image.png\'); // incorrect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test headers.js 1`] = ` +"/* @flow */ + +const a = new Headers(\"\'Content-Type\': \'image/jpeg\'\"); // not correct +const b = new Headers([\'Content-Type\', \'image/jpeg\']); // not correct +const c = new Headers({\'Content-Type\', \'image/jpeg\'}); // correct +const d = new Headers(c); // correct +const e: Headers = new Headers(); // correct +e.append(\'Content-Type\', \'image/jpeg\'); // correct +e.append(\'Content-Type\'); // not correct +e.append({\'Content-Type\', \'image/jpeg\'}); // not correct +e.set(\'Content-Type\', \'image/jpeg\'); // correct +e.set(\'Content-Type\'); // not correct +e.set({\'Content-Type\', \'image/jpeg\'}); // not correct + +const f: Headers = e.append(\'Content-Type\', \'image/jpeg\'); // not correct + +const g: string = e.get(\'Content-Type\'); // correct +const h: number = e.get(\'Content-Type\'); // not correct + +for (let v of e) { + const [i, j]: [string, string] = v; // correct +} + +for (let v of e.entries()) { + const [i, j]: [string, string] = v; // correct +} + +e.getAll(\'content-type\').forEach((v: string) => {}); // correct +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:37) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseObjPropValue (/node_modules/babylon/lib/index.js:3940:8) + at Parser.parseObjPropValue (/node_modules/babylon/lib/index.js:5537:13) + at Parser.pp$3.parseObj (/node_modules/babylon/lib/index.js:3871:10) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3561:19) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) +" +`; + +exports[`test request.js 1`] = ` +"/* @flow */ +const a: Request = new Request(); // incorrect +const b: Request = new Request(\'http://example.org\'); // correct +const c: Request = new Request(b); // correct +const d: Request = new Request(c.clone()); // correct (doesn\'t make much sense though) +const e: Request = new Request(b, c); // incorrect + +const f: Request = new Request({}) // incorrect +const g: Request = new Request(\'http://example.org\', {}) // correct + +const h: Request = new Request(\'http://example.org\', { + method: \'GET\', + headers: { + \'Content-Type\': \'image/jpeg\' + }, + mode: \'cors\', + cache: \'default\' +}) // correct + +const i: Request = new Request(\'http://example.org\', { + method: \'POST\', + headers: { + \'Content-Type\': \'image/jpeg\' + }, + body: new URLSearchParams(\"key=value\"), + mode: \'cors\', + cache: \'default\' +}) // correct + +const j: Request = new Request(\'http://example.org\', { + method: \'GET\', + headers: \'Content-Type: image/jpeg\', + mode: \'cors\', + cache: \'default\' +}) // incorrect - headers is string + +const k: Request = new Request(\'http://example.org\', { + method: \'CONNECT\', + headers: { + \'Content-Type\': \'image/jpeg\' + }, + mode: \'cors\', + cache: \'default\' +}) // incorrect - CONNECT is forbidden + +var l: boolean = h.bodyUsed; + +h.text().then((t: string) => t); // correct +h.text().then((t: Buffer) => t); // incorrect +h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct +h.arrayBuffer().then((ab: Buffer) => ab); // incorrect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +const a: Request = new Request();// incorrect +const b: Request = new Request(\"http://example.org\");// correct +const c: Request = new Request(b);// correct +const d: Request = new Request( + c.clone() +);// correct (doesn\'t make much sense though) +const e: Request = new Request(b, c);// incorrect +const f: Request = new Request({});// incorrect +const g: Request = new Request(\"http://example.org\", {});// correct +const h: Request = new Request( + \"http://example.org\", + { + method: \"GET\", + headers: { \"Content-Type\": \"image/jpeg\" }, + mode: \"cors\", + cache: \"default\" + } +);// correct +const i: Request = new Request( + \"http://example.org\", + { + method: \"POST\", + headers: { \"Content-Type\": \"image/jpeg\" }, + body: new URLSearchParams(\"key=value\"), + mode: \"cors\", + cache: \"default\" + } +);// correct +const j: Request = new Request( + \"http://example.org\", + { + method: \"GET\", + headers: \"Content-Type: image/jpeg\", + mode: \"cors\", + cache: \"default\" + } +);// incorrect - headers is string +const k: Request = new Request( + \"http://example.org\", + { + method: \"CONNECT\", + headers: { \"Content-Type\": \"image/jpeg\" }, + mode: \"cors\", + cache: \"default\" + } +);// incorrect - CONNECT is forbidden +var l: boolean = h.bodyUsed; +h.text().then((t: string) => t);// correct +h.text().then((t: Buffer) => t);// incorrect +h.arrayBuffer().then((ab: ArrayBuffer) => ab);// correct +h.arrayBuffer().then((ab: Buffer) => ab);// incorrect + +" +`; + +exports[`test response.js 1`] = ` +"/* @flow */ +const a: Response = new Response(); // correct +const b: Response = new Response(new Blob()); // correct +const c: Response = new Response(new FormData()); // correct + +const d: Response = new Response(new FormData(), { + status: 404 +}); // correct + +const e: Response = new Response(\"responsebody\", { + status: \"404\" +}); // incorrect + +const f: Response = new Response(\"responsebody\", { + status: 404, + headers: \"\'Content-Type\': \'image/jpeg\'\" +}); // incorrect + +const g: Response = new Response(\"responsebody\", { + status: 404, + headers: { + \'Content-Type\': \'image/jpeg\' + } +}); // correct + +const h: Response = new Response(\"responsebody\", { + status: 404, + headers: new Headers({ + \'Content-Type\': \'image/jpeg\' + }) +}); // correct, if verbose + +const i: Response = new Response({ + status: 404, + headers: new Headers({ + \'Content-Type\': \'image/jpeg\' + }) +}); // incorrect + +const ok: boolean = h.ok; +const status: number = h.status; + +h.text().then((t: string) => t); // correct +h.text().then((t: Buffer) => t); // incorrect +h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct +h.arrayBuffer().then((ab: Buffer) => ab); // incorrect +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +const a: Response = new Response();// correct +const b: Response = new Response(new Blob());// correct +const c: Response = new Response(new FormData());// correct +const d: Response = new Response(new FormData(), { status: 404 });// correct +const e: Response = new Response(\"responsebody\", { status: \"404\" });// incorrect +const f: Response = new Response( + \"responsebody\", + { status: 404, headers: \"\'Content-Type\': \'image/jpeg\'\" } +);// incorrect +const g: Response = new Response( + \"responsebody\", + { status: 404, headers: { \"Content-Type\": \"image/jpeg\" } } +);// correct +const h: Response = new Response( + \"responsebody\", + { status: 404, headers: new Headers({ \"Content-Type\": \"image/jpeg\" }) } +);// correct, if verbose +const i: Response = new Response({ + status: 404, + headers: new Headers({ \"Content-Type\": \"image/jpeg\" }) +});// incorrect +const ok: boolean = h.ok; +const status: number = h.status; +h.text().then((t: string) => t);// correct +h.text().then((t: Buffer) => t);// incorrect +h.arrayBuffer().then((ab: ArrayBuffer) => ab);// correct +h.arrayBuffer().then((ab: Buffer) => ab);// incorrect + +" +`; + +exports[`test urlsearchparams.js 1`] = ` +"/* @flow */ + +const a = new URLSearchParams(\"key1=value1\"); // correct +const b = new URLSearchParams([\'key1\', \'value1\']); // not correct +const c = new URLSearchParams({\'key1\', \'value1\'}); // not correct +const d = new URLSearchParams(c); // correct +const e: URLSearchParams = new URLSearchParams(); // correct +e.append(\'key1\', \'value1\'); // correct +e.append(\'key1\'); // not correct +e.append({\'key1\', \'value1\'}); // not correct +e.set(\'key1\', \'value1\'); // correct +e.set(\'key1\'); // not correct +e.set({\'key1\', \'value1\'}); // not correct + +const f: URLSearchParams = e.append(\'key1\', \'value1\'); // not correct + +const g: string = e.get(\'key1\'); // correct +const h: number = e.get(\'key1\'); // not correct + +for (let v of e) { + const [i, j]: [string, string] = v; // correct +} + +for (let v of e.entries()) { + const [i, j]: [string, string] = v; // correct +} + +e.getAll(\'key1\').forEach((v: string) => {}); // correct +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:37) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseObjPropValue (/node_modules/babylon/lib/index.js:3940:8) + at Parser.parseObjPropValue (/node_modules/babylon/lib/index.js:5537:13) + at Parser.pp$3.parseObj (/node_modules/babylon/lib/index.js:3871:10) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3561:19) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) +" +`; diff --git a/tests/fetch/fetch.js b/tests/fetch/fetch.js new file mode 100644 index 000000000000..bd1f44a84333 --- /dev/null +++ b/tests/fetch/fetch.js @@ -0,0 +1,25 @@ +/* @flow */ + +// most of the details are tested in the separate file +// here I test the basic usage + +const myRequest = new Request('http://google.com'); + +const a: Promise = + fetch(myRequest) + .then(response => response.text()); + +const b: Promise = fetch(myRequest); // incorrect + +var myInit = { method: 'GET', + headers: { + 'Content-Type': 'image/jpeg' + }, + mode: 'cors', + cache: 'default' }; + +const c: Promise = + fetch('image.png') + .then(response => response.blob()); // correct + +const d: Promise = fetch('image.png'); // incorrect diff --git a/tests/fetch/headers.js b/tests/fetch/headers.js new file mode 100644 index 000000000000..9eab0d99635b --- /dev/null +++ b/tests/fetch/headers.js @@ -0,0 +1,28 @@ +/* @flow */ + +const a = new Headers("'Content-Type': 'image/jpeg'"); // not correct +const b = new Headers(['Content-Type', 'image/jpeg']); // not correct +const c = new Headers({'Content-Type', 'image/jpeg'}); // correct +const d = new Headers(c); // correct +const e: Headers = new Headers(); // correct +e.append('Content-Type', 'image/jpeg'); // correct +e.append('Content-Type'); // not correct +e.append({'Content-Type', 'image/jpeg'}); // not correct +e.set('Content-Type', 'image/jpeg'); // correct +e.set('Content-Type'); // not correct +e.set({'Content-Type', 'image/jpeg'}); // not correct + +const f: Headers = e.append('Content-Type', 'image/jpeg'); // not correct + +const g: string = e.get('Content-Type'); // correct +const h: number = e.get('Content-Type'); // not correct + +for (let v of e) { + const [i, j]: [string, string] = v; // correct +} + +for (let v of e.entries()) { + const [i, j]: [string, string] = v; // correct +} + +e.getAll('content-type').forEach((v: string) => {}); // correct diff --git a/tests/fetch/jsfmt.spec.js b/tests/fetch/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/fetch/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/fetch/request.js b/tests/fetch/request.js new file mode 100644 index 000000000000..1f8981e91f28 --- /dev/null +++ b/tests/fetch/request.js @@ -0,0 +1,51 @@ +/* @flow */ +const a: Request = new Request(); // incorrect +const b: Request = new Request('http://example.org'); // correct +const c: Request = new Request(b); // correct +const d: Request = new Request(c.clone()); // correct (doesn't make much sense though) +const e: Request = new Request(b, c); // incorrect + +const f: Request = new Request({}) // incorrect +const g: Request = new Request('http://example.org', {}) // correct + +const h: Request = new Request('http://example.org', { + method: 'GET', + headers: { + 'Content-Type': 'image/jpeg' + }, + mode: 'cors', + cache: 'default' +}) // correct + +const i: Request = new Request('http://example.org', { + method: 'POST', + headers: { + 'Content-Type': 'image/jpeg' + }, + body: new URLSearchParams("key=value"), + mode: 'cors', + cache: 'default' +}) // correct + +const j: Request = new Request('http://example.org', { + method: 'GET', + headers: 'Content-Type: image/jpeg', + mode: 'cors', + cache: 'default' +}) // incorrect - headers is string + +const k: Request = new Request('http://example.org', { + method: 'CONNECT', + headers: { + 'Content-Type': 'image/jpeg' + }, + mode: 'cors', + cache: 'default' +}) // incorrect - CONNECT is forbidden + +var l: boolean = h.bodyUsed; + +h.text().then((t: string) => t); // correct +h.text().then((t: Buffer) => t); // incorrect +h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct +h.arrayBuffer().then((ab: Buffer) => ab); // incorrect diff --git a/tests/fetch/response.js b/tests/fetch/response.js new file mode 100644 index 000000000000..f68b4d8b3493 --- /dev/null +++ b/tests/fetch/response.js @@ -0,0 +1,46 @@ +/* @flow */ +const a: Response = new Response(); // correct +const b: Response = new Response(new Blob()); // correct +const c: Response = new Response(new FormData()); // correct + +const d: Response = new Response(new FormData(), { + status: 404 +}); // correct + +const e: Response = new Response("responsebody", { + status: "404" +}); // incorrect + +const f: Response = new Response("responsebody", { + status: 404, + headers: "'Content-Type': 'image/jpeg'" +}); // incorrect + +const g: Response = new Response("responsebody", { + status: 404, + headers: { + 'Content-Type': 'image/jpeg' + } +}); // correct + +const h: Response = new Response("responsebody", { + status: 404, + headers: new Headers({ + 'Content-Type': 'image/jpeg' + }) +}); // correct, if verbose + +const i: Response = new Response({ + status: 404, + headers: new Headers({ + 'Content-Type': 'image/jpeg' + }) +}); // incorrect + +const ok: boolean = h.ok; +const status: number = h.status; + +h.text().then((t: string) => t); // correct +h.text().then((t: Buffer) => t); // incorrect +h.arrayBuffer().then((ab: ArrayBuffer) => ab); // correct +h.arrayBuffer().then((ab: Buffer) => ab); // incorrect diff --git a/tests/fetch/urlsearchparams.js b/tests/fetch/urlsearchparams.js new file mode 100644 index 000000000000..f40aae313f36 --- /dev/null +++ b/tests/fetch/urlsearchparams.js @@ -0,0 +1,28 @@ +/* @flow */ + +const a = new URLSearchParams("key1=value1"); // correct +const b = new URLSearchParams(['key1', 'value1']); // not correct +const c = new URLSearchParams({'key1', 'value1'}); // not correct +const d = new URLSearchParams(c); // correct +const e: URLSearchParams = new URLSearchParams(); // correct +e.append('key1', 'value1'); // correct +e.append('key1'); // not correct +e.append({'key1', 'value1'}); // not correct +e.set('key1', 'value1'); // correct +e.set('key1'); // not correct +e.set({'key1', 'value1'}); // not correct + +const f: URLSearchParams = e.append('key1', 'value1'); // not correct + +const g: string = e.get('key1'); // correct +const h: number = e.get('key1'); // not correct + +for (let v of e) { + const [i, j]: [string, string] = v; // correct +} + +for (let v of e.entries()) { + const [i, j]: [string, string] = v; // correct +} + +e.getAll('key1').forEach((v: string) => {}); // correct diff --git a/tests/find-module/__snapshots__/jsfmt.spec.js.snap b/tests/find-module/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2855edc03840 --- /dev/null +++ b/tests/find-module/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +exports[`test req.js 1`] = ` +"module.exports = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = 0; + +" +`; + +exports[`test test.js 1`] = ` +"var x = require('./req'); +(x: string); + +import x from './req'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("./req"); +(x: string); +import x from "./req"; + +" +`; diff --git a/tests/find-module/jsfmt.spec.js b/tests/find-module/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/find-module/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/find-module/req.js b/tests/find-module/req.js new file mode 100644 index 000000000000..d5b2e8bb3efb --- /dev/null +++ b/tests/find-module/req.js @@ -0,0 +1 @@ +module.exports = 0; diff --git a/tests/find-module/test.js b/tests/find-module/test.js new file mode 100644 index 000000000000..79de263f6960 --- /dev/null +++ b/tests/find-module/test.js @@ -0,0 +1,4 @@ +var x = require('./req'); +(x: string); + +import x from './req'; diff --git a/tests/find-refs/__snapshots__/jsfmt.spec.js.snap b/tests/find-refs/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bd0b87986865 --- /dev/null +++ b/tests/find-refs/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,77 @@ +exports[`test locals.js 1`] = ` +"// @flow + +// Variable defs and uses +var foo = function() { }; +foo(); +foo = null; +foo(); + +// Nested functions +function bar() { + function bar() { + } + bar(); +} +bar(); + +// Classes +class C { } +new C; +class D extends C { } + +// Type aliases +type T = number; +type S = T; +((_: T) => {}); + +// Refinements +let nullable: ?string = \"\"; +if (nullable != null) { + console.log(nullable.length); + nullable = null; +} +(nullable: null); + +// Destructuring +let { x, y } = { x: 0, y: 0 }; +let { x: _x, y: _y } = { x, y }; +({ x: _x, y: _y }); + +// Not in scope +wut1; +wut1 = wut2; +wut2; + +// JSX +var React = require(\'react\'); +class Fancy extends React.Component { + props: { x: number }; +} +; + +// Imports +import { wut3 } from \'wutland\'; +import type { wut4 } from \'wutland\'; +(wut3: wut4); + +// Qualified types +(null: React.Component); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:5687 + throw jsxError || err; + ^ + +SyntaxError: JSX value should be either an expression or a quoted JSX text (50:9) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp$8.jsxParseAttributeValue (/node_modules/babylon/lib/index.js:6255:12) + at Parser.pp$8.jsxParseAttribute (/node_modules/babylon/lib/index.js:6306:42) + at Parser.pp$8.jsxParseOpeningElementAt (/node_modules/babylon/lib/index.js:6317:31) + at Parser.pp$8.jsxParseElementAt (/node_modules/babylon/lib/index.js:6339:29) + at Parser.pp$8.jsxParseElement (/node_modules/babylon/lib/index.js:6394:15) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6406:21) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) +" +`; diff --git a/tests/find-refs/jsfmt.spec.js b/tests/find-refs/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/find-refs/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/find-refs/locals.js b/tests/find-refs/locals.js new file mode 100644 index 000000000000..5651166c1f62 --- /dev/null +++ b/tests/find-refs/locals.js @@ -0,0 +1,58 @@ +// @flow + +// Variable defs and uses +var foo = function() { }; +foo(); +foo = null; +foo(); + +// Nested functions +function bar() { + function bar() { + } + bar(); +} +bar(); + +// Classes +class C { } +new C; +class D extends C { } + +// Type aliases +type T = number; +type S = T; +((_: T) => {}); + +// Refinements +let nullable: ?string = ""; +if (nullable != null) { + console.log(nullable.length); + nullable = null; +} +(nullable: null); + +// Destructuring +let { x, y } = { x: 0, y: 0 }; +let { x: _x, y: _y } = { x, y }; +({ x: _x, y: _y }); + +// Not in scope +wut1; +wut1 = wut2; +wut2; + +// JSX +var React = require('react'); +class Fancy extends React.Component { + props: { x: number }; +} +; + +// Imports +import { wut3 } from 'wutland'; +import type { wut4 } from 'wutland'; +(wut3: wut4); + +// Qualified types +(null: React.Component); diff --git a/tests/fixpoint/Fun.js b/tests/fixpoint/Fun.js new file mode 100644 index 000000000000..944a780d1260 --- /dev/null +++ b/tests/fixpoint/Fun.js @@ -0,0 +1,30 @@ + +/* @providesModule Fun */ + +function eq(x:number,y:number) { return true }; +function sub(x:number,y:number) { return 0; } +function mul(x:number,y:number) { return 0; } + +function fix(fold) { + var delta = function(delta) { + return fold( + function(x) { var eta = delta(delta); return eta(x); } + ); + }; + return delta(delta); +} + +function mk_factorial() { + return fix(function(factorial) { + return function(n) { + if (eq (n, 1)) { return 1; } + return mul (factorial (sub (n, 1)), n); + }; + }); +} + + +var factorial = mk_factorial(); +factorial("..."); + +module.exports = {fn: fix}; diff --git a/tests/fixpoint/Ycombinator.js b/tests/fixpoint/Ycombinator.js new file mode 100644 index 000000000000..d433603e5ca0 --- /dev/null +++ b/tests/fixpoint/Ycombinator.js @@ -0,0 +1,21 @@ + +/* @providesModule Ycombinator */ + +function Y(f) { + function g(x) { return f(x(x)); } + g(g); +} + +function func1(f) { + function fix_f(x:number):number { return f(x); } + return fix_f; +} +function func2(f) { + function fix_f(x:string):string { return f(x); } + return fix_f; +} + +Y(func1); +Y(func2); + +module.exports = Y; diff --git a/tests/fixpoint/__snapshots__/jsfmt.spec.js.snap b/tests/fixpoint/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b397dc2a755f --- /dev/null +++ b/tests/fixpoint/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,120 @@ +exports[`test Fun.js 1`] = ` +" +/* @providesModule Fun */ + +function eq(x:number,y:number) { return true }; +function sub(x:number,y:number) { return 0; } +function mul(x:number,y:number) { return 0; } + +function fix(fold) { + var delta = function(delta) { + return fold( + function(x) { var eta = delta(delta); return eta(x); } + ); + }; + return delta(delta); +} + +function mk_factorial() { + return fix(function(factorial) { + return function(n) { + if (eq (n, 1)) { return 1; } + return mul (factorial (sub (n, 1)), n); + }; + }); +} + + +var factorial = mk_factorial(); +factorial("..."); + +module.exports = {fn: fix}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Fun */ +function eq(x: number, y: number) { + return true; +} +function sub(x: number, y: number) { + return 0; +} +function mul(x: number, y: number) { + return 0; +} +function fix(fold) { + var delta = function(delta) { + return fold( + function(x) { + var eta = delta(delta); + return eta(x); + } + ); + }; + return delta(delta); +} +function mk_factorial() { + return fix( + function(factorial) { + return function(n) { + if (eq(n, 1)) { + return 1; + } + return mul(factorial(sub(n, 1)), n); + }; + } + ); +} +var factorial = mk_factorial(); +factorial("..."); +module.exports = { fn: fix }; + +" +`; + +exports[`test Ycombinator.js 1`] = ` +" +/* @providesModule Ycombinator */ + +function Y(f) { + function g(x) { return f(x(x)); } + g(g); +} + +function func1(f) { + function fix_f(x:number):number { return f(x); } + return fix_f; +} +function func2(f) { + function fix_f(x:string):string { return f(x); } + return fix_f; +} + +Y(func1); +Y(func2); + +module.exports = Y; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Ycombinator */ +function Y(f) { + function g(x) { + return f(x(x)); + } + g(g); +} +function func1(f) { + function fix_f(x: number): number { + return f(x); + } + return fix_f; +} +function func2(f) { + function fix_f(x: string): string { + return f(x); + } + return fix_f; +} +Y(func1); +Y(func2); +module.exports = Y; + +" +`; diff --git a/tests/fixpoint/jsfmt.spec.js b/tests/fixpoint/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/fixpoint/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/flow_ast.template_strings/__snapshots__/jsfmt.spec.js.snap b/tests/flow_ast.template_strings/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f3ef97d9d279 --- /dev/null +++ b/tests/flow_ast.template_strings/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test foo.js 1`] = ` +"a\`foo \${bar} baz\` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +a\`foo \${bar} baz\`; + +" +`; diff --git a/tests/flow_ast.template_strings/foo.js b/tests/flow_ast.template_strings/foo.js new file mode 100644 index 000000000000..201691617f58 --- /dev/null +++ b/tests/flow_ast.template_strings/foo.js @@ -0,0 +1 @@ +a`foo ${bar} baz` diff --git a/tests/flow_ast.template_strings/jsfmt.spec.js b/tests/flow_ast.template_strings/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/flow_ast.template_strings/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/for/__snapshots__/jsfmt.spec.js.snap b/tests/for/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..84356a0db27e --- /dev/null +++ b/tests/for/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,272 @@ +exports[`test abnormal.js 1`] = ` +"/* @flow */ + +function foo(x: boolean) { + var max = 10; + for (var ii = 0; ii < max; ii++) { + if (x) { + continue; + } + return; + } + console.log('this is still reachable'); +} + +function bar(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + return; + } + console.log('this is still reachable'); +} + +function baz(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + continue; + } + console.log('this is still reachable'); +} + +function bliffl(x: boolean) { + var max = 10; + loop1: for (var ii = 0; ii < max; ii++) { + loop2: for (var jj = 0; jj < max; jj++) { + break loop1; + } + console.log('this is still reachable'); + } + console.log('this is still reachable'); +} + +function corge(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + break; + } + console.log('this is still reachable'); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo(x: boolean) { + var max = 10; + for (var ii = 0; ii < max; ii++) { + if (x) { + continue; + } + return; + } + console.log("this is still reachable"); +} +function bar(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + return; + } + console.log("this is still reachable"); +} +function baz(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + continue; + } + console.log("this is still reachable"); +} +function bliffl(x: boolean) { + var max = 10; + loop1: +for (var ii = 0; ii < max; ii++) { + loop2: +for (var jj = 0; jj < max; jj++) { + break loop1; + } + console.log("this is still reachable"); + } + console.log("this is still reachable"); +} +function corge(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + break; + } + console.log("this is still reachable"); +} + +" +`; + +exports[`test abnormal_for_in.js 1`] = ` +"function foo(x: boolean) { + var obj = { a: 1, b: 2}; + for (var prop in obj) { + if (x) { + continue; + } + return; + } + console.log('this is still reachable'); +} + +function bar(x: boolean) { + for (var prop in {}) { + return; + } + console.log('this is still reachable'); +} + +function baz(x: boolean) { + for (var prop in {}) { + continue; + } + console.log('this is still reachable'); +} + +function bliffl(x: boolean) { + var obj = { a: 1, b: 2}; + loop1: for (var prop1 in obj) { + loop2: for (var prop2 in obj) { + break loop1; + } + console.log('this is still reachable'); + } + console.log('this is still reachable'); +} + +function corge(x: boolean) { + for (var prop in {}) { + break; + } + console.log('this is still reachable'); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(x: boolean) { + var obj = { a: 1, b: 2 }; + for (var prop in obj) { + if (x) { + continue; + } + return; + } + console.log("this is still reachable"); +} +function bar(x: boolean) { + for (var prop in {}) { + return; + } + console.log("this is still reachable"); +} +function baz(x: boolean) { + for (var prop in {}) { + continue; + } + console.log("this is still reachable"); +} +function bliffl(x: boolean) { + var obj = { a: 1, b: 2 }; + loop1: +for (var prop1 in obj) { + loop2: +for (var prop2 in obj) { + break loop1; + } + console.log("this is still reachable"); + } + console.log("this is still reachable"); +} +function corge(x: boolean) { + for (var prop in {}) { + break; + } + console.log("this is still reachable"); +} + +" +`; + +exports[`test abnormal_for_of.js 1`] = ` +"function foo(x: boolean) { + var arr = [1, 2, 3]; + for (var elem of arr) { + if (x) { + continue; + } + return; + } + console.log('this is still reachable'); +} + +function bar(x: boolean) { + for (var elem of []) { + return; + } + console.log('this is still reachable'); +} + +function baz(x: boolean) { + for (var elem of []) { + continue; + } + console.log('this is still reachable'); +} + +function bliffl(x: boolean) { + var arr = [1, 2, 3]; + loop1: for (var elem of arr) { + loop2: for (var elem of arr) { + break loop1; + } + console.log('this is still reachable'); + } + console.log('this is still reachable'); +} + +function corge(x: boolean) { + for (var elem of []) { + break; + } + console.log('this is still reachable'); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(x: boolean) { + var arr = [ 1, 2, 3 ]; + for (var elem of arr) { + if (x) { + continue; + } + return; + } + console.log("this is still reachable"); +} +function bar(x: boolean) { + for (var elem of [ ]) { + return; + } + console.log("this is still reachable"); +} +function baz(x: boolean) { + for (var elem of [ ]) { + continue; + } + console.log("this is still reachable"); +} +function bliffl(x: boolean) { + var arr = [ 1, 2, 3 ]; + loop1: +for (var elem of arr) { + loop2: +for (var elem of arr) { + break loop1; + } + console.log("this is still reachable"); + } + console.log("this is still reachable"); +} +function corge(x: boolean) { + for (var elem of [ ]) { + break; + } + console.log("this is still reachable"); +} + +" +`; diff --git a/tests/for/abnormal.js b/tests/for/abnormal.js new file mode 100644 index 000000000000..cc588841c2d6 --- /dev/null +++ b/tests/for/abnormal.js @@ -0,0 +1,47 @@ +/* @flow */ + +function foo(x: boolean) { + var max = 10; + for (var ii = 0; ii < max; ii++) { + if (x) { + continue; + } + return; + } + console.log('this is still reachable'); +} + +function bar(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + return; + } + console.log('this is still reachable'); +} + +function baz(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + continue; + } + console.log('this is still reachable'); +} + +function bliffl(x: boolean) { + var max = 10; + loop1: for (var ii = 0; ii < max; ii++) { + loop2: for (var jj = 0; jj < max; jj++) { + break loop1; + } + console.log('this is still reachable'); + } + console.log('this is still reachable'); +} + +function corge(x: boolean) { + var max = 0; + for (var ii = 0; ii < max; ii++) { + break; + } + console.log('this is still reachable'); +} diff --git a/tests/for/abnormal_for_in.js b/tests/for/abnormal_for_in.js new file mode 100644 index 000000000000..add7d98c52b2 --- /dev/null +++ b/tests/for/abnormal_for_in.js @@ -0,0 +1,42 @@ +function foo(x: boolean) { + var obj = { a: 1, b: 2}; + for (var prop in obj) { + if (x) { + continue; + } + return; + } + console.log('this is still reachable'); +} + +function bar(x: boolean) { + for (var prop in {}) { + return; + } + console.log('this is still reachable'); +} + +function baz(x: boolean) { + for (var prop in {}) { + continue; + } + console.log('this is still reachable'); +} + +function bliffl(x: boolean) { + var obj = { a: 1, b: 2}; + loop1: for (var prop1 in obj) { + loop2: for (var prop2 in obj) { + break loop1; + } + console.log('this is still reachable'); + } + console.log('this is still reachable'); +} + +function corge(x: boolean) { + for (var prop in {}) { + break; + } + console.log('this is still reachable'); +} diff --git a/tests/for/abnormal_for_of.js b/tests/for/abnormal_for_of.js new file mode 100644 index 000000000000..f6724018ed55 --- /dev/null +++ b/tests/for/abnormal_for_of.js @@ -0,0 +1,42 @@ +function foo(x: boolean) { + var arr = [1, 2, 3]; + for (var elem of arr) { + if (x) { + continue; + } + return; + } + console.log('this is still reachable'); +} + +function bar(x: boolean) { + for (var elem of []) { + return; + } + console.log('this is still reachable'); +} + +function baz(x: boolean) { + for (var elem of []) { + continue; + } + console.log('this is still reachable'); +} + +function bliffl(x: boolean) { + var arr = [1, 2, 3]; + loop1: for (var elem of arr) { + loop2: for (var elem of arr) { + break loop1; + } + console.log('this is still reachable'); + } + console.log('this is still reachable'); +} + +function corge(x: boolean) { + for (var elem of []) { + break; + } + console.log('this is still reachable'); +} diff --git a/tests/for/jsfmt.spec.js b/tests/for/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/for/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/forof/__snapshots__/jsfmt.spec.js.snap b/tests/forof/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c772d3d905fc --- /dev/null +++ b/tests/forof/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,72 @@ +exports[`test forof.js 1`] = ` +"/** + * @flow + */ + +function testArray(arr: Array): void { + for (var x of arr) { + (x: string); // Error - number ~> string + } +} + +function testIterable1(iterable: Iterable): void { + for (var x of iterable) { + (x: string); // Error - number ~> string + } +} + +function testIterable2(iterable: Iterable<*>): void { + for (var x of iterable) { + (x: string); + } +} + +function testString(str: string): void { + for (var x of str) { + (x: number); // Error - string ~> number + } +} + +function testMap1(map: Map): void { + for (var elem of map) { + (elem: [string, number]); + (elem: number); // Error - tuple ~> number + } +} + +function testMap2(map: Map<*, *>): void { + for (var elem of map) { + (elem: [number, string]); // Any tuple is fine + (elem: number); // Error - tuple ~> number + } +} + +function testSet1(set: Set): void { + for (var x of set) { + (x: number); // Error - string ~> number + } +} + +function testSet2(set: Set<*>): void { + for (var x of set) { + (x: number); // Anything goes + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/forof/forof.js b/tests/forof/forof.js new file mode 100644 index 000000000000..ffcece1b14a0 --- /dev/null +++ b/tests/forof/forof.js @@ -0,0 +1,53 @@ +/** + * @flow + */ + +function testArray(arr: Array): void { + for (var x of arr) { + (x: string); // Error - number ~> string + } +} + +function testIterable1(iterable: Iterable): void { + for (var x of iterable) { + (x: string); // Error - number ~> string + } +} + +function testIterable2(iterable: Iterable<*>): void { + for (var x of iterable) { + (x: string); + } +} + +function testString(str: string): void { + for (var x of str) { + (x: number); // Error - string ~> number + } +} + +function testMap1(map: Map): void { + for (var elem of map) { + (elem: [string, number]); + (elem: number); // Error - tuple ~> number + } +} + +function testMap2(map: Map<*, *>): void { + for (var elem of map) { + (elem: [number, string]); // Any tuple is fine + (elem: number); // Error - tuple ~> number + } +} + +function testSet1(set: Set): void { + for (var x of set) { + (x: number); // Error - string ~> number + } +} + +function testSet2(set: Set<*>): void { + for (var x of set) { + (x: number); // Anything goes + } +} diff --git a/tests/forof/jsfmt.spec.js b/tests/forof/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/forof/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/function/__snapshots__/jsfmt.spec.js.snap b/tests/function/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..668c46396d01 --- /dev/null +++ b/tests/function/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,287 @@ +exports[`test apply.js 1`] = ` +"function test(a: string, b: number): number { + return this.length; // expect []/\"\" this +} + +// tuples flow correctly into params +test.apply(\"\", [\"\", 0]); + +// wrong this is an error +test.apply(0, [\"\", 0]); // error: lookup \`length\` on Number + +// not enough arguments is an error (via incompatible RestT) +test.apply(\"\", [\"\"]); // error: string ~> number + +// mistyped arguments is an error +test.apply(\"\", [\"\", \"\"]); // error: string ~> number (2nd arg) +test.apply(\"\", [0, 0]); // error: number ~> string (1st arg) + +// resolve args array from tvar +function f(args) { test.apply(\"\", args) } +f([\"\", 0]); // OK +f([\"\", \"\"]); // error: string ~> number (2nd arg) +f([0, 0]); // error: number ~> string (1st arg) + +// expect array +test.apply(\"\", \"not array\"); // error: expect array of args + +// expect 4 errors: +// - lookup length on Number (because 0 is used as \`this\`) +// - 123 is not a string +// - \'foo\' is not a number +// - return type (number) is not void +(test.call.apply(test, [0, 123, \'foo\']): void); + +// expect 2 errors: +// - lookup length on number (0 is used as \`this\`) +// - 123 is not a string +(test.bind.apply(test, [0, 123]): (b: number) => number); + +// args are optional +function test2(): number { return 0; } +(test2.apply(): number); +(test2.apply(\"\"): number); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test bind.js 1`] = ` +"// @flow + +let tests = [ + function(x: (a: string, b: string) => void) { + let y = x.bind(x, \'foo\'); + y(\'bar\'); // ok + y(123); // error, number !~> string + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test call.js 1`] = ` +"// @flow + +function test(a: string, b: number): number { + return this.length; // expect []/\"\" this +} + +// args flow correctly into params +test.call(\"\", \"\", 0); + +// wrong this is an error +test.call(0, \"\", 0); // error: lookup \`length\` on Number + +// not enough arguments is an error (via incompatible RestT) +test.call(\"\", \"\"); // error: string ~> number + +// mistyped arguments is an error +test.call(\"\", \"\", \"\"); // error: string ~> number (2nd arg) +test.call(\"\", 0, 0); // error: number ~> string (1st arg) + +// resolve args array from tvar +function f(args) { test.call(\"\", args[0], args[1]) } +f([\"\", 0]); // OK +f([\"\", \"\"]); // error: string ~> number (2nd arg) +f([0, 0]); // error: number ~> string (1st arg) + +// expect 3 errors: +// - lookup length on Number (0 used as \`this\`) +// - number !~> string (param a) +// - string !~> number (param b) +(test.apply.call(test, 0, [0, \'foo\']): number); + +// args are optional +function test2(): number { return 0; } +(test2.call(): number); +(test2.call(\"\"): number); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function test(a: string, b: number): number { + return this.length;// expect []/\"\" this +} +// args flow correctly into params +test.call(\"\", \"\", 0); +// wrong this is an error +test.call(0, \"\", 0);// error: lookup \`length\` on Number +// not enough arguments is an error (via incompatible RestT) +test.call(\"\", \"\");// error: string ~> number +// mistyped arguments is an error +test.call(\"\", \"\", \"\");// error: string ~> number (2nd arg) +test.call(\"\", 0, 0);// error: number ~> string (1st arg) +// resolve args array from tvar +function f(args) { + test.call(\"\", args[0], args[1]); +} +f([ \"\", 0 ]);// OK +f([ \"\", \"\" ]);// error: string ~> number (2nd arg) +f([ 0, 0 ]);// error: number ~> string (1st arg) +// expect 3 errors: +// - lookup length on Number (0 used as \`this\`) +// - number !~> string (param a) +// - string !~> number (param b) +(test.apply.call(test, 0, [ 0, \"foo\" ]): number); +// args are optional +function test2(): number { + return 0; +} +(test2.call(): number); +(test2.call(\"\"): number); + +" +`; + +exports[`test function.js 1`] = ` +"/** + * @flow + */ + +// Previously we represented Function as (...rest: any) => any +// This means the following wouldn\'t pass, because that arrow function +// can only be called with 3 arguments. +var a: Function = (a, b, c) => 123; + +var b: Function = function(a: number, b: number): number { return a + b; }; + +class C {} + +var c: Function = C; + +function good(x: Function, MyThing: Function): number { + var o: Object = x; // Function is an Object + x.foo = 123; + x[\'foo\'] = 456; + x(); + ; + var {...something} = x; + Object.assign(x, {hi: \'there\'}); + Object.keys(x); + return x.bar + x[\'bar\'] + x.lala(); +} + +function bad(x: Function, y: Object): void { + var a: number = x; // Error + var b: string = x; // Error + var c: Function = y; // Object is not a Function +} + +let tests = [ + function(y: () => void, z: Function) { + function x() {} + (x.length: void); // error, it\'s a number + (y.length: void); // error, it\'s a number + (z.length: void); // error, it\'s a number + + (x.name: void); // error, it\'s a string + (y.name: void); // error, it\'s a string + (z.name: void); // error, it\'s a string + }, + + function(y: () => void, z: Function) { + function x() {} + x.length = \'foo\'; // error, it\'s a number + y.length = \'foo\'; // error, it\'s a number + z.length = \'foo\'; // error, it\'s a number + + x.name = 123; // error, it\'s a string + y.name = 123; // error, it\'s a string + z.name = 123; // error, it\'s a string + + // Non-(Function.prototype) properties on a \`Function\` type should be \`any\` + (z.foo: number); + (z.foo: string); + }, +]; + +// \`Function\` types can be bound (resulting in a \`Function\` type) +var d: Function = () => 1; +var e = (d.bind(1): Function)(); +(e: number); +(e: string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test rest.js 1`] = ` +"/* regression tests */ + +function rest_array(...xs: Array): T { + return xs[0]; +} + +// Warn, singleton tuple types don\'t represent rest params +function rest_tuple(...xs: [T]): T { + return xs[0]; +} + +function rest_any(...xs: any): any { + return xs[0]; +} + +// Warn, arbitrary subtypes of an array type don\'t represent rest params +function rest_t>(...xs: T): U { + return xs[0]; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/function/apply.js b/tests/function/apply.js new file mode 100644 index 000000000000..527839d334c1 --- /dev/null +++ b/tests/function/apply.js @@ -0,0 +1,42 @@ +function test(a: string, b: number): number { + return this.length; // expect []/"" this +} + +// tuples flow correctly into params +test.apply("", ["", 0]); + +// wrong this is an error +test.apply(0, ["", 0]); // error: lookup `length` on Number + +// not enough arguments is an error (via incompatible RestT) +test.apply("", [""]); // error: string ~> number + +// mistyped arguments is an error +test.apply("", ["", ""]); // error: string ~> number (2nd arg) +test.apply("", [0, 0]); // error: number ~> string (1st arg) + +// resolve args array from tvar +function f(args) { test.apply("", args) } +f(["", 0]); // OK +f(["", ""]); // error: string ~> number (2nd arg) +f([0, 0]); // error: number ~> string (1st arg) + +// expect array +test.apply("", "not array"); // error: expect array of args + +// expect 4 errors: +// - lookup length on Number (because 0 is used as `this`) +// - 123 is not a string +// - 'foo' is not a number +// - return type (number) is not void +(test.call.apply(test, [0, 123, 'foo']): void); + +// expect 2 errors: +// - lookup length on number (0 is used as `this`) +// - 123 is not a string +(test.bind.apply(test, [0, 123]): (b: number) => number); + +// args are optional +function test2(): number { return 0; } +(test2.apply(): number); +(test2.apply(""): number); diff --git a/tests/function/bind.js b/tests/function/bind.js new file mode 100644 index 000000000000..1e29e8ee60eb --- /dev/null +++ b/tests/function/bind.js @@ -0,0 +1,9 @@ +// @flow + +let tests = [ + function(x: (a: string, b: string) => void) { + let y = x.bind(x, 'foo'); + y('bar'); // ok + y(123); // error, number !~> string + }, +]; diff --git a/tests/function/call.js b/tests/function/call.js new file mode 100644 index 000000000000..ebb6acd2e8a3 --- /dev/null +++ b/tests/function/call.js @@ -0,0 +1,35 @@ +// @flow + +function test(a: string, b: number): number { + return this.length; // expect []/"" this +} + +// args flow correctly into params +test.call("", "", 0); + +// wrong this is an error +test.call(0, "", 0); // error: lookup `length` on Number + +// not enough arguments is an error (via incompatible RestT) +test.call("", ""); // error: string ~> number + +// mistyped arguments is an error +test.call("", "", ""); // error: string ~> number (2nd arg) +test.call("", 0, 0); // error: number ~> string (1st arg) + +// resolve args array from tvar +function f(args) { test.call("", args[0], args[1]) } +f(["", 0]); // OK +f(["", ""]); // error: string ~> number (2nd arg) +f([0, 0]); // error: number ~> string (1st arg) + +// expect 3 errors: +// - lookup length on Number (0 used as `this`) +// - number !~> string (param a) +// - string !~> number (param b) +(test.apply.call(test, 0, [0, 'foo']): number); + +// args are optional +function test2(): number { return 0; } +(test2.call(): number); +(test2.call(""): number); diff --git a/tests/function/function.js b/tests/function/function.js new file mode 100644 index 000000000000..496b3031d645 --- /dev/null +++ b/tests/function/function.js @@ -0,0 +1,66 @@ +/** + * @flow + */ + +// Previously we represented Function as (...rest: any) => any +// This means the following wouldn't pass, because that arrow function +// can only be called with 3 arguments. +var a: Function = (a, b, c) => 123; + +var b: Function = function(a: number, b: number): number { return a + b; }; + +class C {} + +var c: Function = C; + +function good(x: Function, MyThing: Function): number { + var o: Object = x; // Function is an Object + x.foo = 123; + x['foo'] = 456; + x(); + ; + var {...something} = x; + Object.assign(x, {hi: 'there'}); + Object.keys(x); + return x.bar + x['bar'] + x.lala(); +} + +function bad(x: Function, y: Object): void { + var a: number = x; // Error + var b: string = x; // Error + var c: Function = y; // Object is not a Function +} + +let tests = [ + function(y: () => void, z: Function) { + function x() {} + (x.length: void); // error, it's a number + (y.length: void); // error, it's a number + (z.length: void); // error, it's a number + + (x.name: void); // error, it's a string + (y.name: void); // error, it's a string + (z.name: void); // error, it's a string + }, + + function(y: () => void, z: Function) { + function x() {} + x.length = 'foo'; // error, it's a number + y.length = 'foo'; // error, it's a number + z.length = 'foo'; // error, it's a number + + x.name = 123; // error, it's a string + y.name = 123; // error, it's a string + z.name = 123; // error, it's a string + + // Non-(Function.prototype) properties on a `Function` type should be `any` + (z.foo: number); + (z.foo: string); + }, +]; + +// `Function` types can be bound (resulting in a `Function` type) +var d: Function = () => 1; +var e = (d.bind(1): Function)(); +(e: number); +(e: string); diff --git a/tests/function/jsfmt.spec.js b/tests/function/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/function/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/function/rest.js b/tests/function/rest.js new file mode 100644 index 000000000000..78f52926f951 --- /dev/null +++ b/tests/function/rest.js @@ -0,0 +1,19 @@ +/* regression tests */ + +function rest_array(...xs: Array): T { + return xs[0]; +} + +// Warn, singleton tuple types don't represent rest params +function rest_tuple(...xs: [T]): T { + return xs[0]; +} + +function rest_any(...xs: any): any { + return xs[0]; +} + +// Warn, arbitrary subtypes of an array type don't represent rest params +function rest_t>(...xs: T): U { + return xs[0]; +} diff --git a/tests/funrec/__snapshots__/jsfmt.spec.js.snap b/tests/funrec/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..945fe504c59b --- /dev/null +++ b/tests/funrec/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,19 @@ +exports[`test funrec.js 1`] = ` +"function bar(x) { return x; } +function foo() { + return function bound() { + return bar(bound); + }; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function bar(x) { + return x; +} +function foo() { + return function bound() { + return bar(bound); + }; +} + +" +`; diff --git a/tests/funrec/funrec.js b/tests/funrec/funrec.js new file mode 100644 index 000000000000..4f597e22d574 --- /dev/null +++ b/tests/funrec/funrec.js @@ -0,0 +1,6 @@ +function bar(x) { return x; } +function foo() { + return function bound() { + return bar(bound); + }; +} diff --git a/tests/funrec/jsfmt.spec.js b/tests/funrec/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/funrec/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/generators/__snapshots__/jsfmt.spec.js.snap b/tests/generators/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..67db9796bc48 --- /dev/null +++ b/tests/generators/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,454 @@ +exports[`test class.js 1`] = ` +"class GeneratorExamples { + *stmt_yield(): Generator { + yield 0; // ok + yield \"\"; // error: string ~> number + } + + *stmt_next(): Generator { + var a = yield; + if (a) { + (a : number); // ok + } + + var b = yield; + if (b) { + (b : string); // error: number ~> string + } + } + + *stmt_return_ok(): Generator { + return 0; // ok + } + + *stmt_return_err(): Generator { + return \"\"; // error: string ~> number + } + + *infer_stmt() { + var x: boolean = yield 0; // error: number ~> boolean + return \"\"; + } + + *widen_next() { + var x = yield 0; + if (typeof x === \"number\") { + } else if (typeof x === \"boolean\") { + } else { + (x : string) // ok, sherlock + } + } + + *widen_yield() { + yield 0; + yield \"\"; + yield true; + } + + *delegate_next_generator() { + function *inner() { + var x: number = yield; // error: string ~> number + } + yield *inner(); + } + + *delegate_yield_generator() { + function *inner() { + yield \"\"; + } + + yield *inner(); + } + + *delegate_return_generator() { + function *inner() { + return \"\"; + } + + var x: number = yield *inner(); // error: string ~> number + } + + // only generators can make use of a value passed to next + *delegate_next_iterable(xs: Array) { + yield *xs; + } + + *delegate_yield_iterable(xs: Array) { + yield *xs; + } + + *delegate_return_iterable(xs: Array) { + var x: void = yield *xs // ok: Iterator has no yield value + } + + *generic_yield(y: Y): Generator { + yield y; + } + + *generic_return(r: R): Generator { + return r; + } + + *generic_next(): Generator { + return yield undefined; + } +} + +var examples = new GeneratorExamples(); + +for (var x of examples.infer_stmt()) { (x : string) } // error: number ~> string + +var infer_stmt_next = examples.infer_stmt().next(0).value; // error: number ~> boolean +if (typeof infer_stmt_next === \"undefined\") { +} else if (typeof infer_stmt_next === \"number\") { +} else { + (infer_stmt_next : boolean) // error: string ~> boolean +} + +examples.widen_next().next(0) +examples.widen_next().next(\"\") +examples.widen_next().next(true) + +for (var x of examples.widen_yield()) { + if (typeof x === \"number\") { + } else if (typeof x === \"boolean\") { + } else { + (x : string) // ok, sherlock + } +} + +examples.delegate_next_generator().next(\"\"); + +for (var x of examples.delegate_yield_generator()) { + (x : number) // error: string ~> number +} + +examples.delegate_next_iterable([]).next(\"\"); // error: Iterator has no next value + +for (var x of examples.delegate_yield_iterable([])) { + (x : string) // error: number ~> string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test class_failure.js 1`] = ` +"// generalization of failure in class.js + +class GeneratorExamples { + *infer_stmt() { + var x: boolean = yield 0; // error: number ~> boolean + return \"\"; + } +} + +var examples = new GeneratorExamples(); + +for (var x of examples.infer_stmt()) { (x : string) } // error: number ~> string + +var infer_stmt_next = examples.infer_stmt().next(0).value; // error: number ~> boolean + +if (typeof infer_stmt_next === \"undefined\") { +} else if (typeof infer_stmt_next === \"number\") { +} else { + (infer_stmt_next : boolean) // error: string ~> boolean +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test generators.js 1`] = ` +"function *stmt_yield(): Generator { + yield 0; // ok + yield \"\"; // error: string ~> number +} + +function *stmt_next(): Generator { + var a = yield; + if (a) { + (a : number); // ok + } + + var b = yield; + if (b) { + (b : string); // error: number ~> string + } +} + +function *stmt_return_ok(): Generator { + return 0; // ok +} + +function *stmt_return_err(): Generator { + return \"\"; // error: string ~> number +} + +function *infer_stmt() { + var x: boolean = yield 0; + return \"\"; +} +for (var x of infer_stmt()) { (x : string) } // error: number ~> string +var infer_stmt_next = infer_stmt().next(0).value; // error: number ~> boolean +if (typeof infer_stmt_next === \"undefined\") { +} else if (typeof infer_stmt_next === \"number\") { +} else { + (infer_stmt_next : boolean) // error: string ~> boolean +} + +function *widen_next() { + var x = yield 0; + if (typeof x === \"number\") { + } else if (typeof x === \"boolean\") { + } else { + (x : string) // ok, sherlock + } +} +widen_next().next(0) +widen_next().next(\"\") +widen_next().next(true) + +function *widen_yield() { + yield 0; + yield \"\"; + yield true; +} +for (var x of widen_yield()) { + if (typeof x === \"number\") { + } else if (typeof x === \"boolean\") { + } else { + (x : string) // ok, sherlock + } +} + +function *delegate_next_generator() { + function *inner() { + var x: number = yield; // error: string ~> number + } + yield *inner(); +} +delegate_next_generator().next(\"\"); + +function *delegate_yield_generator() { + function *inner() { + yield \"\"; + } + + yield *inner(); +} +for (var x of delegate_yield_generator()) { + (x : number) // error: string ~> number +} + +function *delegate_return_generator() { + function *inner() { + return \"\"; + } + + var x: number = yield *inner(); // error: string ~> number +} + +// only generators can make use of a value passed to next +function *delegate_next_iterable(xs: Array) { + yield *xs; +} +delegate_next_iterable([]).next(\"\"); // error: Iterator has no next value + +function *delegate_yield_iterable(xs: Array) { + yield *xs; +} +for (var x of delegate_yield_iterable([])) { + (x : string) // error: number ~> string +} + +function *delegate_return_iterable(xs: Array) { + var x: void = yield *xs // ok: Iterator has no yield value +} + +function *generic_yield(y: Y): Generator { + yield y; +} + +function *generic_return(r: R): Generator { + return r; +} + +function *generic_next(): Generator { + return yield undefined; +} + +function *multiple_return(b) { + if (b) { + return 0; + } else { + return \"foo\"; + } +} +let multiple_return_result = multiple_return().next(); +if (multiple_return_result.done) { + (multiple_return_result.value: void); // error: number|string ~> void +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test return.js 1`] = ` +"function test1(gen: Generator) { + // You can pass whatever you like to return, it doesn\'t need to be related to + // the Generator\'s return type + var ret = gen.return(0); + (ret.value: void); // error: string | number ~> void +} + +// However, a generator can \"refuse\" the return by catching an exception and +// yielding or returning internally. +function *refuse_return() { + try { + yield 1; + } finally { + return 0; + } +} +var refuse_return_gen = refuse_return(); +var refuse_return_result = refuse_return_gen.return(\"string\"); +if (refuse_return_result.done) { + (refuse_return_result.value: string); // error: number | void ~> string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test throw.js 1`] = ` +"function *catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} + +var catch_return_value = catch_return().throw(\"\").value; +if (catch_return_value !== undefined) { + (catch_return_value : string); // error: number ~> string +} + +function *yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} +var yield_return_value = yield_return().throw(\"\").value; +if (yield_return_value !== undefined) { + (yield_return_value: string); // error: number ~> string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function* catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} +var catch_return_value = catch_return().throw(\"\").value; +if (catch_return_value !== undefined) { + (catch_return_value: string);// error: number ~> string +} +function* yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} +var yield_return_value = yield_return().throw(\"\").value; +if (yield_return_value !== undefined) { + (yield_return_value: string);// error: number ~> string +} + +" +`; + +exports[`test variance.js 1`] = ` +"declare var g1: Generator; +var g2: Generator = g1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/generators/class.js b/tests/generators/class.js new file mode 100644 index 000000000000..8e88486f3831 --- /dev/null +++ b/tests/generators/class.js @@ -0,0 +1,129 @@ +class GeneratorExamples { + *stmt_yield(): Generator { + yield 0; // ok + yield ""; // error: string ~> number + } + + *stmt_next(): Generator { + var a = yield; + if (a) { + (a : number); // ok + } + + var b = yield; + if (b) { + (b : string); // error: number ~> string + } + } + + *stmt_return_ok(): Generator { + return 0; // ok + } + + *stmt_return_err(): Generator { + return ""; // error: string ~> number + } + + *infer_stmt() { + var x: boolean = yield 0; // error: number ~> boolean + return ""; + } + + *widen_next() { + var x = yield 0; + if (typeof x === "number") { + } else if (typeof x === "boolean") { + } else { + (x : string) // ok, sherlock + } + } + + *widen_yield() { + yield 0; + yield ""; + yield true; + } + + *delegate_next_generator() { + function *inner() { + var x: number = yield; // error: string ~> number + } + yield *inner(); + } + + *delegate_yield_generator() { + function *inner() { + yield ""; + } + + yield *inner(); + } + + *delegate_return_generator() { + function *inner() { + return ""; + } + + var x: number = yield *inner(); // error: string ~> number + } + + // only generators can make use of a value passed to next + *delegate_next_iterable(xs: Array) { + yield *xs; + } + + *delegate_yield_iterable(xs: Array) { + yield *xs; + } + + *delegate_return_iterable(xs: Array) { + var x: void = yield *xs // ok: Iterator has no yield value + } + + *generic_yield(y: Y): Generator { + yield y; + } + + *generic_return(r: R): Generator { + return r; + } + + *generic_next(): Generator { + return yield undefined; + } +} + +var examples = new GeneratorExamples(); + +for (var x of examples.infer_stmt()) { (x : string) } // error: number ~> string + +var infer_stmt_next = examples.infer_stmt().next(0).value; // error: number ~> boolean +if (typeof infer_stmt_next === "undefined") { +} else if (typeof infer_stmt_next === "number") { +} else { + (infer_stmt_next : boolean) // error: string ~> boolean +} + +examples.widen_next().next(0) +examples.widen_next().next("") +examples.widen_next().next(true) + +for (var x of examples.widen_yield()) { + if (typeof x === "number") { + } else if (typeof x === "boolean") { + } else { + (x : string) // ok, sherlock + } +} + +examples.delegate_next_generator().next(""); + +for (var x of examples.delegate_yield_generator()) { + (x : number) // error: string ~> number +} + +examples.delegate_next_iterable([]).next(""); // error: Iterator has no next value + +for (var x of examples.delegate_yield_iterable([])) { + (x : string) // error: number ~> string +} diff --git a/tests/generators/class_failure.js b/tests/generators/class_failure.js new file mode 100644 index 000000000000..42697f5de7ff --- /dev/null +++ b/tests/generators/class_failure.js @@ -0,0 +1,20 @@ +// generalization of failure in class.js + +class GeneratorExamples { + *infer_stmt() { + var x: boolean = yield 0; // error: number ~> boolean + return ""; + } +} + +var examples = new GeneratorExamples(); + +for (var x of examples.infer_stmt()) { (x : string) } // error: number ~> string + +var infer_stmt_next = examples.infer_stmt().next(0).value; // error: number ~> boolean + +if (typeof infer_stmt_next === "undefined") { +} else if (typeof infer_stmt_next === "number") { +} else { + (infer_stmt_next : boolean) // error: string ~> boolean +} diff --git a/tests/generators/generators.js b/tests/generators/generators.js new file mode 100644 index 000000000000..c59630bae767 --- /dev/null +++ b/tests/generators/generators.js @@ -0,0 +1,129 @@ +function *stmt_yield(): Generator { + yield 0; // ok + yield ""; // error: string ~> number +} + +function *stmt_next(): Generator { + var a = yield; + if (a) { + (a : number); // ok + } + + var b = yield; + if (b) { + (b : string); // error: number ~> string + } +} + +function *stmt_return_ok(): Generator { + return 0; // ok +} + +function *stmt_return_err(): Generator { + return ""; // error: string ~> number +} + +function *infer_stmt() { + var x: boolean = yield 0; + return ""; +} +for (var x of infer_stmt()) { (x : string) } // error: number ~> string +var infer_stmt_next = infer_stmt().next(0).value; // error: number ~> boolean +if (typeof infer_stmt_next === "undefined") { +} else if (typeof infer_stmt_next === "number") { +} else { + (infer_stmt_next : boolean) // error: string ~> boolean +} + +function *widen_next() { + var x = yield 0; + if (typeof x === "number") { + } else if (typeof x === "boolean") { + } else { + (x : string) // ok, sherlock + } +} +widen_next().next(0) +widen_next().next("") +widen_next().next(true) + +function *widen_yield() { + yield 0; + yield ""; + yield true; +} +for (var x of widen_yield()) { + if (typeof x === "number") { + } else if (typeof x === "boolean") { + } else { + (x : string) // ok, sherlock + } +} + +function *delegate_next_generator() { + function *inner() { + var x: number = yield; // error: string ~> number + } + yield *inner(); +} +delegate_next_generator().next(""); + +function *delegate_yield_generator() { + function *inner() { + yield ""; + } + + yield *inner(); +} +for (var x of delegate_yield_generator()) { + (x : number) // error: string ~> number +} + +function *delegate_return_generator() { + function *inner() { + return ""; + } + + var x: number = yield *inner(); // error: string ~> number +} + +// only generators can make use of a value passed to next +function *delegate_next_iterable(xs: Array) { + yield *xs; +} +delegate_next_iterable([]).next(""); // error: Iterator has no next value + +function *delegate_yield_iterable(xs: Array) { + yield *xs; +} +for (var x of delegate_yield_iterable([])) { + (x : string) // error: number ~> string +} + +function *delegate_return_iterable(xs: Array) { + var x: void = yield *xs // ok: Iterator has no yield value +} + +function *generic_yield(y: Y): Generator { + yield y; +} + +function *generic_return(r: R): Generator { + return r; +} + +function *generic_next(): Generator { + return yield undefined; +} + +function *multiple_return(b) { + if (b) { + return 0; + } else { + return "foo"; + } +} +let multiple_return_result = multiple_return().next(); +if (multiple_return_result.done) { + (multiple_return_result.value: void); // error: number|string ~> void +} diff --git a/tests/generators/jsfmt.spec.js b/tests/generators/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/generators/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/generators/return.js b/tests/generators/return.js new file mode 100644 index 000000000000..411d5ec17de0 --- /dev/null +++ b/tests/generators/return.js @@ -0,0 +1,21 @@ +function test1(gen: Generator) { + // You can pass whatever you like to return, it doesn't need to be related to + // the Generator's return type + var ret = gen.return(0); + (ret.value: void); // error: string | number ~> void +} + +// However, a generator can "refuse" the return by catching an exception and +// yielding or returning internally. +function *refuse_return() { + try { + yield 1; + } finally { + return 0; + } +} +var refuse_return_gen = refuse_return(); +var refuse_return_result = refuse_return_gen.return("string"); +if (refuse_return_result.done) { + (refuse_return_result.value: string); // error: number | void ~> string +} diff --git a/tests/generators/throw.js b/tests/generators/throw.js new file mode 100644 index 000000000000..de4ae94883d3 --- /dev/null +++ b/tests/generators/throw.js @@ -0,0 +1,25 @@ +function *catch_return() { + try { + yield 0; + } catch (e) { + return e; + } +} + +var catch_return_value = catch_return().throw("").value; +if (catch_return_value !== undefined) { + (catch_return_value : string); // error: number ~> string +} + +function *yield_return() { + try { + yield 0; + return; + } catch (e) { + yield e; + } +} +var yield_return_value = yield_return().throw("").value; +if (yield_return_value !== undefined) { + (yield_return_value: string); // error: number ~> string +} diff --git a/tests/generators/variance.js b/tests/generators/variance.js new file mode 100644 index 000000000000..021c3eddef17 --- /dev/null +++ b/tests/generators/variance.js @@ -0,0 +1,2 @@ +declare var g1: Generator; +var g2: Generator = g1; diff --git a/tests/generics/__snapshots__/jsfmt.spec.js.snap b/tests/generics/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0edf6ac3fab0 --- /dev/null +++ b/tests/generics/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,62 @@ +exports[`test generics.js 1`] = ` +"class C { + x:X; + constructor(x:X) { this.x = x; } + get():X { return this.x; } +} + +class D { + x:T; + m(z:S,u:T,v):S { + this.x = u; + v.u = u; + return z; + } +} + +var d = new D(); +var o = {}; +var b = d.m(true,0,o); +var s:string = d.x; +var n:number = o.u; + +class E extends C { + //x:X; + set(x:X):X { /*return x;*/ this.x = x; return /*this.x; */this.get(); } +} + +var e = new E(); // error: too few arguments to inherited constructor +var x:string = e.set(0); + +class F { } +class G extends F> {} +class H extends G> { + x:Z; + foo(x:Z) { this.x = x; } +} + +var h1 = new H(); +h1.foo([\"...\"]); +var h2:F>>> = h1; + +var obj : Object = {} // error, arity 0 +var fn : Function = function() { return \'foo\'; } // error, arity 0 +var fn : function = function() { return \'foo\'; } // error, arity 0 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (43:9) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; diff --git a/tests/generics/generics.js b/tests/generics/generics.js new file mode 100644 index 000000000000..603f3aebb836 --- /dev/null +++ b/tests/generics/generics.js @@ -0,0 +1,43 @@ +class C { + x:X; + constructor(x:X) { this.x = x; } + get():X { return this.x; } +} + +class D { + x:T; + m(z:S,u:T,v):S { + this.x = u; + v.u = u; + return z; + } +} + +var d = new D(); +var o = {}; +var b = d.m(true,0,o); +var s:string = d.x; +var n:number = o.u; + +class E extends C { + //x:X; + set(x:X):X { /*return x;*/ this.x = x; return /*this.x; */this.get(); } +} + +var e = new E(); // error: too few arguments to inherited constructor +var x:string = e.set(0); + +class F { } +class G extends F> {} +class H extends G> { + x:Z; + foo(x:Z) { this.x = x; } +} + +var h1 = new H(); +h1.foo(["..."]); +var h2:F>>> = h1; + +var obj : Object = {} // error, arity 0 +var fn : Function = function() { return 'foo'; } // error, arity 0 +var fn : function = function() { return 'foo'; } // error, arity 0 diff --git a/tests/generics/jsfmt.spec.js b/tests/generics/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/generics/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/geolocation/__snapshots__/jsfmt.spec.js.snap b/tests/geolocation/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..989969569252 --- /dev/null +++ b/tests/geolocation/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,39 @@ +exports[`test a.js 1`] = ` +"/* @flow */ + +var geolocation = new Geolocation(); +var id = geolocation.watchPosition( + position => { + var coords: Coordinates = position.coords; + var accuracy: number = coords.accuracy; + }, + e => { + var message: string = e.message; + switch (e.code) { + case e.PERMISSION_DENIED: + case e.POSITION_UNAVAILABLE: + case e.TIMEOUT: + default: + break; + } + } +); +geolocation.clearWatch(id); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/geolocation/a.js b/tests/geolocation/a.js new file mode 100644 index 000000000000..21090c0c43b2 --- /dev/null +++ b/tests/geolocation/a.js @@ -0,0 +1,20 @@ +/* @flow */ + +var geolocation = new Geolocation(); +var id = geolocation.watchPosition( + position => { + var coords: Coordinates = position.coords; + var accuracy: number = coords.accuracy; + }, + e => { + var message: string = e.message; + switch (e.code) { + case e.PERMISSION_DENIED: + case e.POSITION_UNAVAILABLE: + case e.TIMEOUT: + default: + break; + } + } +); +geolocation.clearWatch(id); diff --git a/tests/geolocation/jsfmt.spec.js b/tests/geolocation/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/geolocation/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/get-def/__snapshots__/jsfmt.spec.js.snap b/tests/get-def/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..11081a6e424b --- /dev/null +++ b/tests/get-def/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,83 @@ +exports[`test example.js 1`] = ` +"/* @flow */ + +var lib = require('./library'); + +function add(a: number, b: number): number { + return a + b; +} + +var re = /^keynote (talk){2} (lightning){3,5} (talk){2} closing partytime!!!/ + +// t123456 +add(lib.iTakeAString(42), 7); + +// D123456 +lib.bar(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var lib = require("./library"); +function add(a: number, b: number): number { + return a + b; +} +var re = /^keynote (talk){2} (lightning){3,5} (talk){2} closing partytime!!!/; +// t123456 +add(lib.iTakeAString(42), 7); +// D123456 +lib.bar(); + +" +`; + +exports[`test imports.js 1`] = ` +"// @flow + +import thing from "./helpers/exports_default.js"; +thing; + +import {foo, bar as baz} from "./helpers/exports_named.js"; +foo; +baz; + +import * as things from "./helpers/exports_named.js"; +things; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import thing from "./helpers/exports_default.js"; +thing; +import { foo, bar as baz } from "./helpers/exports_named.js"; +foo; +baz; +import * as things from "./helpers/exports_named.js"; +things; + +" +`; + +exports[`test library.js 1`] = ` +"/* @flow */ + +module.exports = { + + iTakeAString: function(name: string): number { + return 42; + }, + + bar: function(): number { + return 42; + }, + +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports = { + iTakeAString: function(name: string): number { + return 42; + }, + bar: function(): number { + return 42; + } +}; + +" +`; diff --git a/tests/get-def/example.js b/tests/get-def/example.js new file mode 100644 index 000000000000..430af4dddd06 --- /dev/null +++ b/tests/get-def/example.js @@ -0,0 +1,15 @@ +/* @flow */ + +var lib = require('./library'); + +function add(a: number, b: number): number { + return a + b; +} + +var re = /^keynote (talk){2} (lightning){3,5} (talk){2} closing partytime!!!/ + +// t123456 +add(lib.iTakeAString(42), 7); + +// D123456 +lib.bar(); diff --git a/tests/get-def/helpers/__snapshots__/jsfmt.spec.js.snap b/tests/get-def/helpers/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..45914a5abd03 --- /dev/null +++ b/tests/get-def/helpers/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test exports_default.js 1`] = ` +"// @flow + +const x = "foo"; + +export default x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +const x = "foo"; +export default x + +" +`; + +exports[`test exports_named.js 1`] = ` +"// @flow + +export const foo = "foo"; +export const bar = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export const foo = "foo"; +export const bar = "bar"; + +" +`; diff --git a/tests/get-def/helpers/exports_default.js b/tests/get-def/helpers/exports_default.js new file mode 100644 index 000000000000..35d13ab4a63c --- /dev/null +++ b/tests/get-def/helpers/exports_default.js @@ -0,0 +1,5 @@ +// @flow + +const x = "foo"; + +export default x; diff --git a/tests/get-def/helpers/exports_named.js b/tests/get-def/helpers/exports_named.js new file mode 100644 index 000000000000..1d89d4eb161c --- /dev/null +++ b/tests/get-def/helpers/exports_named.js @@ -0,0 +1,4 @@ +// @flow + +export const foo = "foo"; +export const bar = "bar"; diff --git a/tests/get-def/helpers/jsfmt.spec.js b/tests/get-def/helpers/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/get-def/helpers/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/get-def/imports.js b/tests/get-def/imports.js new file mode 100644 index 000000000000..34cf5bc9c3c6 --- /dev/null +++ b/tests/get-def/imports.js @@ -0,0 +1,11 @@ +// @flow + +import thing from "./helpers/exports_default.js"; +thing; + +import {foo, bar as baz} from "./helpers/exports_named.js"; +foo; +baz; + +import * as things from "./helpers/exports_named.js"; +things; diff --git a/tests/get-def/jsfmt.spec.js b/tests/get-def/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/get-def/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/get-def/library.js b/tests/get-def/library.js new file mode 100644 index 000000000000..fae7b9fc3770 --- /dev/null +++ b/tests/get-def/library.js @@ -0,0 +1,13 @@ +/* @flow */ + +module.exports = { + + iTakeAString: function(name: string): number { + return 42; + }, + + bar: function(): number { + return 42; + }, + +}; diff --git a/tests/get-def2/Parent.js b/tests/get-def2/Parent.js new file mode 100644 index 000000000000..830a1cd31ed6 --- /dev/null +++ b/tests/get-def2/Parent.js @@ -0,0 +1,4 @@ +// @flow + +var ParentFoo = {foo: 'bar'}; +module.exports = {ParentFoo}; diff --git a/tests/get-def2/__snapshots__/jsfmt.spec.js.snap b/tests/get-def2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bad7c5acd016 --- /dev/null +++ b/tests/get-def2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,127 @@ +exports[`test Parent.js 1`] = ` +"// @flow + +var ParentFoo = {foo: 'bar'}; +module.exports = {ParentFoo}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var ParentFoo = { foo: "bar" }; +module.exports = { ParentFoo }; + +" +`; + +exports[`test main.js 1`] = ` +"// @flow + +var Parent = require('./Parent'); + +// Hops through destructuring +let ParentFoo; +({ParentFoo} = Parent); +ParentFoo; // Points to lval in line above this + +// Follows assignment on simple/"non-destructuring" patterns +let ParentFoo2; +ParentFoo2 = Parent; +ParentFoo2; // Points to LHS of line above this + +// Follows assignment with declaration +let ParentFoo3 = Parent; +ParentFoo3; // Points to LHS of line above this + +// Follows non-destructured property access of \`require('Parent')\` +let foo = require('./Parent').ParentFoo.foo; +foo; + +import type {Foo} from './types'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var Parent = require("./Parent"); +// Hops through destructuring +let ParentFoo; +{ ParentFoo } = Parent; +ParentFoo;// Points to lval in line above this +// Follows assignment on simple/"non-destructuring" patterns +let ParentFoo2; +ParentFoo2 = Parent; +ParentFoo2;// Points to LHS of line above this +// Follows assignment with declaration +let ParentFoo3 = Parent; +ParentFoo3;// Points to LHS of line above this +// Follows non-destructured property access of \`require('Parent')\` +let foo = require("./Parent").ParentFoo.foo; +foo; +import type { Foo } from "./types"; + +" +`; + +exports[`test override.js 1`] = ` +"// @flow + +class C { + override() { } +} + +class D extends C { + foo() { this.override() } + bar() { this.override } + override() { } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class C { + override() { + + } +} +class D extends C { + foo() { + this.override(); + } + bar() { + this.override; + } + override() { + + } +} + +" +`; + +exports[`test react.js 1`] = ` +"var React = require('react'); + +class C extends React.Component { + props: { x: string }; +} + +let msg = "hello"; + +(); + +(
); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require("react"); +class C extends React.Component { + props: { x: string }; +} +let msg = "hello"; +; +
; + +" +`; + +exports[`test types.js 1`] = ` +"// @flow + +export type Foo = {}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export type Foo = {}; + +" +`; diff --git a/tests/get-def2/jsfmt.spec.js b/tests/get-def2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/get-def2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/get-def2/lib/__snapshots__/jsfmt.spec.js.snap b/tests/get-def2/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1c2c02375402 --- /dev/null +++ b/tests/get-def2/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test jsx.js 1`] = ` +"declare var $React: $Exports<\'react\'>; // fake import +type $JSXIntrinsic = Class<$React.Component>; + +type $JSXIntrinsics = { + div: $JSXIntrinsic<{id: string}>, + span: $JSXIntrinsic<{id: string, class: string}>, +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/get-def2/lib/jsfmt.spec.js b/tests/get-def2/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/get-def2/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/get-def2/lib/jsx.js b/tests/get-def2/lib/jsx.js new file mode 100644 index 000000000000..7de8608bc649 --- /dev/null +++ b/tests/get-def2/lib/jsx.js @@ -0,0 +1,7 @@ +declare var $React: $Exports<'react'>; // fake import +type $JSXIntrinsic = Class<$React.Component>; + +type $JSXIntrinsics = { + div: $JSXIntrinsic<{id: string}>, + span: $JSXIntrinsic<{id: string, class: string}>, +}; diff --git a/tests/get-def2/main.js b/tests/get-def2/main.js new file mode 100644 index 000000000000..63064a345a05 --- /dev/null +++ b/tests/get-def2/main.js @@ -0,0 +1,23 @@ +// @flow + +var Parent = require('./Parent'); + +// Hops through destructuring +let ParentFoo; +({ParentFoo} = Parent); +ParentFoo; // Points to lval in line above this + +// Follows assignment on simple/"non-destructuring" patterns +let ParentFoo2; +ParentFoo2 = Parent; +ParentFoo2; // Points to LHS of line above this + +// Follows assignment with declaration +let ParentFoo3 = Parent; +ParentFoo3; // Points to LHS of line above this + +// Follows non-destructured property access of `require('Parent')` +let foo = require('./Parent').ParentFoo.foo; +foo; + +import type {Foo} from './types'; diff --git a/tests/get-def2/override.js b/tests/get-def2/override.js new file mode 100644 index 000000000000..50de748aeb9c --- /dev/null +++ b/tests/get-def2/override.js @@ -0,0 +1,11 @@ +// @flow + +class C { + override() { } +} + +class D extends C { + foo() { this.override() } + bar() { this.override } + override() { } +} diff --git a/tests/get-def2/react.js b/tests/get-def2/react.js new file mode 100644 index 000000000000..1c633ef60d61 --- /dev/null +++ b/tests/get-def2/react.js @@ -0,0 +1,11 @@ +var React = require('react'); + +class C extends React.Component { + props: { x: string }; +} + +let msg = "hello"; + +(); + +(
); diff --git a/tests/get-def2/types.js b/tests/get-def2/types.js new file mode 100644 index 000000000000..2778d2acab1c --- /dev/null +++ b/tests/get-def2/types.js @@ -0,0 +1,3 @@ +// @flow + +export type Foo = {}; diff --git a/tests/get-imports-and-importers/__snapshots__/jsfmt.spec.js.snap b/tests/get-imports-and-importers/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3a4850bffce2 --- /dev/null +++ b/tests/get-imports-and-importers/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,35 @@ +exports[`test a.js 1`] = ` +"// @flow +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test b.js 1`] = ` +"/** + * @flow + * @providesModule b + */ +require('./a'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + * @providesModule b + */ +require("./a"); + +" +`; + +exports[`test c.js 1`] = ` +"// @flow +require('./a.js'); +require('b'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +require("./a.js"); +require("b"); + +" +`; diff --git a/tests/get-imports-and-importers/a.js b/tests/get-imports-and-importers/a.js new file mode 100644 index 000000000000..46e7f7c04567 --- /dev/null +++ b/tests/get-imports-and-importers/a.js @@ -0,0 +1 @@ +// @flow diff --git a/tests/get-imports-and-importers/b.js b/tests/get-imports-and-importers/b.js new file mode 100644 index 000000000000..6f8b57f3965d --- /dev/null +++ b/tests/get-imports-and-importers/b.js @@ -0,0 +1,5 @@ +/** + * @flow + * @providesModule b + */ +require('./a'); diff --git a/tests/get-imports-and-importers/c.js b/tests/get-imports-and-importers/c.js new file mode 100644 index 000000000000..31d5ef9657f4 --- /dev/null +++ b/tests/get-imports-and-importers/c.js @@ -0,0 +1,3 @@ +// @flow +require('./a.js'); +require('b'); diff --git a/tests/get-imports-and-importers/jsfmt.spec.js b/tests/get-imports-and-importers/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/get-imports-and-importers/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/getters_and_setters_disabled/__snapshots__/jsfmt.spec.js.snap b/tests/getters_and_setters_disabled/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1c785f6ffd3c --- /dev/null +++ b/tests/getters_and_setters_disabled/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test getters_and_setters.js 1`] = ` +"/** + * @flow + */ + +var f = { + get a() { return 4; }, + set b(x: number) { this.c = b; }, + c: 10, +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +var f = { + get a() { + return 4; + }, + set b(x: number) { + this.c = b; + }, + c: 10 +}; + +" +`; diff --git a/tests/getters_and_setters_disabled/getters_and_setters.js b/tests/getters_and_setters_disabled/getters_and_setters.js new file mode 100644 index 000000000000..f20bb4867a5a --- /dev/null +++ b/tests/getters_and_setters_disabled/getters_and_setters.js @@ -0,0 +1,9 @@ +/** + * @flow + */ + +var f = { + get a() { return 4; }, + set b(x: number) { this.c = b; }, + c: 10, +}; diff --git a/tests/getters_and_setters_disabled/jsfmt.spec.js b/tests/getters_and_setters_disabled/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/getters_and_setters_disabled/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap b/tests/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7bb852a92f5d --- /dev/null +++ b/tests/getters_and_setters_enabled/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,451 @@ +exports[`test class.js 1`] = ` +"/** + * @flow + */ + +var z: number = 123; + +class Foo { + get goodGetterNoAnnotation() { return 4; } + get goodGetterWithAnnotation(): number { return 4; } + + set goodSetterNoAnnotation(x) { z = x; } + set goodSetterWithAnnotation(x: number) { z = x; } + + get propWithMatchingGetterAndSetter(): number { return 4; } + set propWithMatchingGetterAndSetter(x: number) { } + + // The getter and setter need not have the same type - no error + get propWithSubtypingGetterAndSetter(): ?number { return 4; } + set propWithSubtypingGetterAndSetter(x: number) { } + + // The getter and setter need not have the same type - no error + set propWithSubtypingGetterAndSetterReordered(x: number) { } + get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; } + + get propWithMismatchingGetterAndSetter(): number { return 4; } + set propWithMismatchingGetterAndSetter(x: string) { } // doesn't match getter (OK) + + propOverriddenWithGetter: number; + get propOverriddenWithGetter() { return "hello"; } + + propOverriddenWithSetter: number; + set propOverriddenWithSetter(x: string) { } +}; + +var foo = new Foo(); + +// Test getting properties with getters +var testGetterNoError1: number = foo.goodGetterNoAnnotation; +var testGetterNoError2: number = foo.goodGetterWithAnnotation; + +var testGetterWithError1: string = foo.goodGetterNoAnnotation; // Error number ~> string +var testGetterWithError2: string = foo.goodGetterWithAnnotation; // Error number ~> string + +// Test setting properties with getters +foo.goodSetterNoAnnotation = 123; +foo.goodSetterWithAnnotation = 123; + +// TODO: Why does no annotation mean no error? +foo.goodSetterNoAnnotation = "hello"; // Error string ~> number +foo.goodSetterWithAnnotation = "hello"; // Error string ~> number + +var testSubtypingGetterAndSetter: number = foo.propWithSubtypingGetterAndSetter; // Error ?number ~> number + +var testPropOverridenWithGetter: number = foo.propOverriddenWithGetter; // Error string ~> number +foo.propOverriddenWithSetter = 123; // Error number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +var z: number = 123; +class Foo { + get goodGetterNoAnnotation() { + return 4; + } + get goodGetterWithAnnotation(): number { + return 4; + } + set goodSetterNoAnnotation(x) { + z = x; + } + set goodSetterWithAnnotation(x: number) { + z = x; + } + get propWithMatchingGetterAndSetter(): number { + return 4; + } + set propWithMatchingGetterAndSetter(x: number) { + + } + // The getter and setter need not have the same type - no error + get propWithSubtypingGetterAndSetter(): ?number { + return 4; + } + set propWithSubtypingGetterAndSetter(x: number) { + + } + // The getter and setter need not have the same type - no error + set propWithSubtypingGetterAndSetterReordered(x: number) { + + } + get propWithSubtypingGetterAndSetterReordered(): ?number { + return 4; + } + get propWithMismatchingGetterAndSetter(): number { + return 4; + } + set propWithMismatchingGetterAndSetter(x: string) { + + }// doesn't match getter (OK) + propOverriddenWithGetter: number; + get propOverriddenWithGetter() { + return "hello"; + } + propOverriddenWithSetter: number; + set propOverriddenWithSetter(x: string) { + + } +} +var foo = new Foo(); +// Test getting properties with getters +var testGetterNoError1: number = foo.goodGetterNoAnnotation; +var testGetterNoError2: number = foo.goodGetterWithAnnotation; +var testGetterWithError1: string = foo.goodGetterNoAnnotation;// Error number ~> string +var testGetterWithError2: string = foo.goodGetterWithAnnotation;// Error number ~> string +// Test setting properties with getters +foo.goodSetterNoAnnotation = 123; +foo.goodSetterWithAnnotation = 123; +// TODO: Why does no annotation mean no error? +foo.goodSetterNoAnnotation = "hello";// Error string ~> number +foo.goodSetterWithAnnotation = "hello";// Error string ~> number +var testSubtypingGetterAndSetter: number = foo.propWithSubtypingGetterAndSetter;// Error ?number ~> number +var testPropOverridenWithGetter: number = foo.propOverriddenWithGetter;// Error string ~> number +foo.propOverriddenWithSetter = 123;// Error number ~> string + +" +`; + +exports[`test object.js 1`] = ` +"/** + * @flow + */ + +var z: number = 123; + +class A {} +class B extends A {} +class C extends A {} + +var obj = { + get goodGetterNoAnnotation() { return 4; }, + get goodGetterWithAnnotation(): number { return 4; }, + + set goodSetterNoAnnotation(x) { z = x; }, + set goodSetterWithAnnotation(x: number) { z = x; }, + + get propWithMatchingGetterAndSetter(): number { return 4; }, + set propWithMatchingGetterAndSetter(x: number) { }, + + // The getter and setter need not have the same type + get propWithSubtypingGetterAndSetter(): ?number { return 4; }, // OK + set propWithSubtypingGetterAndSetter(x: number) { }, + + set propWithSubtypingGetterAndSetterReordered(x: number) { }, // OK + get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; }, + + get exampleOfOrderOfGetterAndSetter(): A { return new A(); }, + set exampleOfOrderOfGetterAndSetter(x: B) {}, + + set exampleOfOrderOfGetterAndSetterReordered(x: B) {}, + get exampleOfOrderOfGetterAndSetterReordered(): A { return new A(); }, +}; + + + +// Test getting properties with getters +var testGetterNoError1: number = obj.goodGetterNoAnnotation; +var testGetterNoError2: number = obj.goodGetterWithAnnotation; + +var testGetterWithError1: string = obj.goodGetterNoAnnotation; // Error number ~> string +var testGetterWithError2: string = obj.goodGetterWithAnnotation; // Error number ~> string + +// Test setting properties with getters +obj.goodSetterNoAnnotation = 123; +obj.goodSetterWithAnnotation = 123; + +obj.goodSetterNoAnnotation = "hello"; // Error string ~> number +obj.goodSetterWithAnnotation = "hello"; // Error string ~> number + +var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter; // Error ?number ~> number + +// When building this feature, it was tempting to flow the setter into the +// getter and then use either the getter or setter as the type of the property. +// This example shows the danger of using the getter's type +obj.exampleOfOrderOfGetterAndSetter = new C(); // Error C ~> B + +// And this example shows the danger of using the setter's type. +var testExampleOrOrderOfGetterAndSetterReordered: number = + obj.exampleOfOrderOfGetterAndSetterReordered; // Error A ~> B +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +var z: number = 123; +class A {} +class B extends A {} +class C extends A {} +var obj = { + get goodGetterNoAnnotation() { + return 4; + }, + get goodGetterWithAnnotation(): number { + return 4; + }, + set goodSetterNoAnnotation(x) { + z = x; + }, + set goodSetterWithAnnotation(x: number) { + z = x; + }, + get propWithMatchingGetterAndSetter(): number { + return 4; + }, + set propWithMatchingGetterAndSetter(x: number) { + + }, + // The getter and setter need not have the same type + // OK + get propWithSubtypingGetterAndSetter(): ?number { + return 4; + }, + set propWithSubtypingGetterAndSetter(x: number) { + + }, + // OK set propWithSubtypingGetterAndSetterReordered(x: number) { + + }, + get propWithSubtypingGetterAndSetterReordered(): ?number { + return 4; + }, + get exampleOfOrderOfGetterAndSetter(): A { + return new A(); + }, + set exampleOfOrderOfGetterAndSetter(x: B) { + + }, + set exampleOfOrderOfGetterAndSetterReordered(x: B) { + + }, + get exampleOfOrderOfGetterAndSetterReordered(): A { + return new A(); + } +}; +// Test getting properties with getters +var testGetterNoError1: number = obj.goodGetterNoAnnotation; +var testGetterNoError2: number = obj.goodGetterWithAnnotation; +var testGetterWithError1: string = obj.goodGetterNoAnnotation;// Error number ~> string +var testGetterWithError2: string = obj.goodGetterWithAnnotation;// Error number ~> string +// Test setting properties with getters +obj.goodSetterNoAnnotation = 123; +obj.goodSetterWithAnnotation = 123; +obj.goodSetterNoAnnotation = "hello";// Error string ~> number +obj.goodSetterWithAnnotation = "hello";// Error string ~> number +var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter;// Error ?number ~> number +// When building this feature, it was tempting to flow the setter into the +// getter and then use either the getter or setter as the type of the property. +// This example shows the danger of using the getter's type +obj.exampleOfOrderOfGetterAndSetter = new C();// Error C ~> B +// And this example shows the danger of using the setter's type. +var testExampleOrOrderOfGetterAndSetterReordered: number = obj.exampleOfOrderOfGetterAndSetterReordered;// Error A ~> B + +" +`; + +exports[`test react.js 1`] = ` +"/** + * @flow + */ + +React.createClass({ + propTypes: { + get a() { return 4; }, + set b(x: number) { this.c = x; }, + c: 10, + } +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +React.createClass({ + propTypes: { + get a() { + return 4; + }, + set b(x: number) { + this.c = x; + }, + c: 10 + } +}); + +" +`; + +exports[`test variance.js 1`] = ` +"/* @flow */ + +class A {} +class B extends A {} +class C extends B {} + +declare var a: A; +declare var b: B; +declare var c: C; + +class Base { + x: B; + +pos: B; + -neg: B; + get get(): B { return this.x }; + set set(value: B): void { this.x = value }; + get getset(): B { return this.x }; + set getset(value: B): void { this.x = value }; +} + +(class extends Base { + // error: getter incompatible with read/write property + get x(): B { return b } +}); + +(class extends Base { + // error: setter incompatible with read/write property + set x(value: B): void {} +}); + +(class extends Base { + // ok: get/set co/contra with read/write property, resp. + get x(): C { return c } + set x(value: A): void {} +}); + +(class extends Base { + // error: setter incompatible with read-only property + set pos(value: B): void {} +}); + +(class extends Base { + // ok: getter covariant with read-only property + get pos(): C { return c } +}); + +(class extends Base { + // error: getter incompatible with write-only property + get neg(): B { return b } +}); + +(class extends Base { + // ok: setter contravariant with write-only property + set neg(value: A): void {} +}); + +(class extends Base { + // ok: read/write covariant with getter + get: C; +}); + +(class extends Base { + // ok: read/write contravariant with setter + set: A; +}); + +(class extends Base { + // ok: read/write invariant with get/set + getset: B; +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class A {} +class B extends A {} +class C extends B {} +declare var a: A; +declare var b: B; +declare var c: C; +class Base { + x: B; + +pos: B; + -neg: B; + get get(): B { + return this.x; + } + set set(value: B): void { + this.x = value; + } + get getset(): B { + return this.x; + } + set getset(value: B): void { + this.x = value; + } +} +class extends Base { + // error: getter incompatible with read/write property + get x(): B { + return b; + } +}; +class extends Base { + // error: setter incompatible with read/write property + set x(value: B): void { + + } +}; +class extends Base { + // ok: get/set co/contra with read/write property, resp. + get x(): C { + return c; + } + set x(value: A): void { + + } +}; +class extends Base { + // error: setter incompatible with read-only property + set pos(value: B): void { + + } +}; +class extends Base { + // ok: getter covariant with read-only property + get pos(): C { + return c; + } +}; +class extends Base { + // error: getter incompatible with write-only property + get neg(): B { + return b; + } +}; +class extends Base { + // ok: setter contravariant with write-only property + set neg(value: A): void { + + } +}; +class extends Base { + // ok: read/write covariant with getter + get: C; +}; +class extends Base { + // ok: read/write contravariant with setter + set: A; +}; +class extends Base { + // ok: read/write invariant with get/set + getset: B; +}; + +" +`; diff --git a/tests/getters_and_setters_enabled/class.js b/tests/getters_and_setters_enabled/class.js new file mode 100644 index 000000000000..c9a3707e28df --- /dev/null +++ b/tests/getters_and_setters_enabled/class.js @@ -0,0 +1,55 @@ +/** + * @flow + */ + +var z: number = 123; + +class Foo { + get goodGetterNoAnnotation() { return 4; } + get goodGetterWithAnnotation(): number { return 4; } + + set goodSetterNoAnnotation(x) { z = x; } + set goodSetterWithAnnotation(x: number) { z = x; } + + get propWithMatchingGetterAndSetter(): number { return 4; } + set propWithMatchingGetterAndSetter(x: number) { } + + // The getter and setter need not have the same type - no error + get propWithSubtypingGetterAndSetter(): ?number { return 4; } + set propWithSubtypingGetterAndSetter(x: number) { } + + // The getter and setter need not have the same type - no error + set propWithSubtypingGetterAndSetterReordered(x: number) { } + get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; } + + get propWithMismatchingGetterAndSetter(): number { return 4; } + set propWithMismatchingGetterAndSetter(x: string) { } // doesn't match getter (OK) + + propOverriddenWithGetter: number; + get propOverriddenWithGetter() { return "hello"; } + + propOverriddenWithSetter: number; + set propOverriddenWithSetter(x: string) { } +}; + +var foo = new Foo(); + +// Test getting properties with getters +var testGetterNoError1: number = foo.goodGetterNoAnnotation; +var testGetterNoError2: number = foo.goodGetterWithAnnotation; + +var testGetterWithError1: string = foo.goodGetterNoAnnotation; // Error number ~> string +var testGetterWithError2: string = foo.goodGetterWithAnnotation; // Error number ~> string + +// Test setting properties with getters +foo.goodSetterNoAnnotation = 123; +foo.goodSetterWithAnnotation = 123; + +// TODO: Why does no annotation mean no error? +foo.goodSetterNoAnnotation = "hello"; // Error string ~> number +foo.goodSetterWithAnnotation = "hello"; // Error string ~> number + +var testSubtypingGetterAndSetter: number = foo.propWithSubtypingGetterAndSetter; // Error ?number ~> number + +var testPropOverridenWithGetter: number = foo.propOverriddenWithGetter; // Error string ~> number +foo.propOverriddenWithSetter = 123; // Error number ~> string diff --git a/tests/getters_and_setters_enabled/jsfmt.spec.js b/tests/getters_and_setters_enabled/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/getters_and_setters_enabled/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/getters_and_setters_enabled/object.js b/tests/getters_and_setters_enabled/object.js new file mode 100644 index 000000000000..5e54f25f40dc --- /dev/null +++ b/tests/getters_and_setters_enabled/object.js @@ -0,0 +1,60 @@ +/** + * @flow + */ + +var z: number = 123; + +class A {} +class B extends A {} +class C extends A {} + +var obj = { + get goodGetterNoAnnotation() { return 4; }, + get goodGetterWithAnnotation(): number { return 4; }, + + set goodSetterNoAnnotation(x) { z = x; }, + set goodSetterWithAnnotation(x: number) { z = x; }, + + get propWithMatchingGetterAndSetter(): number { return 4; }, + set propWithMatchingGetterAndSetter(x: number) { }, + + // The getter and setter need not have the same type + get propWithSubtypingGetterAndSetter(): ?number { return 4; }, // OK + set propWithSubtypingGetterAndSetter(x: number) { }, + + set propWithSubtypingGetterAndSetterReordered(x: number) { }, // OK + get propWithSubtypingGetterAndSetterReordered(): ?number { return 4; }, + + get exampleOfOrderOfGetterAndSetter(): A { return new A(); }, + set exampleOfOrderOfGetterAndSetter(x: B) {}, + + set exampleOfOrderOfGetterAndSetterReordered(x: B) {}, + get exampleOfOrderOfGetterAndSetterReordered(): A { return new A(); }, +}; + + + +// Test getting properties with getters +var testGetterNoError1: number = obj.goodGetterNoAnnotation; +var testGetterNoError2: number = obj.goodGetterWithAnnotation; + +var testGetterWithError1: string = obj.goodGetterNoAnnotation; // Error number ~> string +var testGetterWithError2: string = obj.goodGetterWithAnnotation; // Error number ~> string + +// Test setting properties with getters +obj.goodSetterNoAnnotation = 123; +obj.goodSetterWithAnnotation = 123; + +obj.goodSetterNoAnnotation = "hello"; // Error string ~> number +obj.goodSetterWithAnnotation = "hello"; // Error string ~> number + +var testSubtypingGetterAndSetter: number = obj.propWithSubtypingGetterAndSetter; // Error ?number ~> number + +// When building this feature, it was tempting to flow the setter into the +// getter and then use either the getter or setter as the type of the property. +// This example shows the danger of using the getter's type +obj.exampleOfOrderOfGetterAndSetter = new C(); // Error C ~> B + +// And this example shows the danger of using the setter's type. +var testExampleOrOrderOfGetterAndSetterReordered: number = + obj.exampleOfOrderOfGetterAndSetterReordered; // Error A ~> B diff --git a/tests/getters_and_setters_enabled/react.js b/tests/getters_and_setters_enabled/react.js new file mode 100644 index 000000000000..811acd9ec376 --- /dev/null +++ b/tests/getters_and_setters_enabled/react.js @@ -0,0 +1,11 @@ +/** + * @flow + */ + +React.createClass({ + propTypes: { + get a() { return 4; }, + set b(x: number) { this.c = x; }, + c: 10, + } +}); diff --git a/tests/getters_and_setters_enabled/variance.js b/tests/getters_and_setters_enabled/variance.js new file mode 100644 index 000000000000..8337453d57d9 --- /dev/null +++ b/tests/getters_and_setters_enabled/variance.js @@ -0,0 +1,70 @@ +/* @flow */ + +class A {} +class B extends A {} +class C extends B {} + +declare var a: A; +declare var b: B; +declare var c: C; + +class Base { + x: B; + +pos: B; + -neg: B; + get get(): B { return this.x }; + set set(value: B): void { this.x = value }; + get getset(): B { return this.x }; + set getset(value: B): void { this.x = value }; +} + +(class extends Base { + // error: getter incompatible with read/write property + get x(): B { return b } +}); + +(class extends Base { + // error: setter incompatible with read/write property + set x(value: B): void {} +}); + +(class extends Base { + // ok: get/set co/contra with read/write property, resp. + get x(): C { return c } + set x(value: A): void {} +}); + +(class extends Base { + // error: setter incompatible with read-only property + set pos(value: B): void {} +}); + +(class extends Base { + // ok: getter covariant with read-only property + get pos(): C { return c } +}); + +(class extends Base { + // error: getter incompatible with write-only property + get neg(): B { return b } +}); + +(class extends Base { + // ok: setter contravariant with write-only property + set neg(value: A): void {} +}); + +(class extends Base { + // ok: read/write covariant with getter + get: C; +}); + +(class extends Base { + // ok: read/write contravariant with setter + set: A; +}); + +(class extends Base { + // ok: read/write invariant with get/set + getset: B; +}); diff --git a/tests/haste_cycle/API.js b/tests/haste_cycle/API.js new file mode 100644 index 000000000000..9224269fc476 --- /dev/null +++ b/tests/haste_cycle/API.js @@ -0,0 +1,3 @@ +// @flow + +var OpenGraphObject = require('./models/OpenGraphObject.js'); diff --git a/tests/haste_cycle/__snapshots__/jsfmt.spec.js.snap b/tests/haste_cycle/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a6433431534f --- /dev/null +++ b/tests/haste_cycle/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test API.js 1`] = ` +"// @flow + +var OpenGraphObject = require('./models/OpenGraphObject.js'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var OpenGraphObject = require("./models/OpenGraphObject.js"); + +" +`; diff --git a/tests/haste_cycle/jsfmt.spec.js b/tests/haste_cycle/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/haste_cycle/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/haste_cycle/models/OpenGraphAction.js b/tests/haste_cycle/models/OpenGraphAction.js new file mode 100644 index 000000000000..364e413bb22f --- /dev/null +++ b/tests/haste_cycle/models/OpenGraphAction.js @@ -0,0 +1,3 @@ +// @flow + +var OpenGraphValueContainer = require('./OpenGraphValueContainer.js'); diff --git a/tests/haste_cycle/models/OpenGraphObject.js b/tests/haste_cycle/models/OpenGraphObject.js new file mode 100644 index 000000000000..364e413bb22f --- /dev/null +++ b/tests/haste_cycle/models/OpenGraphObject.js @@ -0,0 +1,3 @@ +// @flow + +var OpenGraphValueContainer = require('./OpenGraphValueContainer.js'); diff --git a/tests/haste_cycle/models/OpenGraphValueContainer.js b/tests/haste_cycle/models/OpenGraphValueContainer.js new file mode 100644 index 000000000000..24d28abd4d28 --- /dev/null +++ b/tests/haste_cycle/models/OpenGraphValueContainer.js @@ -0,0 +1,3 @@ +// @flow + +var OpenGraphObject = require('./OpenGraphObject.js'); diff --git a/tests/haste_cycle/models/__snapshots__/jsfmt.spec.js.snap b/tests/haste_cycle/models/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9b3493adb074 --- /dev/null +++ b/tests/haste_cycle/models/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,32 @@ +exports[`test OpenGraphAction.js 1`] = ` +"// @flow + +var OpenGraphValueContainer = require('./OpenGraphValueContainer.js'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var OpenGraphValueContainer = require("./OpenGraphValueContainer.js"); + +" +`; + +exports[`test OpenGraphObject.js 1`] = ` +"// @flow + +var OpenGraphValueContainer = require('./OpenGraphValueContainer.js'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var OpenGraphValueContainer = require("./OpenGraphValueContainer.js"); + +" +`; + +exports[`test OpenGraphValueContainer.js 1`] = ` +"// @flow + +var OpenGraphObject = require('./OpenGraphObject.js'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var OpenGraphObject = require("./OpenGraphObject.js"); + +" +`; diff --git a/tests/haste_cycle/models/jsfmt.spec.js b/tests/haste_cycle/models/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/haste_cycle/models/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/haste_dupe/__snapshots__/jsfmt.spec.js.snap b/tests/haste_dupe/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..88db0d310415 --- /dev/null +++ b/tests/haste_dupe/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,51 @@ +exports[`test dupe1.js 1`] = ` +"/** + * Dupe provider 1/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe1"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Dupe provider 1/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe1"; + +" +`; + +exports[`test dupe2.js 1`] = ` +"/** + * Dupe provider 2/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe2"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Dupe provider 2/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe2"; + +" +`; + +exports[`test requires_dupe.js 1`] = ` +"/** + * depends on doubly-provided module + * @flow + */ +var dupe = require('Dupe'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * depends on doubly-provided module + * @flow + */ +var dupe = require("Dupe"); + +" +`; diff --git a/tests/haste_dupe/dupe1.js b/tests/haste_dupe/dupe1.js new file mode 100644 index 000000000000..1a298b67eae7 --- /dev/null +++ b/tests/haste_dupe/dupe1.js @@ -0,0 +1,6 @@ +/** + * Dupe provider 1/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe1"; diff --git a/tests/haste_dupe/dupe2.js b/tests/haste_dupe/dupe2.js new file mode 100644 index 000000000000..aa64ae687dd8 --- /dev/null +++ b/tests/haste_dupe/dupe2.js @@ -0,0 +1,6 @@ +/** + * Dupe provider 2/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe2"; diff --git a/tests/haste_dupe/jsfmt.spec.js b/tests/haste_dupe/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/haste_dupe/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/haste_dupe/requires_dupe.js b/tests/haste_dupe/requires_dupe.js new file mode 100644 index 000000000000..129992b7ab05 --- /dev/null +++ b/tests/haste_dupe/requires_dupe.js @@ -0,0 +1,5 @@ +/** + * depends on doubly-provided module + * @flow + */ +var dupe = require('Dupe'); diff --git a/tests/ignore_package/__snapshots__/jsfmt.spec.js.snap b/tests/ignore_package/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..365defe04de3 --- /dev/null +++ b/tests/ignore_package/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,31 @@ +exports[`test foo.js 1`] = ` +"/** @flow */ +/* this require routes to nothing, because + our node_modules/underscore directory + has been excluded. If package.json files + are being excluded properly, we'll get + 'Required module not found'. + */ +var _ = require('underscore'); + +function foo(): string { + return _.foo(); +} + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** @flow */ +/* this require routes to nothing, because + our node_modules/underscore directory + has been excluded. If package.json files + are being excluded properly, we'll get + 'Required module not found'. + */ +var _ = require("underscore"); +function foo(): string { + return _.foo(); +} +module.exports = foo; + +" +`; diff --git a/tests/ignore_package/foo.js b/tests/ignore_package/foo.js new file mode 100644 index 000000000000..ff3a3366ac03 --- /dev/null +++ b/tests/ignore_package/foo.js @@ -0,0 +1,14 @@ +/** @flow */ +/* this require routes to nothing, because + our node_modules/underscore directory + has been excluded. If package.json files + are being excluded properly, we'll get + 'Required module not found'. + */ +var _ = require('underscore'); + +function foo(): string { + return _.foo(); +} + +module.exports = foo; diff --git a/tests/ignore_package/jsfmt.spec.js b/tests/ignore_package/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/ignore_package/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/immutable_methods/__snapshots__/jsfmt.spec.js.snap b/tests/immutable_methods/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7365d8ee4758 --- /dev/null +++ b/tests/immutable_methods/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,29 @@ +exports[`test test.js 1`] = ` +"class A { + foo(): A { return this; } +} +class B extends A { + foo(): B { return this; } +} +class C extends A {} +var a: A = new B(); +a.foo = function(): C { return new C(); } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A { + foo(): A { + return this; + } +} +class B extends A { + foo(): B { + return this; + } +} +class C extends A {} +var a: A = new B(); +a.foo = function(): C { + return new C(); +}; + +" +`; diff --git a/tests/immutable_methods/jsfmt.spec.js b/tests/immutable_methods/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/immutable_methods/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/immutable_methods/test.js b/tests/immutable_methods/test.js new file mode 100644 index 000000000000..2278239a27d9 --- /dev/null +++ b/tests/immutable_methods/test.js @@ -0,0 +1,9 @@ +class A { + foo(): A { return this; } +} +class B extends A { + foo(): B { return this; } +} +class C extends A {} +var a: A = new B(); +a.foo = function(): C { return new C(); } diff --git a/tests/import_type/ExportCJSDefault_Class.js b/tests/import_type/ExportCJSDefault_Class.js new file mode 100644 index 000000000000..dbbb5594a550 --- /dev/null +++ b/tests/import_type/ExportCJSDefault_Class.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +class ClassFoo3 { + givesANum(): number { return 42; } + static givesAFoo3(): ClassFoo3 { + return new ClassFoo3(); + } +} + +module.exports = ClassFoo3; diff --git a/tests/import_type/ExportCJSNamed_Class.js b/tests/import_type/ExportCJSNamed_Class.js new file mode 100644 index 000000000000..5a6ff405708a --- /dev/null +++ b/tests/import_type/ExportCJSNamed_Class.js @@ -0,0 +1,22 @@ +/** + * @flow + */ + +class ClassFoo4 { + returnsANumber(): number { return 42; } +} + +class ClassFoo5 {} + +function givesAFoo4(): ClassFoo4 { + return new ClassFoo4(); +} + +function givesAFoo5(): ClassFoo5 { + return new ClassFoo5(); +} + +exports.ClassFoo4 = ClassFoo4; +exports.ClassFoo5 = ClassFoo5 +exports.foo4Inst = new ClassFoo4(); +exports.foo5Inst = new ClassFoo5(); diff --git a/tests/import_type/ExportDefault_Class.js b/tests/import_type/ExportDefault_Class.js new file mode 100644 index 000000000000..9fe9fb3dc2e7 --- /dev/null +++ b/tests/import_type/ExportDefault_Class.js @@ -0,0 +1,10 @@ +/** + * @flow + */ + +class ClassFoo1 { + returnsANumber(): number { return 42; } +} + +export default ClassFoo1; +export var foo1Inst = new ClassFoo1(); diff --git a/tests/import_type/ExportNamed_Alias.js b/tests/import_type/ExportNamed_Alias.js new file mode 100644 index 000000000000..0f8c0f810195 --- /dev/null +++ b/tests/import_type/ExportNamed_Alias.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +export type AliasFoo3 = { + givesANum(): number +}; +export function givesAFoo3Obj(): AliasFoo3 { + return { + givesANum(): number { return 42; } + }; +}; diff --git a/tests/import_type/ExportNamed_Class.js b/tests/import_type/ExportNamed_Class.js new file mode 100644 index 000000000000..e5486eec5430 --- /dev/null +++ b/tests/import_type/ExportNamed_Class.js @@ -0,0 +1,10 @@ +/** + * @flow + */ + +class ClassFoo2 { + returnsANumber(): number { return 42; } +} + +export {ClassFoo2}; +export var foo2Inst = new ClassFoo2(); diff --git a/tests/import_type/ExportsANumber.js b/tests/import_type/ExportsANumber.js new file mode 100644 index 000000000000..bd4ab83a20e3 --- /dev/null +++ b/tests/import_type/ExportsANumber.js @@ -0,0 +1,3 @@ +/* @ flow */ + +export var numValue = 42; diff --git a/tests/import_type/__snapshots__/jsfmt.spec.js.snap b/tests/import_type/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..86121979ecbe --- /dev/null +++ b/tests/import_type/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,340 @@ +exports[`test ExportCJSDefault_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo3 { + givesANum(): number { return 42; } + static givesAFoo3(): ClassFoo3 { + return new ClassFoo3(); + } +} + +module.exports = ClassFoo3; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class ClassFoo3 { + givesANum(): number { + return 42; + } + givesAFoo3(): ClassFoo3 { + return new ClassFoo3(); + } +} +module.exports = ClassFoo3; + +" +`; + +exports[`test ExportCJSNamed_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo4 { + returnsANumber(): number { return 42; } +} + +class ClassFoo5 {} + +function givesAFoo4(): ClassFoo4 { + return new ClassFoo4(); +} + +function givesAFoo5(): ClassFoo5 { + return new ClassFoo5(); +} + +exports.ClassFoo4 = ClassFoo4; +exports.ClassFoo5 = ClassFoo5 +exports.foo4Inst = new ClassFoo4(); +exports.foo5Inst = new ClassFoo5(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class ClassFoo4 { + returnsANumber(): number { + return 42; + } +} +class ClassFoo5 {} +function givesAFoo4(): ClassFoo4 { + return new ClassFoo4(); +} +function givesAFoo5(): ClassFoo5 { + return new ClassFoo5(); +} +exports.ClassFoo4 = ClassFoo4; +exports.ClassFoo5 = ClassFoo5; +exports.foo4Inst = new ClassFoo4(); +exports.foo5Inst = new ClassFoo5(); + +" +`; + +exports[`test ExportDefault_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo1 { + returnsANumber(): number { return 42; } +} + +export default ClassFoo1; +export var foo1Inst = new ClassFoo1(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class ClassFoo1 { + returnsANumber(): number { + return 42; + } +} +export default ClassFoo1 +export var foo1Inst = new ClassFoo1(); + +" +`; + +exports[`test ExportNamed_Alias.js 1`] = ` +"/** + * @flow + */ + +export type AliasFoo3 = { + givesANum(): number +}; +export function givesAFoo3Obj(): AliasFoo3 { + return { + givesANum(): number { return 42; } + }; +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test ExportNamed_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo2 { + returnsANumber(): number { return 42; } +} + +export {ClassFoo2}; +export var foo2Inst = new ClassFoo2(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test ExportsANumber.js 1`] = ` +"/* @ flow */ + +export var numValue = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @ flow */ +export var numValue = 42; + +" +`; + +exports[`test import_type.js 1`] = ` +"/** + * @flow + */ + +///////////////////////////////////////////////// +// == Importing Class Type (Default Export) == // +///////////////////////////////////////////////// + +import type ClassFoo1 from \"./ExportDefault_Class\"; +import {foo1Inst} from \"./ExportDefault_Class\"; + +var a1: ClassFoo1 = foo1Inst; +var a2: number = foo1Inst; // Error: ClassFoo1 ~> number +new ClassFoo1(); // Error: ClassFoo1 is not a value-identifier + +/////////////////////////////////////////////// +// == Importing Class Type (Named Export) == // +/////////////////////////////////////////////// + +import type {ClassFoo2} from \"./ExportNamed_Class\"; +import {foo2Inst} from \"./ExportNamed_Class\"; + +var b1: ClassFoo2 = foo2Inst; +var b2: number = foo2Inst; // Error: ClassFoo2 ~> number +new ClassFoo2(); // Error: ClassFoo2 is not a value-identifier + +///////////////////////////////////////////////////// +// == Importing Class Type (CJS Default Export) == // +///////////////////////////////////////////////////// + +import type ClassFoo3T from \"./ExportCJSDefault_Class\"; +import ClassFoo3 from \"./ExportCJSDefault_Class\"; +var c1: ClassFoo3T = new ClassFoo3(); +new ClassFoo3T(); // Error: ClassFoo3 is not a value-identifier + +/////////////////////////////////////////////////// +// == Importing Class Type (CJS Named Export) == // +/////////////////////////////////////////////////// + +import type {ClassFoo4, ClassFoo5} from \"./ExportCJSNamed_Class\"; +import {foo4Inst, foo5Inst} from \"./ExportCJSNamed_Class\"; + +var d1: ClassFoo4 = foo4Inst; +var d2: number = foo4Inst; // Error: ClassFoo4 ~> number +new ClassFoo4(); // Error: ClassFoo4 is not a value-identifier +// TODO: this errors correctly, but the message is just \'can\'t resolve name\' +var d3: typeof ClassFoo5 = foo5Inst; // Error: Can\'t typeof a type alias + +//////////////////////////////////////////// +// == Import Type Alias (Named Export) == // +//////////////////////////////////////////// + +import type {AliasFoo3} from \"./ExportNamed_Alias\"; +import {givesAFoo3Obj} from \"./ExportNamed_Alias\"; +var e1: AliasFoo3 = givesAFoo3Obj(); +var e2: number = givesAFoo3Obj(); // Error: AliasFoo3 ~> number +var e3: typeof AliasFoo3 = givesAFoo3Obj(); // Error: Can\'t typeof a type alias + +////////////////////////////////////////////// +// == Import Type Alias (Default Export) == // +////////////////////////////////////////////// + +// TODO: No support for this right now. It\'s most likely possible, but it\'s +// unclear how useful it is at the moment and it entails a little +// more work than named type exports, so I\'m punting on it for now. + +/////////////////////////////////////////////////////// +// == Import Type With Non-Alias Compatible Value == // +/////////////////////////////////////////////////////// + +import type {numValue} from \"./ExportsANumber\"; // Error: Cannot import-type a number value + +//////////////////////////////////////////////////////////////////////// +// == Regression Test: https://github.com/facebook/flow/issues/359 == // +// Ensure that type bindings stay type bindings across function body // +// env contexts. // +//////////////////////////////////////////////////////////////////////// + +import type ClassFoo6 from \"./issue-359\"; +function foo() { + ClassFoo6; // Error: Not a value binding +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +///////////////////////////////////////////////// +// == Importing Class Type (Default Export) == // +///////////////////////////////////////////////// +import type ClassFoo1 from \"./ExportDefault_Class\"; +import { foo1Inst } from \"./ExportDefault_Class\"; +var a1: ClassFoo1 = foo1Inst; +var a2: number = foo1Inst;// Error: ClassFoo1 ~> number +new ClassFoo1();// Error: ClassFoo1 is not a value-identifier +/////////////////////////////////////////////// +// == Importing Class Type (Named Export) == // +/////////////////////////////////////////////// +import type { ClassFoo2 } from \"./ExportNamed_Class\"; +import { foo2Inst } from \"./ExportNamed_Class\"; +var b1: ClassFoo2 = foo2Inst; +var b2: number = foo2Inst;// Error: ClassFoo2 ~> number +new ClassFoo2();// Error: ClassFoo2 is not a value-identifier +///////////////////////////////////////////////////// +// == Importing Class Type (CJS Default Export) == // +///////////////////////////////////////////////////// +import type ClassFoo3T from \"./ExportCJSDefault_Class\"; +import ClassFoo3 from \"./ExportCJSDefault_Class\"; +var c1: ClassFoo3T = new ClassFoo3(); +new ClassFoo3T();// Error: ClassFoo3 is not a value-identifier +/////////////////////////////////////////////////// +// == Importing Class Type (CJS Named Export) == // +/////////////////////////////////////////////////// +import type { ClassFoo4, ClassFoo5 } from \"./ExportCJSNamed_Class\"; +import { foo4Inst, foo5Inst } from \"./ExportCJSNamed_Class\"; +var d1: ClassFoo4 = foo4Inst; +var d2: number = foo4Inst;// Error: ClassFoo4 ~> number +new ClassFoo4();// Error: ClassFoo4 is not a value-identifier +// TODO: this errors correctly, but the message is just \'can\'t resolve name\' +var d3: typeof ClassFoo5 = foo5Inst;// Error: Can\'t typeof a type alias +//////////////////////////////////////////// +// == Import Type Alias (Named Export) == // +//////////////////////////////////////////// +import type { AliasFoo3 } from \"./ExportNamed_Alias\"; +import { givesAFoo3Obj } from \"./ExportNamed_Alias\"; +var e1: AliasFoo3 = givesAFoo3Obj(); +var e2: number = givesAFoo3Obj();// Error: AliasFoo3 ~> number +var e3: typeof AliasFoo3 = givesAFoo3Obj();// Error: Can\'t typeof a type alias +////////////////////////////////////////////// +// == Import Type Alias (Default Export) == // +////////////////////////////////////////////// +// TODO: No support for this right now. It\'s most likely possible, but it\'s +// unclear how useful it is at the moment and it entails a little +// more work than named type exports, so I\'m punting on it for now. +/////////////////////////////////////////////////////// +// == Import Type With Non-Alias Compatible Value == // +/////////////////////////////////////////////////////// +import type { numValue } from \"./ExportsANumber\";// Error: Cannot import-type a number value +//////////////////////////////////////////////////////////////////////// +// == Regression Test: https://github.com/facebook/flow/issues/359 == // +// Ensure that type bindings stay type bindings across function body // +// env contexts. // +//////////////////////////////////////////////////////////////////////// +import type ClassFoo6 from \"./issue-359\"; +function foo() { + ClassFoo6;// Error: Not a value binding +} + +" +`; + +exports[`test issue-359.js 1`] = ` +"/* @flow */ + +class ClassFoo6 {}; + +export default ClassFoo6; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class ClassFoo6 {} +export default ClassFoo6 + +" +`; diff --git a/tests/import_type/import_type.js b/tests/import_type/import_type.js new file mode 100644 index 000000000000..96ec2be84ea4 --- /dev/null +++ b/tests/import_type/import_type.js @@ -0,0 +1,82 @@ +/** + * @flow + */ + +///////////////////////////////////////////////// +// == Importing Class Type (Default Export) == // +///////////////////////////////////////////////// + +import type ClassFoo1 from "./ExportDefault_Class"; +import {foo1Inst} from "./ExportDefault_Class"; + +var a1: ClassFoo1 = foo1Inst; +var a2: number = foo1Inst; // Error: ClassFoo1 ~> number +new ClassFoo1(); // Error: ClassFoo1 is not a value-identifier + +/////////////////////////////////////////////// +// == Importing Class Type (Named Export) == // +/////////////////////////////////////////////// + +import type {ClassFoo2} from "./ExportNamed_Class"; +import {foo2Inst} from "./ExportNamed_Class"; + +var b1: ClassFoo2 = foo2Inst; +var b2: number = foo2Inst; // Error: ClassFoo2 ~> number +new ClassFoo2(); // Error: ClassFoo2 is not a value-identifier + +///////////////////////////////////////////////////// +// == Importing Class Type (CJS Default Export) == // +///////////////////////////////////////////////////// + +import type ClassFoo3T from "./ExportCJSDefault_Class"; +import ClassFoo3 from "./ExportCJSDefault_Class"; +var c1: ClassFoo3T = new ClassFoo3(); +new ClassFoo3T(); // Error: ClassFoo3 is not a value-identifier + +/////////////////////////////////////////////////// +// == Importing Class Type (CJS Named Export) == // +/////////////////////////////////////////////////// + +import type {ClassFoo4, ClassFoo5} from "./ExportCJSNamed_Class"; +import {foo4Inst, foo5Inst} from "./ExportCJSNamed_Class"; + +var d1: ClassFoo4 = foo4Inst; +var d2: number = foo4Inst; // Error: ClassFoo4 ~> number +new ClassFoo4(); // Error: ClassFoo4 is not a value-identifier +// TODO: this errors correctly, but the message is just 'can't resolve name' +var d3: typeof ClassFoo5 = foo5Inst; // Error: Can't typeof a type alias + +//////////////////////////////////////////// +// == Import Type Alias (Named Export) == // +//////////////////////////////////////////// + +import type {AliasFoo3} from "./ExportNamed_Alias"; +import {givesAFoo3Obj} from "./ExportNamed_Alias"; +var e1: AliasFoo3 = givesAFoo3Obj(); +var e2: number = givesAFoo3Obj(); // Error: AliasFoo3 ~> number +var e3: typeof AliasFoo3 = givesAFoo3Obj(); // Error: Can't typeof a type alias + +////////////////////////////////////////////// +// == Import Type Alias (Default Export) == // +////////////////////////////////////////////// + +// TODO: No support for this right now. It's most likely possible, but it's +// unclear how useful it is at the moment and it entails a little +// more work than named type exports, so I'm punting on it for now. + +/////////////////////////////////////////////////////// +// == Import Type With Non-Alias Compatible Value == // +/////////////////////////////////////////////////////// + +import type {numValue} from "./ExportsANumber"; // Error: Cannot import-type a number value + +//////////////////////////////////////////////////////////////////////// +// == Regression Test: https://github.com/facebook/flow/issues/359 == // +// Ensure that type bindings stay type bindings across function body // +// env contexts. // +//////////////////////////////////////////////////////////////////////// + +import type ClassFoo6 from "./issue-359"; +function foo() { + ClassFoo6; // Error: Not a value binding +} diff --git a/tests/import_type/issue-359.js b/tests/import_type/issue-359.js new file mode 100644 index 000000000000..ee16df3468f4 --- /dev/null +++ b/tests/import_type/issue-359.js @@ -0,0 +1,5 @@ +/* @flow */ + +class ClassFoo6 {}; + +export default ClassFoo6; diff --git a/tests/import_type/jsfmt.spec.js b/tests/import_type/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/import_type/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/import_typeof/ExportCJSDefault_Class.js b/tests/import_typeof/ExportCJSDefault_Class.js new file mode 100644 index 000000000000..dbbb5594a550 --- /dev/null +++ b/tests/import_typeof/ExportCJSDefault_Class.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +class ClassFoo3 { + givesANum(): number { return 42; } + static givesAFoo3(): ClassFoo3 { + return new ClassFoo3(); + } +} + +module.exports = ClassFoo3; diff --git a/tests/import_typeof/ExportCJSDefault_Number.js b/tests/import_typeof/ExportCJSDefault_Number.js new file mode 100644 index 000000000000..a659089f56f5 --- /dev/null +++ b/tests/import_typeof/ExportCJSDefault_Number.js @@ -0,0 +1,3 @@ +/* @flow */ + +module.exports = 42; diff --git a/tests/import_typeof/ExportCJSNamed_Class.js b/tests/import_typeof/ExportCJSNamed_Class.js new file mode 100644 index 000000000000..d62df9161ea5 --- /dev/null +++ b/tests/import_typeof/ExportCJSNamed_Class.js @@ -0,0 +1,7 @@ +/** + * @flow + */ + +class ClassFoo4 {} + +exports.ClassFoo4 = ClassFoo4; diff --git a/tests/import_typeof/ExportCJSNamed_Number.js b/tests/import_typeof/ExportCJSNamed_Number.js new file mode 100644 index 000000000000..9341801928fd --- /dev/null +++ b/tests/import_typeof/ExportCJSNamed_Number.js @@ -0,0 +1,3 @@ +/* @flow */ + +exports.num = 42; diff --git a/tests/import_typeof/ExportDefault_Class.js b/tests/import_typeof/ExportDefault_Class.js new file mode 100644 index 000000000000..04777aa3fa28 --- /dev/null +++ b/tests/import_typeof/ExportDefault_Class.js @@ -0,0 +1,9 @@ +/** + * @flow + */ + +class ClassFoo1 { + returnsANumber(): number { return 42; } +} + +export default ClassFoo1; diff --git a/tests/import_typeof/ExportDefault_Number.js b/tests/import_typeof/ExportDefault_Number.js new file mode 100644 index 000000000000..4f63aba00b99 --- /dev/null +++ b/tests/import_typeof/ExportDefault_Number.js @@ -0,0 +1,3 @@ +/* @flow */ + +export default 42; diff --git a/tests/import_typeof/ExportNamed_Alias.js b/tests/import_typeof/ExportNamed_Alias.js new file mode 100644 index 000000000000..0f8c0f810195 --- /dev/null +++ b/tests/import_typeof/ExportNamed_Alias.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +export type AliasFoo3 = { + givesANum(): number +}; +export function givesAFoo3Obj(): AliasFoo3 { + return { + givesANum(): number { return 42; } + }; +}; diff --git a/tests/import_typeof/ExportNamed_Class.js b/tests/import_typeof/ExportNamed_Class.js new file mode 100644 index 000000000000..90ee78a0b440 --- /dev/null +++ b/tests/import_typeof/ExportNamed_Class.js @@ -0,0 +1,9 @@ +/** + * @flow + */ + +class ClassFoo2 { + returnsANumber(): number { return 42; } +} + +export {ClassFoo2}; diff --git a/tests/import_typeof/ExportNamed_Multi.js b/tests/import_typeof/ExportNamed_Multi.js new file mode 100644 index 000000000000..91f96c936d6f --- /dev/null +++ b/tests/import_typeof/ExportNamed_Multi.js @@ -0,0 +1,4 @@ +// @flow + +export var num = 42; +export var str = 'asdf'; diff --git a/tests/import_typeof/ExportNamed_Number.js b/tests/import_typeof/ExportNamed_Number.js new file mode 100644 index 000000000000..dc4b2ec97d0d --- /dev/null +++ b/tests/import_typeof/ExportNamed_Number.js @@ -0,0 +1,3 @@ +/* @flow */ + +export var num = 42; diff --git a/tests/import_typeof/__snapshots__/jsfmt.spec.js.snap b/tests/import_typeof/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5eade817f7a9 --- /dev/null +++ b/tests/import_typeof/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,371 @@ +exports[`test ExportCJSDefault_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo3 { + givesANum(): number { return 42; } + static givesAFoo3(): ClassFoo3 { + return new ClassFoo3(); + } +} + +module.exports = ClassFoo3; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class ClassFoo3 { + givesANum(): number { + return 42; + } + givesAFoo3(): ClassFoo3 { + return new ClassFoo3(); + } +} +module.exports = ClassFoo3; + +" +`; + +exports[`test ExportCJSDefault_Number.js 1`] = ` +"/* @flow */ + +module.exports = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports = 42; + +" +`; + +exports[`test ExportCJSNamed_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo4 {} + +exports.ClassFoo4 = ClassFoo4; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class ClassFoo4 {} +exports.ClassFoo4 = ClassFoo4; + +" +`; + +exports[`test ExportCJSNamed_Number.js 1`] = ` +"/* @flow */ + +exports.num = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +exports.num = 42; + +" +`; + +exports[`test ExportDefault_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo1 { + returnsANumber(): number { return 42; } +} + +export default ClassFoo1; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class ClassFoo1 { + returnsANumber(): number { + return 42; + } +} +export default ClassFoo1 + +" +`; + +exports[`test ExportDefault_Number.js 1`] = ` +"/* @flow */ + +export default 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +export default 42 + +" +`; + +exports[`test ExportNamed_Alias.js 1`] = ` +"/** + * @flow + */ + +export type AliasFoo3 = { + givesANum(): number +}; +export function givesAFoo3Obj(): AliasFoo3 { + return { + givesANum(): number { return 42; } + }; +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test ExportNamed_Class.js 1`] = ` +"/** + * @flow + */ + +class ClassFoo2 { + returnsANumber(): number { return 42; } +} + +export {ClassFoo2}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1785 + fromString(\", \").join(path.map(print, \"specifiers\")), + ^ + +TypeError: fromString(...).join is not a function + at printExportDeclaration (/src/printer.js:1785:26) + at genericPrintNoParens (/src/printer.js:488:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 +" +`; + +exports[`test ExportNamed_Multi.js 1`] = ` +"// @flow + +export var num = 42; +export var str = \'asdf\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export var num = 42; +export var str = \"asdf\"; + +" +`; + +exports[`test ExportNamed_Number.js 1`] = ` +"/* @flow */ + +export var num = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +export var num = 42; + +" +`; + +exports[`test import_typeof.js 1`] = ` +"/** + * @flow + */ + +/////////////////////////////////////////////////// +// == Importing Class Typeof (Default Export) == // +/////////////////////////////////////////////////// + +import typeof ClassFoo1T from \"./ExportDefault_Class\"; +import ClassFoo1 from \"./ExportDefault_Class\"; + +var a1: ClassFoo1T = ClassFoo1; +var a2: ClassFoo1T = new ClassFoo1(); // Error: ClassFoo1 (inst) ~> ClassFoo1 (class) +new ClassFoo1T(); // Error: ClassFoo1T is not bound to a value + +///////////////////////////////////////////////// +// == Importing Class Typeof (Named Export) == // +///////////////////////////////////////////////// + +import typeof {ClassFoo2 as ClassFoo2T} from \"./ExportNamed_Class\"; +import {ClassFoo2} from \"./ExportNamed_Class\"; + +var b1: ClassFoo2T = ClassFoo2; +var b2: ClassFoo2T = new ClassFoo2(); // Error: ClassFoo2 (inst) ~> ClassFoo2 (class) +new ClassFoo2T(); // Error: ClassFoo2T is not bound to a value + +/////////////////////////////////////////////////////// +// == Importing Class Typeof (CJS Default Export) == // +/////////////////////////////////////////////////////// + +import typeof ClassFoo3T from \"./ExportCJSDefault_Class\"; +import ClassFoo3 from \"./ExportCJSDefault_Class\"; + +var c1: ClassFoo3T = ClassFoo3; +var c2: ClassFoo3T = new ClassFoo3(); // Error: ClassFoo3 (inst) ~> ClassFoo3 (class) + +///////////////////////////////////////////////////// +// == Importing Class Typeof (CJS Named Export) == // +///////////////////////////////////////////////////// + +import typeof {ClassFoo4 as ClassFoo4T} from \"./ExportCJSNamed_Class\"; +import {ClassFoo4} from \"./ExportCJSNamed_Class\"; + +var d1: ClassFoo4T = ClassFoo4; +var d2: ClassFoo4T = new ClassFoo4(); // Error: ClassFoo4 (inst) ~> ClassFoo4 (class) + +////////////////////////////////////////////// +// == Import Typeof Alias (Named Export) == // +////////////////////////////////////////////// + +import typeof {AliasFoo3} from \"./ExportNamed_Alias\"; // Error: Can\'t \`import typeof\` type aliases! + +//////////////////////////////////////////////// +// == Import Typeof Alias (Default Export) == // +//////////////////////////////////////////////// + +// TODO: No support for this right now. It\'s most likely possible, but it\'s +// unclear how useful it is at the moment and it entails a little +// more work than named type exports, so I\'m punting on it for now. + +/////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (Default Export) == // +/////////////////////////////////////////////////////////////// + +import typeof num_default from \"./ExportDefault_Number\"; + +var f1: num_default = 42; +var f2: num_default = \'asdf\'; // Error: string ~> number + +///////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (Named Export) == // +///////////////////////////////////////////////////////////// + +import typeof {num as num_named} from \"./ExportNamed_Number\"; + +var g1: num_named = 42; +var g2: num_named = \'asdf\'; // Error: string ~> number + +/////////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (CJS Default Export) == // +/////////////////////////////////////////////////////////////////// + +import typeof num_cjs_default from \"./ExportCJSDefault_Number\"; + +var h1: num_cjs_default = 42; +var h2: num_cjs_default = \'asdf\'; // Error: string ~> number + +///////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (CJS Named Export) == // +///////////////////////////////////////////////////////////////// + +import typeof {num as num_cjs_named} from \"./ExportCJSNamed_Number\"; + +var i1: num_cjs_named = 42; +var i2: num_cjs_named = \'asdf\'; // Error: string ~> number + +/////////////////////////////////////////////// +// == Import Typeof ModuleNamespaceObject == // +/////////////////////////////////////////////// + +import typeof * as ModuleNSObjT from \"./ExportNamed_Multi\"; +var j1: ModuleNSObjT = {num: 42, str: \'asdf\'}; +var j2: ModuleNSObjT = {num: 42, str: 42}; // Error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +/////////////////////////////////////////////////// +// == Importing Class Typeof (Default Export) == // +/////////////////////////////////////////////////// +import typeof ClassFoo1T from \"./ExportDefault_Class\"; +import ClassFoo1 from \"./ExportDefault_Class\"; +var a1: ClassFoo1T = ClassFoo1; +var a2: ClassFoo1T = new ClassFoo1();// Error: ClassFoo1 (inst) ~> ClassFoo1 (class) +new ClassFoo1T();// Error: ClassFoo1T is not bound to a value +///////////////////////////////////////////////// +// == Importing Class Typeof (Named Export) == // +///////////////////////////////////////////////// +import typeof { ClassFoo2 as ClassFoo2T } from \"./ExportNamed_Class\"; +import { ClassFoo2 } from \"./ExportNamed_Class\"; +var b1: ClassFoo2T = ClassFoo2; +var b2: ClassFoo2T = new ClassFoo2();// Error: ClassFoo2 (inst) ~> ClassFoo2 (class) +new ClassFoo2T();// Error: ClassFoo2T is not bound to a value +/////////////////////////////////////////////////////// +// == Importing Class Typeof (CJS Default Export) == // +/////////////////////////////////////////////////////// +import typeof ClassFoo3T from \"./ExportCJSDefault_Class\"; +import ClassFoo3 from \"./ExportCJSDefault_Class\"; +var c1: ClassFoo3T = ClassFoo3; +var c2: ClassFoo3T = new ClassFoo3();// Error: ClassFoo3 (inst) ~> ClassFoo3 (class) +///////////////////////////////////////////////////// +// == Importing Class Typeof (CJS Named Export) == // +///////////////////////////////////////////////////// +import typeof { ClassFoo4 as ClassFoo4T } from \"./ExportCJSNamed_Class\"; +import { ClassFoo4 } from \"./ExportCJSNamed_Class\"; +var d1: ClassFoo4T = ClassFoo4; +var d2: ClassFoo4T = new ClassFoo4();// Error: ClassFoo4 (inst) ~> ClassFoo4 (class) +////////////////////////////////////////////// +// == Import Typeof Alias (Named Export) == // +////////////////////////////////////////////// +import typeof { AliasFoo3 } from \"./ExportNamed_Alias\";// Error: Can\'t \`import typeof\` type aliases! +//////////////////////////////////////////////// +// == Import Typeof Alias (Default Export) == // +//////////////////////////////////////////////// +// TODO: No support for this right now. It\'s most likely possible, but it\'s +// unclear how useful it is at the moment and it entails a little +// more work than named type exports, so I\'m punting on it for now. +/////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (Default Export) == // +/////////////////////////////////////////////////////////////// +import typeof num_default from \"./ExportDefault_Number\"; +var f1: num_default = 42; +var f2: num_default = \"asdf\";// Error: string ~> number +///////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (Named Export) == // +///////////////////////////////////////////////////////////// +import typeof { num as num_named } from \"./ExportNamed_Number\"; +var g1: num_named = 42; +var g2: num_named = \"asdf\";// Error: string ~> number +/////////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (CJS Default Export) == // +/////////////////////////////////////////////////////////////////// +import typeof num_cjs_default from \"./ExportCJSDefault_Number\"; +var h1: num_cjs_default = 42; +var h2: num_cjs_default = \"asdf\";// Error: string ~> number +///////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (CJS Named Export) == // +///////////////////////////////////////////////////////////////// +import typeof { num as num_cjs_named } from \"./ExportCJSNamed_Number\"; +var i1: num_cjs_named = 42; +var i2: num_cjs_named = \"asdf\";// Error: string ~> number +/////////////////////////////////////////////// +// == Import Typeof ModuleNamespaceObject == // +/////////////////////////////////////////////// +import typeof * as ModuleNSObjT from \"./ExportNamed_Multi\"; +var j1: ModuleNSObjT = { num: 42, str: \"asdf\" }; +var j2: ModuleNSObjT = { num: 42, str: 42 };// Error: number ~> string + +" +`; diff --git a/tests/import_typeof/import_typeof.js b/tests/import_typeof/import_typeof.js new file mode 100644 index 000000000000..6916f800420c --- /dev/null +++ b/tests/import_typeof/import_typeof.js @@ -0,0 +1,103 @@ +/** + * @flow + */ + +/////////////////////////////////////////////////// +// == Importing Class Typeof (Default Export) == // +/////////////////////////////////////////////////// + +import typeof ClassFoo1T from "./ExportDefault_Class"; +import ClassFoo1 from "./ExportDefault_Class"; + +var a1: ClassFoo1T = ClassFoo1; +var a2: ClassFoo1T = new ClassFoo1(); // Error: ClassFoo1 (inst) ~> ClassFoo1 (class) +new ClassFoo1T(); // Error: ClassFoo1T is not bound to a value + +///////////////////////////////////////////////// +// == Importing Class Typeof (Named Export) == // +///////////////////////////////////////////////// + +import typeof {ClassFoo2 as ClassFoo2T} from "./ExportNamed_Class"; +import {ClassFoo2} from "./ExportNamed_Class"; + +var b1: ClassFoo2T = ClassFoo2; +var b2: ClassFoo2T = new ClassFoo2(); // Error: ClassFoo2 (inst) ~> ClassFoo2 (class) +new ClassFoo2T(); // Error: ClassFoo2T is not bound to a value + +/////////////////////////////////////////////////////// +// == Importing Class Typeof (CJS Default Export) == // +/////////////////////////////////////////////////////// + +import typeof ClassFoo3T from "./ExportCJSDefault_Class"; +import ClassFoo3 from "./ExportCJSDefault_Class"; + +var c1: ClassFoo3T = ClassFoo3; +var c2: ClassFoo3T = new ClassFoo3(); // Error: ClassFoo3 (inst) ~> ClassFoo3 (class) + +///////////////////////////////////////////////////// +// == Importing Class Typeof (CJS Named Export) == // +///////////////////////////////////////////////////// + +import typeof {ClassFoo4 as ClassFoo4T} from "./ExportCJSNamed_Class"; +import {ClassFoo4} from "./ExportCJSNamed_Class"; + +var d1: ClassFoo4T = ClassFoo4; +var d2: ClassFoo4T = new ClassFoo4(); // Error: ClassFoo4 (inst) ~> ClassFoo4 (class) + +////////////////////////////////////////////// +// == Import Typeof Alias (Named Export) == // +////////////////////////////////////////////// + +import typeof {AliasFoo3} from "./ExportNamed_Alias"; // Error: Can't `import typeof` type aliases! + +//////////////////////////////////////////////// +// == Import Typeof Alias (Default Export) == // +//////////////////////////////////////////////// + +// TODO: No support for this right now. It's most likely possible, but it's +// unclear how useful it is at the moment and it entails a little +// more work than named type exports, so I'm punting on it for now. + +/////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (Default Export) == // +/////////////////////////////////////////////////////////////// + +import typeof num_default from "./ExportDefault_Number"; + +var f1: num_default = 42; +var f2: num_default = 'asdf'; // Error: string ~> number + +///////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (Named Export) == // +///////////////////////////////////////////////////////////// + +import typeof {num as num_named} from "./ExportNamed_Number"; + +var g1: num_named = 42; +var g2: num_named = 'asdf'; // Error: string ~> number + +/////////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (CJS Default Export) == // +/////////////////////////////////////////////////////////////////// + +import typeof num_cjs_default from "./ExportCJSDefault_Number"; + +var h1: num_cjs_default = 42; +var h2: num_cjs_default = 'asdf'; // Error: string ~> number + +///////////////////////////////////////////////////////////////// +// == Import Typeof With Non-Class Value (CJS Named Export) == // +///////////////////////////////////////////////////////////////// + +import typeof {num as num_cjs_named} from "./ExportCJSNamed_Number"; + +var i1: num_cjs_named = 42; +var i2: num_cjs_named = 'asdf'; // Error: string ~> number + +/////////////////////////////////////////////// +// == Import Typeof ModuleNamespaceObject == // +/////////////////////////////////////////////// + +import typeof * as ModuleNSObjT from "./ExportNamed_Multi"; +var j1: ModuleNSObjT = {num: 42, str: 'asdf'}; +var j2: ModuleNSObjT = {num: 42, str: 42}; // Error: number ~> string diff --git a/tests/import_typeof/jsfmt.spec.js b/tests/import_typeof/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/import_typeof/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/include/foo/batman/__snapshots__/jsfmt.spec.js.snap b/tests/include/foo/batman/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0716adec34e2 --- /dev/null +++ b/tests/include/foo/batman/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test baz.js 1`] = ` +"/* @flow */ + +var x: number = "not a number" // Error string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var x: number = "not a number";// Error string ~> number + +" +`; diff --git a/tests/include/foo/batman/baz.js b/tests/include/foo/batman/baz.js new file mode 100644 index 000000000000..d6b2eca30b2a --- /dev/null +++ b/tests/include/foo/batman/baz.js @@ -0,0 +1,3 @@ +/* @flow */ + +var x: number = "not a number" // Error string ~> number diff --git a/tests/include/foo/batman/jsfmt.spec.js b/tests/include/foo/batman/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/include/foo/batman/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/include/included/__snapshots__/jsfmt.spec.js.snap b/tests/include/included/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0e05f7235a80 --- /dev/null +++ b/tests/include/included/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test test.js 1`] = ` +"(123: string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +(123: string); + +" +`; diff --git a/tests/include/included/jsfmt.spec.js b/tests/include/included/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/include/included/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/include/included/test.js b/tests/include/included/test.js new file mode 100644 index 000000000000..c41afeed67c2 --- /dev/null +++ b/tests/include/included/test.js @@ -0,0 +1 @@ +(123: string); diff --git a/tests/incremental/__snapshots__/jsfmt.spec.js.snap b/tests/incremental/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..51fa6eb132d4 --- /dev/null +++ b/tests/incremental/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,33 @@ +exports[`test a.js 1`] = ` +"/* @providesModule IncrModuleA */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test b.js 1`] = ` +"/* @providesModule IncrModuleB + @flow +*/ + +var A = require('IncrModuleA'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule IncrModuleB + @flow +*/ +var A = require("IncrModuleA"); + +" +`; + +exports[`test dup_a.js 1`] = ` +"/* @providesModule IncrModuleA */ + +var x:string = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule IncrModuleA */ +var x: string = 0; + +" +`; diff --git a/tests/incremental/a.js b/tests/incremental/a.js new file mode 100644 index 000000000000..02ef81a82995 --- /dev/null +++ b/tests/incremental/a.js @@ -0,0 +1 @@ +/* @providesModule IncrModuleA */ diff --git a/tests/incremental/b.js b/tests/incremental/b.js new file mode 100644 index 000000000000..221ffef4467a --- /dev/null +++ b/tests/incremental/b.js @@ -0,0 +1,5 @@ +/* @providesModule IncrModuleB + @flow +*/ + +var A = require('IncrModuleA'); diff --git a/tests/incremental/dup_a.js b/tests/incremental/dup_a.js new file mode 100644 index 000000000000..b996546f23a1 --- /dev/null +++ b/tests/incremental/dup_a.js @@ -0,0 +1,3 @@ +/* @providesModule IncrModuleA */ + +var x:string = 0; diff --git a/tests/incremental/jsfmt.spec.js b/tests/incremental/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_basic/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_basic/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c90d4376220c --- /dev/null +++ b/tests/incremental_basic/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,39 @@ +exports[`test a.js 1`] = ` +"// @flow +var a: string = 0; +module.exports = a; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a: string = 0; +module.exports = a; + +" +`; + +exports[`test b.js 1`] = ` +"// @flow +var a = require('./a'); +var b: number = a; +module.exports = b; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a = require("./a"); +var b: number = a; +module.exports = b; + +" +`; + +exports[`test c.js 1`] = ` +"// @flow +var b = require('./b'); +var c: string = b; +module.exports = c; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var b = require("./b"); +var c: string = b; +module.exports = c; + +" +`; diff --git a/tests/incremental_basic/a.js b/tests/incremental_basic/a.js new file mode 100644 index 000000000000..f863b77254c3 --- /dev/null +++ b/tests/incremental_basic/a.js @@ -0,0 +1,3 @@ +// @flow +var a: string = 0; +module.exports = a; diff --git a/tests/incremental_basic/b.js b/tests/incremental_basic/b.js new file mode 100644 index 000000000000..8f3560a45c53 --- /dev/null +++ b/tests/incremental_basic/b.js @@ -0,0 +1,4 @@ +// @flow +var a = require('./a'); +var b: number = a; +module.exports = b; diff --git a/tests/incremental_basic/c.js b/tests/incremental_basic/c.js new file mode 100644 index 000000000000..3c6b3f56fe5d --- /dev/null +++ b/tests/incremental_basic/c.js @@ -0,0 +1,4 @@ +// @flow +var b = require('./b'); +var c: string = b; +module.exports = c; diff --git a/tests/incremental_basic/jsfmt.spec.js b/tests/incremental_basic/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_basic/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_basic/tmp1/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_basic/tmp1/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..53f45bfe5ffa --- /dev/null +++ b/tests/incremental_basic/tmp1/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,13 @@ +exports[`test b.js 1`] = ` +"// @flow +var a = require('./a'); +var b = a; +module.exports = b; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a = require("./a"); +var b = a; +module.exports = b; + +" +`; diff --git a/tests/incremental_basic/tmp1/b.js b/tests/incremental_basic/tmp1/b.js new file mode 100644 index 000000000000..14c1a8efab19 --- /dev/null +++ b/tests/incremental_basic/tmp1/b.js @@ -0,0 +1,4 @@ +// @flow +var a = require('./a'); +var b = a; +module.exports = b; diff --git a/tests/incremental_basic/tmp1/jsfmt.spec.js b/tests/incremental_basic/tmp1/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_basic/tmp1/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_basic/tmp2/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_basic/tmp2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2f9e0b72c72f --- /dev/null +++ b/tests/incremental_basic/tmp2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,11 @@ +exports[`test a.js 1`] = ` +"// @flow +var a = 0; +module.exports = a; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a = 0; +module.exports = a; + +" +`; diff --git a/tests/incremental_basic/tmp2/a.js b/tests/incremental_basic/tmp2/a.js new file mode 100644 index 000000000000..6c8a55571b7a --- /dev/null +++ b/tests/incremental_basic/tmp2/a.js @@ -0,0 +1,3 @@ +// @flow +var a = 0; +module.exports = a; diff --git a/tests/incremental_basic/tmp2/jsfmt.spec.js b/tests/incremental_basic/tmp2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_basic/tmp2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_basic/tmp3/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_basic/tmp3/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9fc637bf3218 --- /dev/null +++ b/tests/incremental_basic/tmp3/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,13 @@ +exports[`test b.js 1`] = ` +"// @flow +var a = require('./a'); +var b: number = a; +module.exports = b; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a = require("./a"); +var b: number = a; +module.exports = b; + +" +`; diff --git a/tests/incremental_basic/tmp3/b.js b/tests/incremental_basic/tmp3/b.js new file mode 100644 index 000000000000..8f3560a45c53 --- /dev/null +++ b/tests/incremental_basic/tmp3/b.js @@ -0,0 +1,4 @@ +// @flow +var a = require('./a'); +var b: number = a; +module.exports = b; diff --git a/tests/incremental_basic/tmp3/jsfmt.spec.js b/tests/incremental_basic/tmp3/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_basic/tmp3/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_cycle/A.js b/tests/incremental_cycle/A.js new file mode 100644 index 000000000000..d745347242b6 --- /dev/null +++ b/tests/incremental_cycle/A.js @@ -0,0 +1,8 @@ +// @flow + +class A { + b: number; + c: string; +} + +module.exports = A; diff --git a/tests/incremental_cycle/B.js b/tests/incremental_cycle/B.js new file mode 100644 index 000000000000..2aebd1fc0cb8 --- /dev/null +++ b/tests/incremental_cycle/B.js @@ -0,0 +1,9 @@ +// @flow +var A = require ('./A'); +import type C from './C'; + +class B extends A { + c: C; +} + +module.exports = B; diff --git a/tests/incremental_cycle/C.js b/tests/incremental_cycle/C.js new file mode 100644 index 000000000000..3b7aed9f91d3 --- /dev/null +++ b/tests/incremental_cycle/C.js @@ -0,0 +1,9 @@ +// @flow +var A = require ('./A'); +import type B from './B'; + +class C extends A { + b: B; +} + +module.exports = C; diff --git a/tests/incremental_cycle/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_cycle/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..48806a659072 --- /dev/null +++ b/tests/incremental_cycle/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,63 @@ +exports[`test A.js 1`] = ` +"// @flow + +class A { + b: number; + c: string; +} + +module.exports = A; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class A { + b: number; + c: string; +} +module.exports = A; + +" +`; + +exports[`test B.js 1`] = ` +"// @flow +var A = require ('./A'); +import type C from './C'; + +class B extends A { + c: C; +} + +module.exports = B; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var A = require("./A"); +import type C from "./C"; +class B extends A { + c: C; +} +module.exports = B; + +" +`; + +exports[`test C.js 1`] = ` +"// @flow +var A = require ('./A'); +import type B from './B'; + +class C extends A { + b: B; +} + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var A = require("./A"); +import type B from "./B"; +class C extends A { + b: B; +} +module.exports = C; + +" +`; diff --git a/tests/incremental_cycle/jsfmt.spec.js b/tests/incremental_cycle/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_cycle/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_cycle/tmp1/B.js b/tests/incremental_cycle/tmp1/B.js new file mode 100644 index 000000000000..0beb2ae1ee93 --- /dev/null +++ b/tests/incremental_cycle/tmp1/B.js @@ -0,0 +1,5 @@ +// @flow +var A = require ('./A'); +import type C from './C'; + +export type B = string; diff --git a/tests/incremental_cycle/tmp1/C.js b/tests/incremental_cycle/tmp1/C.js new file mode 100644 index 000000000000..6e957cdd46d1 --- /dev/null +++ b/tests/incremental_cycle/tmp1/C.js @@ -0,0 +1,9 @@ +// @flow +var A = require ('./A'); +import type { B } from './B' + +class C extends A { + b: B; +} + +module.exports = C; diff --git a/tests/incremental_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2712efe33fbd --- /dev/null +++ b/tests/incremental_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,36 @@ +exports[`test B.js 1`] = ` +"// @flow +var A = require ('./A'); +import type C from './C'; + +export type B = string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var A = require("./A"); +import type C from "./C"; +export type B = string; + +" +`; + +exports[`test C.js 1`] = ` +"// @flow +var A = require ('./A'); +import type { B } from './B' + +class C extends A { + b: B; +} + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var A = require("./A"); +import type { B } from "./B"; +class C extends A { + b: B; +} +module.exports = C; + +" +`; diff --git a/tests/incremental_cycle/tmp1/jsfmt.spec.js b/tests/incremental_cycle/tmp1/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_cycle/tmp1/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_cycle/tmp2/B.js b/tests/incremental_cycle/tmp2/B.js new file mode 100644 index 000000000000..b9f7dd32dc37 --- /dev/null +++ b/tests/incremental_cycle/tmp2/B.js @@ -0,0 +1,5 @@ +// @flow +var A = require ('./A'); +//import type C from './C'; + +export type B = string; diff --git a/tests/incremental_cycle/tmp2/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_cycle/tmp2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6781d9af80b0 --- /dev/null +++ b/tests/incremental_cycle/tmp2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,14 @@ +exports[`test B.js 1`] = ` +"// @flow +var A = require ('./A'); +//import type C from './C'; + +export type B = string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var A = require("./A"); +//import type C from './C'; +export type B = string; + +" +`; diff --git a/tests/incremental_cycle/tmp2/jsfmt.spec.js b/tests/incremental_cycle/tmp2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_cycle/tmp2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_cycle/tmp3/B.js b/tests/incremental_cycle/tmp3/B.js new file mode 100644 index 000000000000..748fd837e9f8 --- /dev/null +++ b/tests/incremental_cycle/tmp3/B.js @@ -0,0 +1,6 @@ +// @flow +var A = require ('./A'); +import type C from './C'; + + +export type B = string; diff --git a/tests/incremental_cycle/tmp3/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_cycle/tmp3/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3e2ea4f503ac --- /dev/null +++ b/tests/incremental_cycle/tmp3/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test B.js 1`] = ` +"// @flow +var A = require ('./A'); +import type C from './C'; + + +export type B = string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var A = require("./A"); +import type C from "./C"; +export type B = string; + +" +`; diff --git a/tests/incremental_cycle/tmp3/jsfmt.spec.js b/tests/incremental_cycle/tmp3/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_cycle/tmp3/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_delete/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_delete/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..90424706cea3 --- /dev/null +++ b/tests/incremental_delete/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,123 @@ +exports[`test a.js 1`] = ` +"// @flow +var a: string = 0; +module.exports = a; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a: string = 0; +module.exports = a; + +" +`; + +exports[`test b.js 1`] = ` +"// @flow +var a = require('./a'); +var b: number = a; +module.exports = b; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var a = require("./a"); +var b: number = a; +module.exports = b; + +" +`; + +exports[`test c.js 1`] = ` +"// @flow +var b = require('./b'); +var c: string = b; +module.exports = c; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var b = require("./b"); +var c: string = b; +module.exports = c; + +" +`; + +exports[`test dupe1.js 1`] = ` +"/** + * Dupe provider 1/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe1"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Dupe provider 1/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe1"; + +" +`; + +exports[`test dupe2.js 1`] = ` +"/** + * Dupe provider 2/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe2"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Dupe provider 2/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe2"; + +" +`; + +exports[`test requires_dupe.js 1`] = ` +"/** + * depends on doubly-provided module + * @flow + */ +var dupe = require('Dupe'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * depends on doubly-provided module + * @flow + */ +var dupe = require("Dupe"); + +" +`; + +exports[`test requires_unchecked.js 1`] = ` +"/** + * depends on an unchecked module, which will be deleted + * @flow + */ +var unchecked = require('Unchecked'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * depends on an unchecked module, which will be deleted + * @flow + */ +var unchecked = require("Unchecked"); + +" +`; + +exports[`test unchecked.js 1`] = ` +"/** + * Not a flow module. + * @providesModule Unchecked + */ +module.exports = "unchecked"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Not a flow module. + * @providesModule Unchecked + */ +module.exports = "unchecked"; + +" +`; diff --git a/tests/incremental_delete/a.js b/tests/incremental_delete/a.js new file mode 100644 index 000000000000..f863b77254c3 --- /dev/null +++ b/tests/incremental_delete/a.js @@ -0,0 +1,3 @@ +// @flow +var a: string = 0; +module.exports = a; diff --git a/tests/incremental_delete/b.js b/tests/incremental_delete/b.js new file mode 100644 index 000000000000..8f3560a45c53 --- /dev/null +++ b/tests/incremental_delete/b.js @@ -0,0 +1,4 @@ +// @flow +var a = require('./a'); +var b: number = a; +module.exports = b; diff --git a/tests/incremental_delete/c.js b/tests/incremental_delete/c.js new file mode 100644 index 000000000000..3c6b3f56fe5d --- /dev/null +++ b/tests/incremental_delete/c.js @@ -0,0 +1,4 @@ +// @flow +var b = require('./b'); +var c: string = b; +module.exports = c; diff --git a/tests/incremental_delete/dupe1.js b/tests/incremental_delete/dupe1.js new file mode 100644 index 000000000000..1a298b67eae7 --- /dev/null +++ b/tests/incremental_delete/dupe1.js @@ -0,0 +1,6 @@ +/** + * Dupe provider 1/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe1"; diff --git a/tests/incremental_delete/dupe2.js b/tests/incremental_delete/dupe2.js new file mode 100644 index 000000000000..aa64ae687dd8 --- /dev/null +++ b/tests/incremental_delete/dupe2.js @@ -0,0 +1,6 @@ +/** + * Dupe provider 2/2 + * @providesModule Dupe + * @flow + */ +module.exports = "dupe2"; diff --git a/tests/incremental_delete/jsfmt.spec.js b/tests/incremental_delete/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_delete/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_delete/requires_dupe.js b/tests/incremental_delete/requires_dupe.js new file mode 100644 index 000000000000..129992b7ab05 --- /dev/null +++ b/tests/incremental_delete/requires_dupe.js @@ -0,0 +1,5 @@ +/** + * depends on doubly-provided module + * @flow + */ +var dupe = require('Dupe'); diff --git a/tests/incremental_delete/requires_unchecked.js b/tests/incremental_delete/requires_unchecked.js new file mode 100644 index 000000000000..1db1b9bc6a4c --- /dev/null +++ b/tests/incremental_delete/requires_unchecked.js @@ -0,0 +1,5 @@ +/** + * depends on an unchecked module, which will be deleted + * @flow + */ +var unchecked = require('Unchecked'); diff --git a/tests/incremental_delete/unchecked.js b/tests/incremental_delete/unchecked.js new file mode 100644 index 000000000000..96d63429283f --- /dev/null +++ b/tests/incremental_delete/unchecked.js @@ -0,0 +1,5 @@ +/** + * Not a flow module. + * @providesModule Unchecked + */ +module.exports = "unchecked"; diff --git a/tests/incremental_duplicate_delete/A.js b/tests/incremental_duplicate_delete/A.js new file mode 100644 index 000000000000..638d95f80d1d --- /dev/null +++ b/tests/incremental_duplicate_delete/A.js @@ -0,0 +1,4 @@ +/** + * @providesModule A + * @flow + */ diff --git a/tests/incremental_duplicate_delete/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_duplicate_delete/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..519ef51f35cb --- /dev/null +++ b/tests/incremental_duplicate_delete/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test A.js 1`] = ` +"/** + * @providesModule A + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/incremental_duplicate_delete/jsfmt.spec.js b/tests/incremental_duplicate_delete/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_duplicate_delete/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_json/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_json/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..435a7ef63301 --- /dev/null +++ b/tests/incremental_json/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test test.js 1`] = ` +"/** + * @flow + */ +var data = require('./data'); +var x: number = data.x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +var data = require("./data"); +var x: number = data.x; + +" +`; diff --git a/tests/incremental_json/jsfmt.spec.js b/tests/incremental_json/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_json/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_json/test.js b/tests/incremental_json/test.js new file mode 100644 index 000000000000..3eb8f377fcbe --- /dev/null +++ b/tests/incremental_json/test.js @@ -0,0 +1,5 @@ +/** + * @flow + */ +var data = require('./data'); +var x: number = data.x; diff --git a/tests/incremental_mixed_naming_cycle/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_mixed_naming_cycle/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6b272ab92e10 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,102 @@ +exports[`test a.js 1`] = ` +"/** + * @providesModule A + * @flow + */ + +(require('./b'): void); +(require('C'): void); + +module.exports = 'A'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule A + * @flow + */ +(require("./b"): void); +(require("C"): void); +module.exports = "A"; + +" +`; + +exports[`test b.js 1`] = ` +"/** + * @providesModule B + * @flow + */ + +(require('A'): void); +(require('D'): void); + +module.exports = 'B'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule B + * @flow + */ +(require("A"): void); +(require("D"): void); +module.exports = "B"; + +" +`; + +exports[`test c.js 1`] = ` +"/** + * @providesModule C + * @flow + */ + +require('Root'); +(require('./b'): void); + +module.exports = 'C'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule C + * @flow + */ +require("Root"); +(require("./b"): void); +module.exports = "C"; + +" +`; + +exports[`test d.js 1`] = ` +"/** + * @providesModule D + * @flow + */ + +(require('./b'): void); + +module.exports = 'D'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule D + * @flow + */ +(require("./b"): void); +module.exports = "D"; + +" +`; + +exports[`test root.js 1`] = ` +"/** + * @providesModule Root + * @flow + */ + +module.exports = 'Root'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule Root + * @flow + */ +module.exports = "Root"; + +" +`; diff --git a/tests/incremental_mixed_naming_cycle/a.js b/tests/incremental_mixed_naming_cycle/a.js new file mode 100644 index 000000000000..e5effdb2d447 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/a.js @@ -0,0 +1,9 @@ +/** + * @providesModule A + * @flow + */ + +(require('./b'): void); +(require('C'): void); + +module.exports = 'A'; diff --git a/tests/incremental_mixed_naming_cycle/b.js b/tests/incremental_mixed_naming_cycle/b.js new file mode 100644 index 000000000000..be1f28147565 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/b.js @@ -0,0 +1,9 @@ +/** + * @providesModule B + * @flow + */ + +(require('A'): void); +(require('D'): void); + +module.exports = 'B'; diff --git a/tests/incremental_mixed_naming_cycle/c.js b/tests/incremental_mixed_naming_cycle/c.js new file mode 100644 index 000000000000..a9cf3abb6f6a --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/c.js @@ -0,0 +1,9 @@ +/** + * @providesModule C + * @flow + */ + +require('Root'); +(require('./b'): void); + +module.exports = 'C'; diff --git a/tests/incremental_mixed_naming_cycle/d.js b/tests/incremental_mixed_naming_cycle/d.js new file mode 100644 index 000000000000..b95edb89b908 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/d.js @@ -0,0 +1,8 @@ +/** + * @providesModule D + * @flow + */ + +(require('./b'): void); + +module.exports = 'D'; diff --git a/tests/incremental_mixed_naming_cycle/jsfmt.spec.js b/tests/incremental_mixed_naming_cycle/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_mixed_naming_cycle/root.js b/tests/incremental_mixed_naming_cycle/root.js new file mode 100644 index 000000000000..890d205a10e3 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/root.js @@ -0,0 +1,6 @@ +/** + * @providesModule Root + * @flow + */ + +module.exports = 'Root'; diff --git a/tests/incremental_mixed_naming_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_mixed_naming_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e441192b8fbe --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/tmp1/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test root.js 1`] = ` +"/** + * @providesModule Root + * @flow + */ + +// trivial edit (adding this comment) +module.exports = 'Root'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule Root + * @flow + */ +// trivial edit (adding this comment) +module.exports = "Root"; + +" +`; diff --git a/tests/incremental_mixed_naming_cycle/tmp1/jsfmt.spec.js b/tests/incremental_mixed_naming_cycle/tmp1/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/tmp1/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_mixed_naming_cycle/tmp1/root.js b/tests/incremental_mixed_naming_cycle/tmp1/root.js new file mode 100644 index 000000000000..d5d42fa36245 --- /dev/null +++ b/tests/incremental_mixed_naming_cycle/tmp1/root.js @@ -0,0 +1,7 @@ +/** + * @providesModule Root + * @flow + */ + +// trivial edit (adding this comment) +module.exports = 'Root'; diff --git a/tests/incremental_non_flow_move/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_non_flow_move/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..51bc01bd2485 --- /dev/null +++ b/tests/incremental_non_flow_move/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,24 @@ +exports[`test foo.js 1`] = ` +"/* + * @providesModule Foo + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test test.js 1`] = ` +"/** + * @flow + */ + +require('Foo'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +require("Foo"); + +" +`; diff --git a/tests/incremental_non_flow_move/foo.js b/tests/incremental_non_flow_move/foo.js new file mode 100644 index 000000000000..ddb85456b207 --- /dev/null +++ b/tests/incremental_non_flow_move/foo.js @@ -0,0 +1,3 @@ +/* + * @providesModule Foo + */ diff --git a/tests/incremental_non_flow_move/jsfmt.spec.js b/tests/incremental_non_flow_move/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_non_flow_move/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/incremental_non_flow_move/test.js b/tests/incremental_non_flow_move/test.js new file mode 100644 index 000000000000..98297b3fb64b --- /dev/null +++ b/tests/incremental_non_flow_move/test.js @@ -0,0 +1,5 @@ +/** + * @flow + */ + +require('Foo'); diff --git a/tests/incremental_path/dir/__snapshots__/jsfmt.spec.js.snap b/tests/incremental_path/dir/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4631bc37ffb5 --- /dev/null +++ b/tests/incremental_path/dir/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test a.js 1`] = ` +"// @flow +(require('b'): boolean); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +(require("b"): boolean); + +" +`; diff --git a/tests/incremental_path/dir/a.js b/tests/incremental_path/dir/a.js new file mode 100644 index 000000000000..cb2264c959c3 --- /dev/null +++ b/tests/incremental_path/dir/a.js @@ -0,0 +1,2 @@ +// @flow +(require('b'): boolean); diff --git a/tests/incremental_path/dir/jsfmt.spec.js b/tests/incremental_path/dir/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/incremental_path/dir/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/indexer/A.js b/tests/indexer/A.js new file mode 100644 index 000000000000..3f14aa36f4fc --- /dev/null +++ b/tests/indexer/A.js @@ -0,0 +1,39 @@ +// No indexer should be fine +function foo0(): {} { + return { foo: "bar" } +} + +// Matching indexer should be fine +function foo1(): {[key: string]: string} { + return { foo: "bar" } +} + +// Indexer with different key type is an error when it matches +function foo2(): {[key: number]: string} { + return { foo: "bar" } +} + +// Matching indexer with different value type is an error +function foo3(): {[key: string]: number} { + return { foo: "bar" } +} + +// Indexer with different key type and different value type is twice an error +function foo4(): {[key: number]: number} { + return { foo: "bar" } +} + +// If key exists in object type then indexer is not matched +function foo5(): {[key: string]: number; foo: string} { + return { foo: "bar" } +} + +// If key exists in object type then indexer is not matched +function foo6(): {[key: number]: number; foo: string} { + return { foo: "bar" } +} + +// Should still complain about mistyped properties +function foo7(): {[key: string]: number; foo: number} { + return { foo: "bar" } +} diff --git a/tests/indexer/__snapshots__/jsfmt.spec.js.snap b/tests/indexer/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..205a700b09df --- /dev/null +++ b/tests/indexer/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,101 @@ +exports[`test A.js 1`] = ` +"// No indexer should be fine +function foo0(): {} { + return { foo: "bar" } +} + +// Matching indexer should be fine +function foo1(): {[key: string]: string} { + return { foo: "bar" } +} + +// Indexer with different key type is an error when it matches +function foo2(): {[key: number]: string} { + return { foo: "bar" } +} + +// Matching indexer with different value type is an error +function foo3(): {[key: string]: number} { + return { foo: "bar" } +} + +// Indexer with different key type and different value type is twice an error +function foo4(): {[key: number]: number} { + return { foo: "bar" } +} + +// If key exists in object type then indexer is not matched +function foo5(): {[key: string]: number; foo: string} { + return { foo: "bar" } +} + +// If key exists in object type then indexer is not matched +function foo6(): {[key: number]: number; foo: string} { + return { foo: "bar" } +} + +// Should still complain about mistyped properties +function foo7(): {[key: string]: number; foo: number} { + return { foo: "bar" } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// No indexer should be fine +function foo0(): {} { + return { foo: "bar" }; +} +// Matching indexer should be fine +function foo1(): { [key: string]: string } { + return { foo: "bar" }; +} +// Indexer with different key type is an error when it matches +function foo2(): { [key: number]: string } { + return { foo: "bar" }; +} +// Matching indexer with different value type is an error +function foo3(): { [key: string]: number } { + return { foo: "bar" }; +} +// Indexer with different key type and different value type is twice an error +function foo4(): { [key: number]: number } { + return { foo: "bar" }; +} +// If key exists in object type then indexer is not matched +function foo5(): { [key: string]: number, foo: string } { + return { foo: "bar" }; +} +// If key exists in object type then indexer is not matched +function foo6(): { [key: number]: number, foo: string } { + return { foo: "bar" }; +} +// Should still complain about mistyped properties +function foo7(): { [key: string]: number, foo: number } { + return { foo: "bar" }; +} + +" +`; + +exports[`test multiple.js 1`] = ` +"// @flow + +let tests = [ + function() { + ({}: { + [k1: string]: string, + [k2: number]: number, // error: not supported (yet) + }); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + function() { + ({}: { + [k1: string]: string, + // error: not supported (yet) [k2: number]: number + }); + } +]; + +" +`; diff --git a/tests/indexer/jsfmt.spec.js b/tests/indexer/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/indexer/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/indexer/multiple.js b/tests/indexer/multiple.js new file mode 100644 index 000000000000..2d6e931c9420 --- /dev/null +++ b/tests/indexer/multiple.js @@ -0,0 +1,10 @@ +// @flow + +let tests = [ + function() { + ({}: { + [k1: string]: string, + [k2: number]: number, // error: not supported (yet) + }); + } +]; diff --git a/tests/init/__snapshots__/jsfmt.spec.js.snap b/tests/init/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..460df9006972 --- /dev/null +++ b/tests/init/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,552 @@ +exports[`test hoisted.js 1`] = ` +"/** + * test initialization tracking in the presence of hoisting + * @flow + */ + +function _if(b: () => boolean) { + if (b()) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _while(b: () => boolean) { + while (b()) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _do_while(b: () => boolean) { + do { + var f = function () {}; + } while (b()); + f(); // ok +} + +function _for(n: number) { + for (var i = 0; i < n; i++) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _for_in(obj: Object) { + for (var p in obj) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _for_of(arr: Array) { + for (var x of arr) { + var f = function () {}; + } + f(); // error, possibly undefined +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test hoisted2.js 1`] = ` +"/** + * test initialization tracking for vars + * note: for try/catch/finally, see tests/try/init.js + * @flow + */ + +// deferred init on annotated vars is ok +function linear_deferred_init() { + var x:number; + x = 0; + var y:number = x; +} + +// ...but use of var before init gives undefined +function linear_pre_init() { + var x:number; + var y:number = x; // error +} + +// local use of annotated vars in an if is ok +function if_scoped_init(b) { + if (b) { + var x:number = 0; + var y:number = x; + } +} + +// but not across if/else +function if_else_partial_init(b) { + if (b) { + var x:number = 0; + } else { + var y:number = x; // error + } +} + +// use of var before if gives undefined +function if_pre_init(b) { + var y:number = x; // error + if (b) { + var x:number = 0; + } +} + +// ...and after +function if_partial_post_init(b) { + if (b) { + var x:number = 0; + } + var y:number = x; // error +} + +// ...unless both branches have initialized +function if_post_init(b) { + if (b) { + var x:number = 0; + } else { + var x:number = 1; + } + var y:number = x; +} + +// use of var after partial init (non-exhaustive if) gives undefined +function if_partial_post_init(b) { + var x:number; + if (b) { + x = 0; + } + var y:number = x; // error, possibly uninitialized +} + +// use of var after guaranteed init (exhaustive if) is ok +function if_post_init(b) { + var x:number; + if (b) { + x = 0; + } else { + x = 1; + } + var y:number = x; +} + +// use of var after partial init (non-exhaustive switch) gives undefined +function switch_partial_post_init(i) { + var x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + } + var y:number = x; // error, possibly uninitialized +} + +// use of var after guaranteed init (exhaustive switch) is ok +function switch_post_init(i) { + var x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + default: + x = 2; + } + var y:number = x; // no error, all cases covered +} + +// local use of annotated var in switch is ok +function switch_scoped_init_1(i) { + switch (i) { + case 0: + var x:number = 0; + var y:number = x; + } +} + +// ...but use of var before switch gives undefined +function switch_scoped_init_2(i) { + var y:number = x; // error + switch (i) { + case 0: + var x:number = 0; + } +} + +// ...and after +function switch_scoped_init_3(i) { + switch (i) { + case 0: + var x:number = 0; + } + var y:number = x; // error +} + +// ...and in a fallthrough case without initialization +function switch_scoped_init_4(i) { + switch (i) { + case 0: + var x:number = 0; + case 1: + var y:number = x; // error + } +} + +// local use of annotated var in while is ok +function while_scoped_init(b) { + while (b) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use of var before while gives undefined +function while_pre_init(b) { + var y:number = x; // error + while (b) { + var x:number = 0; + } +} + +// ...and after +function while_post_init(b) { + while (b) { + var x:number = 0; + } + var y:number = x; // error +} + +// local use of annotated var in do-while is ok +function do_while_scoped_init(b) { + do { + var x:number = 0; + var y:number = x; + } while (b); +} + +// ...but use before do-while gives undefined +function do_while_pre_init(b) { + var y:number = x; // error + do { + var x:number = 0; + } while (b); +} + +// after is ok, because loop is guaranteed to run +function do_while_post_init(b) { + do { + var x:number = 0; + } while (b); + var y:number = x; +} + +// local use of annotated var in for is ok +function for_scoped_init(b) { + for (;b;) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use before for gives undefined +function for_pre_init(b) { + var y:number = x; // error + for (;b;) { + var x:number = 0; + } +} + +// ...and after +function for_post_init(b) { + for (;b;) { + var x:number = 0; + } + var y:number = x; // error +} + +// local use of annotated var in for-in is ok +function for_in_scoped_init() { + for (var p in { a:1, b: 2 }) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use before while gives undefined +function for_in_pre_init() { + var y:number = x; // error + for (var p in { a:1, b: 2 }) { + var x:number = 0; + } +} + +// ...and after +function for_in_post_init() { + for (var p in { a:1, b: 2 }) { + var x:number = 0; + } + var y:number = x; // error +} + +// local use of annotated var in for-of is ok +function for_of_scoped_init() { + for (var x of [1, 2, 3]) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use before while gives undefined +function for_in_pre_init() { + var y:number = x; // error + for (var x of [1, 2, 3]) { + var x:number = 0; + } +} + +// ...and after +function for_in_post_init() { + for (var x of [1, 2, 3]) { + var x:number = 0; + } + var y:number = x; // error +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test let.js 1`] = ` +"/** + * test initialization tracking for lets + * @flow + */ + +// deferred init on annotated lets is ok +function linear_deferred_init() { + let x:number; + x = 0; + let y:number = x; +} + +// use of let before init gives undefined +function linear_pre_init() { + let x:number; + let y:?number = x; // ok + let z:number = x; // error + x = 0; + let w:number = x; // ok +} + +// self-references in let bindings are not ok +function self_init() { + let x = x; // \'x\' not initialized! +} + +// use of let after partial init (non-exhaustive if) gives undefined +function if_partial_post_init(b) { + let x:number; + if (b) { + x = 0; + } + var y:number = x; // error, possibly uninitialized +} + +// use of let after guaranteed init (exhaustive if) is ok +function if_post_init(b) { + let x:number; + if (b) { + x = 0; + } else { + x = 1; + } + var y:number = x; +} + +// use of let after partial init (non-exhaustive switch) gives undefined +function switch_partial_post_init(i) { + let x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + } + var y:number = x; // error, possibly uninitialized +} + +// use of let after guaranteed init (exhaustive switch) is ok +function switch_post_init(i) { + let x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + default: + x = 2; + } + var y:number = x; // no error, all cases covered +} + +// use in a switch after a skipped decl is an error +function switch_scoped_init_2(i) { + switch (i) { + case 0: + let x:number; + case 1: + let y:number = x; // error, skipped declaration + } +} + +// while leaves it possibly uninitialized +function while_post_init(b) { + let x:number; + while (b) { + x = 0; + } + var y:number = x; // error +} + +// do-while is ok, because loop is guaranteed to run at least once +function do_while_post_init(b) { + let x:number; + do { + x = 0; + } while (b); + var y:number = x; // ok +} + +// for-in leaves it possibly uninitialized +function for_in_post_init() { + var x:number; + for (var p in {}) { + x = 0; + } + var y:number = x; // error +} + +// for-of leaves it possibly uninitialized +function for_of_post_init() { + var x:number; + for (var x of []) { + x = 0; + } + var y:number = x; // error +} + +// use of let after guaranteed init (exhaustive switch + throw) is ok +function switch_post_init2(i): number { + let bar; + switch (i) { + case 1: + bar = 3; + break; + default: + throw new Error(\'Invalid state\'); + } + return bar; // ok, definitely initialized +} + +// use of let after guaranteed init (exhaustive switch + throw) is ok +function switch_post_init2(i): number { + let bar; + switch (i) { + case 1: + bar = 3; + break; + default: + throw new Error(\'Invalid state\'); + } + return bar; // ok, definitely initialized +} + +// reference of a let-binding is permitted in a sub-closure within the init expr +function sub_closure_init_reference() { + let x = function() { return x; }; + const y = function() { return y; }; + + // var-bindings can reference each other cyclically since they do not incur a + // TDZ (...even though this is weird...) + var z = z; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test nullable-init.js 1`] = ` +"var o: {x: ?number} = { x: null }; +var a: Array = [null,null]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/init/hoisted.js b/tests/init/hoisted.js new file mode 100644 index 000000000000..0a5458712f18 --- /dev/null +++ b/tests/init/hoisted.js @@ -0,0 +1,46 @@ +/** + * test initialization tracking in the presence of hoisting + * @flow + */ + +function _if(b: () => boolean) { + if (b()) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _while(b: () => boolean) { + while (b()) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _do_while(b: () => boolean) { + do { + var f = function () {}; + } while (b()); + f(); // ok +} + +function _for(n: number) { + for (var i = 0; i < n; i++) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _for_in(obj: Object) { + for (var p in obj) { + var f = function () {}; + } + f(); // error, possibly undefined +} + +function _for_of(arr: Array) { + for (var x of arr) { + var f = function () {}; + } + f(); // error, possibly undefined +} diff --git a/tests/init/hoisted2.js b/tests/init/hoisted2.js new file mode 100644 index 000000000000..4258e0e46082 --- /dev/null +++ b/tests/init/hoisted2.js @@ -0,0 +1,268 @@ +/** + * test initialization tracking for vars + * note: for try/catch/finally, see tests/try/init.js + * @flow + */ + +// deferred init on annotated vars is ok +function linear_deferred_init() { + var x:number; + x = 0; + var y:number = x; +} + +// ...but use of var before init gives undefined +function linear_pre_init() { + var x:number; + var y:number = x; // error +} + +// local use of annotated vars in an if is ok +function if_scoped_init(b) { + if (b) { + var x:number = 0; + var y:number = x; + } +} + +// but not across if/else +function if_else_partial_init(b) { + if (b) { + var x:number = 0; + } else { + var y:number = x; // error + } +} + +// use of var before if gives undefined +function if_pre_init(b) { + var y:number = x; // error + if (b) { + var x:number = 0; + } +} + +// ...and after +function if_partial_post_init(b) { + if (b) { + var x:number = 0; + } + var y:number = x; // error +} + +// ...unless both branches have initialized +function if_post_init(b) { + if (b) { + var x:number = 0; + } else { + var x:number = 1; + } + var y:number = x; +} + +// use of var after partial init (non-exhaustive if) gives undefined +function if_partial_post_init(b) { + var x:number; + if (b) { + x = 0; + } + var y:number = x; // error, possibly uninitialized +} + +// use of var after guaranteed init (exhaustive if) is ok +function if_post_init(b) { + var x:number; + if (b) { + x = 0; + } else { + x = 1; + } + var y:number = x; +} + +// use of var after partial init (non-exhaustive switch) gives undefined +function switch_partial_post_init(i) { + var x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + } + var y:number = x; // error, possibly uninitialized +} + +// use of var after guaranteed init (exhaustive switch) is ok +function switch_post_init(i) { + var x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + default: + x = 2; + } + var y:number = x; // no error, all cases covered +} + +// local use of annotated var in switch is ok +function switch_scoped_init_1(i) { + switch (i) { + case 0: + var x:number = 0; + var y:number = x; + } +} + +// ...but use of var before switch gives undefined +function switch_scoped_init_2(i) { + var y:number = x; // error + switch (i) { + case 0: + var x:number = 0; + } +} + +// ...and after +function switch_scoped_init_3(i) { + switch (i) { + case 0: + var x:number = 0; + } + var y:number = x; // error +} + +// ...and in a fallthrough case without initialization +function switch_scoped_init_4(i) { + switch (i) { + case 0: + var x:number = 0; + case 1: + var y:number = x; // error + } +} + +// local use of annotated var in while is ok +function while_scoped_init(b) { + while (b) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use of var before while gives undefined +function while_pre_init(b) { + var y:number = x; // error + while (b) { + var x:number = 0; + } +} + +// ...and after +function while_post_init(b) { + while (b) { + var x:number = 0; + } + var y:number = x; // error +} + +// local use of annotated var in do-while is ok +function do_while_scoped_init(b) { + do { + var x:number = 0; + var y:number = x; + } while (b); +} + +// ...but use before do-while gives undefined +function do_while_pre_init(b) { + var y:number = x; // error + do { + var x:number = 0; + } while (b); +} + +// after is ok, because loop is guaranteed to run +function do_while_post_init(b) { + do { + var x:number = 0; + } while (b); + var y:number = x; +} + +// local use of annotated var in for is ok +function for_scoped_init(b) { + for (;b;) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use before for gives undefined +function for_pre_init(b) { + var y:number = x; // error + for (;b;) { + var x:number = 0; + } +} + +// ...and after +function for_post_init(b) { + for (;b;) { + var x:number = 0; + } + var y:number = x; // error +} + +// local use of annotated var in for-in is ok +function for_in_scoped_init() { + for (var p in { a:1, b: 2 }) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use before while gives undefined +function for_in_pre_init() { + var y:number = x; // error + for (var p in { a:1, b: 2 }) { + var x:number = 0; + } +} + +// ...and after +function for_in_post_init() { + for (var p in { a:1, b: 2 }) { + var x:number = 0; + } + var y:number = x; // error +} + +// local use of annotated var in for-of is ok +function for_of_scoped_init() { + for (var x of [1, 2, 3]) { + var x:number = 0; + var y:number = x; + } +} + +// ...but use before while gives undefined +function for_in_pre_init() { + var y:number = x; // error + for (var x of [1, 2, 3]) { + var x:number = 0; + } +} + +// ...and after +function for_in_post_init() { + for (var x of [1, 2, 3]) { + var x:number = 0; + } + var y:number = x; // error +} diff --git a/tests/init/jsfmt.spec.js b/tests/init/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/init/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/init/let.js b/tests/init/let.js new file mode 100644 index 000000000000..f35e25f95fe9 --- /dev/null +++ b/tests/init/let.js @@ -0,0 +1,157 @@ +/** + * test initialization tracking for lets + * @flow + */ + +// deferred init on annotated lets is ok +function linear_deferred_init() { + let x:number; + x = 0; + let y:number = x; +} + +// use of let before init gives undefined +function linear_pre_init() { + let x:number; + let y:?number = x; // ok + let z:number = x; // error + x = 0; + let w:number = x; // ok +} + +// self-references in let bindings are not ok +function self_init() { + let x = x; // 'x' not initialized! +} + +// use of let after partial init (non-exhaustive if) gives undefined +function if_partial_post_init(b) { + let x:number; + if (b) { + x = 0; + } + var y:number = x; // error, possibly uninitialized +} + +// use of let after guaranteed init (exhaustive if) is ok +function if_post_init(b) { + let x:number; + if (b) { + x = 0; + } else { + x = 1; + } + var y:number = x; +} + +// use of let after partial init (non-exhaustive switch) gives undefined +function switch_partial_post_init(i) { + let x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + } + var y:number = x; // error, possibly uninitialized +} + +// use of let after guaranteed init (exhaustive switch) is ok +function switch_post_init(i) { + let x:number; + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + default: + x = 2; + } + var y:number = x; // no error, all cases covered +} + +// use in a switch after a skipped decl is an error +function switch_scoped_init_2(i) { + switch (i) { + case 0: + let x:number; + case 1: + let y:number = x; // error, skipped declaration + } +} + +// while leaves it possibly uninitialized +function while_post_init(b) { + let x:number; + while (b) { + x = 0; + } + var y:number = x; // error +} + +// do-while is ok, because loop is guaranteed to run at least once +function do_while_post_init(b) { + let x:number; + do { + x = 0; + } while (b); + var y:number = x; // ok +} + +// for-in leaves it possibly uninitialized +function for_in_post_init() { + var x:number; + for (var p in {}) { + x = 0; + } + var y:number = x; // error +} + +// for-of leaves it possibly uninitialized +function for_of_post_init() { + var x:number; + for (var x of []) { + x = 0; + } + var y:number = x; // error +} + +// use of let after guaranteed init (exhaustive switch + throw) is ok +function switch_post_init2(i): number { + let bar; + switch (i) { + case 1: + bar = 3; + break; + default: + throw new Error('Invalid state'); + } + return bar; // ok, definitely initialized +} + +// use of let after guaranteed init (exhaustive switch + throw) is ok +function switch_post_init2(i): number { + let bar; + switch (i) { + case 1: + bar = 3; + break; + default: + throw new Error('Invalid state'); + } + return bar; // ok, definitely initialized +} + +// reference of a let-binding is permitted in a sub-closure within the init expr +function sub_closure_init_reference() { + let x = function() { return x; }; + const y = function() { return y; }; + + // var-bindings can reference each other cyclically since they do not incur a + // TDZ (...even though this is weird...) + var z = z; +} diff --git a/tests/init/nullable-init.js b/tests/init/nullable-init.js new file mode 100644 index 000000000000..c5d32d0138a1 --- /dev/null +++ b/tests/init/nullable-init.js @@ -0,0 +1,2 @@ +var o: {x: ?number} = { x: null }; +var a: Array = [null,null]; diff --git a/tests/instanceof/__snapshots__/jsfmt.spec.js.snap b/tests/instanceof/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..48d9d5f61ccc --- /dev/null +++ b/tests/instanceof/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,106 @@ +exports[`test instanceof.js 1`] = ` +"/* @flow */ + +// x instancof t +class X1 { foo: number; }; +class X2 { foo: string; }; + +function x(b) { return b ? new X1 : new X2; } + +function consumer1(b) { + var g = x(b); + if (g instanceof X2) g.foo = \'1337\'; + else g.foo = 1337; +} + +function consumer2(b) { + var g = x(b); + if (g instanceof X1) g.foo = \'1337\'; // oops +} + +// x.y instanceof t +class Y1 { bar: X1; }; +class Y2 { bar: X2; }; + +function y(b) { return b ? new Y1 : new Y2; } + +function consumer3(b) { + var g = y(b); + if (g.bar instanceof X2) g.bar.foo = \'1337\'; + else g.bar.foo = 1337; +} + +function consumer4(b) { + var g = y(b); + if (g.bar instanceof X1) g.bar.foo = \'1337\'; // oops +} + +// x.y.z instance of t +class Z1 { baz: Y1; }; +class Z2 { baz: Y2; }; + +function z(b) { return b ? new Z1 : new Z2; } + +function consumer5(b) { + var g = z(b); + if (g.baz.bar instanceof X2) g.baz.bar.foo = \'1337\'; + else g.baz.bar.foo = 1337; +} + +function consumer6(b) { + var g = z(b); + if (g.baz.bar instanceof X1) g.baz.bar.foo = \'1337\'; // oops +} + +// this instanceof t +class C { + m() { + if (this instanceof D) + alert(this.s); + else + alert(\"nope\"); + } +} + +class D extends C { + s: string; + constructor() { + super(); + this.s = \"yup\"; + } +} + + +function foo0(x: Array | number) { + if (x instanceof Array) { + x[0] = 123; + } else { + x++; + } +} + +function foo1(x: Array | number) { + if (x instanceof Array) { + x++; // error + } else { + x[0] = 123; // error + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/instanceof/instanceof.js b/tests/instanceof/instanceof.js new file mode 100644 index 000000000000..bcbe7f6b8dc8 --- /dev/null +++ b/tests/instanceof/instanceof.js @@ -0,0 +1,87 @@ +/* @flow */ + +// x instancof t +class X1 { foo: number; }; +class X2 { foo: string; }; + +function x(b) { return b ? new X1 : new X2; } + +function consumer1(b) { + var g = x(b); + if (g instanceof X2) g.foo = '1337'; + else g.foo = 1337; +} + +function consumer2(b) { + var g = x(b); + if (g instanceof X1) g.foo = '1337'; // oops +} + +// x.y instanceof t +class Y1 { bar: X1; }; +class Y2 { bar: X2; }; + +function y(b) { return b ? new Y1 : new Y2; } + +function consumer3(b) { + var g = y(b); + if (g.bar instanceof X2) g.bar.foo = '1337'; + else g.bar.foo = 1337; +} + +function consumer4(b) { + var g = y(b); + if (g.bar instanceof X1) g.bar.foo = '1337'; // oops +} + +// x.y.z instance of t +class Z1 { baz: Y1; }; +class Z2 { baz: Y2; }; + +function z(b) { return b ? new Z1 : new Z2; } + +function consumer5(b) { + var g = z(b); + if (g.baz.bar instanceof X2) g.baz.bar.foo = '1337'; + else g.baz.bar.foo = 1337; +} + +function consumer6(b) { + var g = z(b); + if (g.baz.bar instanceof X1) g.baz.bar.foo = '1337'; // oops +} + +// this instanceof t +class C { + m() { + if (this instanceof D) + alert(this.s); + else + alert("nope"); + } +} + +class D extends C { + s: string; + constructor() { + super(); + this.s = "yup"; + } +} + + +function foo0(x: Array | number) { + if (x instanceof Array) { + x[0] = 123; + } else { + x++; + } +} + +function foo1(x: Array | number) { + if (x instanceof Array) { + x++; // error + } else { + x[0] = 123; // error + } +} diff --git a/tests/instanceof/jsfmt.spec.js b/tests/instanceof/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/instanceof/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/integration/__snapshots__/jsfmt.spec.js.snap b/tests/integration/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4ca888585bc7 --- /dev/null +++ b/tests/integration/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test bar.js 1`] = ` +"// @flow +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test foo.js 1`] = ` +"// @flow +require('./bar'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +require("./bar"); + +" +`; diff --git a/tests/integration/bar.js b/tests/integration/bar.js new file mode 100644 index 000000000000..46e7f7c04567 --- /dev/null +++ b/tests/integration/bar.js @@ -0,0 +1 @@ +// @flow diff --git a/tests/integration/foo.js b/tests/integration/foo.js new file mode 100644 index 000000000000..69089d4e9298 --- /dev/null +++ b/tests/integration/foo.js @@ -0,0 +1,2 @@ +// @flow +require('./bar'); diff --git a/tests/integration/jsfmt.spec.js b/tests/integration/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/integration/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/interface/__snapshots__/jsfmt.spec.js.snap b/tests/interface/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b612ebc1a585 --- /dev/null +++ b/tests/interface/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,211 @@ +exports[`test import.js 1`] = ` +"interface I { x: number } +export type J = I; // workaround for export interface +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test indexer.js 1`] = ` +"// @flow + +interface Ok { + [key: string]: string; +} + +interface Bad { + [k1: string]: string; + [k2: number]: number; // error: not supported (yet) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test interface.js 1`] = ` +"declare class C { x: number; } + +var x: string = new C().x; + +interface I { x: number; } + +var i = new I(); // error + +function testInterfaceName(o: I) { + (o.name: string); // error, name is static + (o.constructor.name: string); // ok +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test test.js 1`] = ` +"interface I { y: string } +interface I_ { x: number } +interface J extends I, I_ { } +interface K extends J { } + +var k: K = { x: \"\", y: \"\" }; // error: x should be number +(k.x: string); // error: x is number +(k.y: string); + +declare class C { x: number } +declare class D extends C, Other { } // error: multiple extends +//declare class E implements I { } // parse error + +interface A { y: Y } +interface A_ { x: X } +interface B extends A, A_ { z: Z } +interface E extends B { } + +var e: E = { x: \"\", y: \"\", z: \"\" }; // error: x and z should be numbers +(e.x: string); // error: x is number +(e.y: string); +(e.z: string); // error: z is number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test test2.js 1`] = ` +"import type { J } from \'./import\'; +interface K { } +interface L extends J, K { y: string } + +function foo(l: L) { l.x; l.y; l.z; } // error: z not found in L + +// interface + multiple inheritance is similar to object type + intersection +type M = { y: string } & J & { z: boolean } + +function bar(m: M) { m.x; m.y; m.z; } // OK +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test test3.js 1`] = ` +"interface I { x: number, y : string } +interface J { y : number } +interface K extends I, J { x: string } // error: x is number in I +function foo(k: K) { + (k.x: number); // error: x is string in K + (k.y: number); // error: y is string in I +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test test4.js 1`] = ` +"interface I { foo(x: number): void; } +(function foo(x: number) { }: I); // error, property \`foo\` not found function + +declare class C { + bar(i: I): void; + bar(f: (x: number) => void): void; +} + +new C().bar((x: string) => { }); // error, number ~/~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; diff --git a/tests/interface/import.js b/tests/interface/import.js new file mode 100644 index 000000000000..1eba66eac7cb --- /dev/null +++ b/tests/interface/import.js @@ -0,0 +1,2 @@ +interface I { x: number } +export type J = I; // workaround for export interface diff --git a/tests/interface/indexer.js b/tests/interface/indexer.js new file mode 100644 index 000000000000..57d9204eabc5 --- /dev/null +++ b/tests/interface/indexer.js @@ -0,0 +1,10 @@ +// @flow + +interface Ok { + [key: string]: string; +} + +interface Bad { + [k1: string]: string; + [k2: number]: number; // error: not supported (yet) +} diff --git a/tests/interface/interface.js b/tests/interface/interface.js new file mode 100644 index 000000000000..40a01e3d02bd --- /dev/null +++ b/tests/interface/interface.js @@ -0,0 +1,12 @@ +declare class C { x: number; } + +var x: string = new C().x; + +interface I { x: number; } + +var i = new I(); // error + +function testInterfaceName(o: I) { + (o.name: string); // error, name is static + (o.constructor.name: string); // ok +} diff --git a/tests/interface/jsfmt.spec.js b/tests/interface/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/interface/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/interface/test.js b/tests/interface/test.js new file mode 100644 index 000000000000..1b071ece569f --- /dev/null +++ b/tests/interface/test.js @@ -0,0 +1,22 @@ +interface I { y: string } +interface I_ { x: number } +interface J extends I, I_ { } +interface K extends J { } + +var k: K = { x: "", y: "" }; // error: x should be number +(k.x: string); // error: x is number +(k.y: string); + +declare class C { x: number } +declare class D extends C, Other { } // error: multiple extends +//declare class E implements I { } // parse error + +interface A { y: Y } +interface A_ { x: X } +interface B extends A, A_ { z: Z } +interface E extends B { } + +var e: E = { x: "", y: "", z: "" }; // error: x and z should be numbers +(e.x: string); // error: x is number +(e.y: string); +(e.z: string); // error: z is number diff --git a/tests/interface/test2.js b/tests/interface/test2.js new file mode 100644 index 000000000000..0ef83b294e2e --- /dev/null +++ b/tests/interface/test2.js @@ -0,0 +1,10 @@ +import type { J } from './import'; +interface K { } +interface L extends J, K { y: string } + +function foo(l: L) { l.x; l.y; l.z; } // error: z not found in L + +// interface + multiple inheritance is similar to object type + intersection +type M = { y: string } & J & { z: boolean } + +function bar(m: M) { m.x; m.y; m.z; } // OK diff --git a/tests/interface/test3.js b/tests/interface/test3.js new file mode 100644 index 000000000000..a06a374a1dd9 --- /dev/null +++ b/tests/interface/test3.js @@ -0,0 +1,7 @@ +interface I { x: number, y : string } +interface J { y : number } +interface K extends I, J { x: string } // error: x is number in I +function foo(k: K) { + (k.x: number); // error: x is string in K + (k.y: number); // error: y is string in I +} diff --git a/tests/interface/test4.js b/tests/interface/test4.js new file mode 100644 index 000000000000..91246524d72a --- /dev/null +++ b/tests/interface/test4.js @@ -0,0 +1,9 @@ +interface I { foo(x: number): void; } +(function foo(x: number) { }: I); // error, property `foo` not found function + +declare class C { + bar(i: I): void; + bar(f: (x: number) => void): void; +} + +new C().bar((x: string) => { }); // error, number ~/~> string diff --git a/tests/intersection/__snapshots__/jsfmt.spec.js.snap b/tests/intersection/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..97de30df4f01 --- /dev/null +++ b/tests/intersection/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,207 @@ +exports[`test intersection.js 1`] = ` +"function foo(x: $All): number { + return x.type; +} + +function bar(x: Error & {type:number}): number { + return x.type; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test objassign.js 1`] = ` +"/** + * Test intersection of objects flowing to spread assignment. + * + * Definitions in lib/lib.js + * + * @noflow + */ + +declare var x: ObjAssignT; + +let y: ObjAssignT = { ...x }; // should be fine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Test intersection of objects flowing to spread assignment. + * + * Definitions in lib/lib.js + * + * @noflow + */ +declare var x: ObjAssignT; +let y: ObjAssignT = { ...x };// should be fine + +" +`; + +exports[`test pred.js 1`] = ` +"/** + * Test interaction of object intersections and predicates. + * Definitions in lib/lib.js + * + * @flow + */ + +type DuplexStreamOptions = ReadableStreamOptions & WritableStreamOptions & { + allowHalfOpen? : boolean, + readableObjectMode? : boolean, + writableObjectMode? : boolean +}; + +function hasObjectMode_bad(options: DuplexStreamOptions): boolean { + return options.objectMode + || options.readableObjectMode + || options.writableObjectMode; // error, undefined ~> boolean +} + +function hasObjectMode_ok(options: DuplexStreamOptions): boolean { + return !!(options.objectMode + || options.readableObjectMode + || options.writableObjectMode); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test_fun.js 1`] = ` +"/** + * Tests for intersections of function types. + * + * Note: Flow abuses intersection types to model + * function overloading, which precludes using a + * correct intersection of return types in the result. + * + * Here we test the special case where return types + * are equal. Tests of the overloading behavior can + * be found in tests/overload + * + * Definitions lin lib/lib.js + * + * @noflow + */ + +// intersection of function types satisfies union of param types + +type F = (_: ObjA) => void; +type G = (_: ObjB) => void; +type FG = (_: ObjA | ObjB) => void; + +declare var fun1 : F & G; + +(fun1 : FG); + +var fun2 : FG = fun1; + +// simpler variation +declare var f : ((_: number) => void) & ((_: string) => void); +var g: (_: number | string) => void = f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test_obj.js 1`] = ` +"/** + * Tests for intersections of object types + * + * @noflow + */ + +// TODO we should give explicit errors for incompatibilities +// which make an intersection uninhabitable: +// - shared mutable properties with different types +// - different dictionary types +// +// Currently we give no such errors. Instead, we rely on +// the impossibility of providing a value for such a type +// to produce errors on value inflows. This is clearly +// suboptimal, since eg declared vars require no explicit +// provision of values. This leaves the impossible types +// free to flow downstream and satisfy impossible constraints. + +// intersection of object types satisfies union of properties +declare var a: A; +var b: B = a; + +// intersection of dictionary types: +declare var c: C; +var d: D = c; // ok + +// dict type mismatch +type E = { [key: string]: string }; +var e: E = c; // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Tests for intersections of object types + * + * @noflow + */ +// TODO we should give explicit errors for incompatibilities +// which make an intersection uninhabitable: +// - shared mutable properties with different types +// - different dictionary types +// +// Currently we give no such errors. Instead, we rely on +// the impossibility of providing a value for such a type +// to produce errors on value inflows. This is clearly +// suboptimal, since eg declared vars require no explicit +// provision of values. This leaves the impossible types +// free to flow downstream and satisfy impossible constraints. +// intersection of object types satisfies union of properties +declare var a: A; +var b: B = a; +// intersection of dictionary types: +declare var c: C; +var d: D = c;// ok +// dict type mismatch +type E = { [key: string]: string }; +var e: E = c;// error + +" +`; diff --git a/tests/intersection/intersection.js b/tests/intersection/intersection.js new file mode 100644 index 000000000000..7508926e5902 --- /dev/null +++ b/tests/intersection/intersection.js @@ -0,0 +1,7 @@ +function foo(x: $All): number { + return x.type; +} + +function bar(x: Error & {type:number}): number { + return x.type; +} diff --git a/tests/intersection/jsfmt.spec.js b/tests/intersection/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/intersection/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/intersection/lib/__snapshots__/jsfmt.spec.js.snap b/tests/intersection/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..17c299687982 --- /dev/null +++ b/tests/intersection/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,53 @@ +exports[`test lib.js 1`] = ` +"// @flow + +// defs used in tests, here to stress tvar machinery + +// used in ObjAssign.js +// +type ObjAssignT = { foo: string } & { bar: string }; + +// used in pred.js +// +type ReadableStreamOptions = { + highWaterMark? : number, + encoding? : ?string, + objectMode? : boolean +}; + +type WritableStreamOptions = { + highWaterMark? : number, + decodeString? : boolean, + objectMode? : boolean +}; + +// used in test_fun.js +// +type ObjA = { foo: number, bar: string }; +type ObjB = { baz: bool }; + +// used in test_obj.js +// +type A = { a: string } & { b: string }; +type B = { a: string, b: string }; + +type C = { [key: string]: number } & { [key: string]: number }; +type D = { [key: string]: number }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/intersection/lib/jsfmt.spec.js b/tests/intersection/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/intersection/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/intersection/lib/lib.js b/tests/intersection/lib/lib.js new file mode 100644 index 000000000000..df9d7d3f207e --- /dev/null +++ b/tests/intersection/lib/lib.js @@ -0,0 +1,34 @@ +// @flow + +// defs used in tests, here to stress tvar machinery + +// used in ObjAssign.js +// +type ObjAssignT = { foo: string } & { bar: string }; + +// used in pred.js +// +type ReadableStreamOptions = { + highWaterMark? : number, + encoding? : ?string, + objectMode? : boolean +}; + +type WritableStreamOptions = { + highWaterMark? : number, + decodeString? : boolean, + objectMode? : boolean +}; + +// used in test_fun.js +// +type ObjA = { foo: number, bar: string }; +type ObjB = { baz: bool }; + +// used in test_obj.js +// +type A = { a: string } & { b: string }; +type B = { a: string, b: string }; + +type C = { [key: string]: number } & { [key: string]: number }; +type D = { [key: string]: number }; diff --git a/tests/intersection/objassign.js b/tests/intersection/objassign.js new file mode 100644 index 000000000000..fc0436123c65 --- /dev/null +++ b/tests/intersection/objassign.js @@ -0,0 +1,11 @@ +/** + * Test intersection of objects flowing to spread assignment. + * + * Definitions in lib/lib.js + * + * @noflow + */ + +declare var x: ObjAssignT; + +let y: ObjAssignT = { ...x }; // should be fine diff --git a/tests/intersection/pred.js b/tests/intersection/pred.js new file mode 100644 index 000000000000..37a0d13beadf --- /dev/null +++ b/tests/intersection/pred.js @@ -0,0 +1,24 @@ +/** + * Test interaction of object intersections and predicates. + * Definitions in lib/lib.js + * + * @flow + */ + +type DuplexStreamOptions = ReadableStreamOptions & WritableStreamOptions & { + allowHalfOpen? : boolean, + readableObjectMode? : boolean, + writableObjectMode? : boolean +}; + +function hasObjectMode_bad(options: DuplexStreamOptions): boolean { + return options.objectMode + || options.readableObjectMode + || options.writableObjectMode; // error, undefined ~> boolean +} + +function hasObjectMode_ok(options: DuplexStreamOptions): boolean { + return !!(options.objectMode + || options.readableObjectMode + || options.writableObjectMode); +} diff --git a/tests/intersection/test_fun.js b/tests/intersection/test_fun.js new file mode 100644 index 000000000000..b9b2f81074bb --- /dev/null +++ b/tests/intersection/test_fun.js @@ -0,0 +1,31 @@ +/** + * Tests for intersections of function types. + * + * Note: Flow abuses intersection types to model + * function overloading, which precludes using a + * correct intersection of return types in the result. + * + * Here we test the special case where return types + * are equal. Tests of the overloading behavior can + * be found in tests/overload + * + * Definitions lin lib/lib.js + * + * @noflow + */ + +// intersection of function types satisfies union of param types + +type F = (_: ObjA) => void; +type G = (_: ObjB) => void; +type FG = (_: ObjA | ObjB) => void; + +declare var fun1 : F & G; + +(fun1 : FG); + +var fun2 : FG = fun1; + +// simpler variation +declare var f : ((_: number) => void) & ((_: string) => void); +var g: (_: number | string) => void = f; diff --git a/tests/intersection/test_obj.js b/tests/intersection/test_obj.js new file mode 100644 index 000000000000..6817584708ab --- /dev/null +++ b/tests/intersection/test_obj.js @@ -0,0 +1,29 @@ +/** + * Tests for intersections of object types + * + * @noflow + */ + +// TODO we should give explicit errors for incompatibilities +// which make an intersection uninhabitable: +// - shared mutable properties with different types +// - different dictionary types +// +// Currently we give no such errors. Instead, we rely on +// the impossibility of providing a value for such a type +// to produce errors on value inflows. This is clearly +// suboptimal, since eg declared vars require no explicit +// provision of values. This leaves the impossible types +// free to flow downstream and satisfy impossible constraints. + +// intersection of object types satisfies union of properties +declare var a: A; +var b: B = a; + +// intersection of dictionary types: +declare var c: C; +var d: D = c; // ok + +// dict type mismatch +type E = { [key: string]: string }; +var e: E = c; // error diff --git a/tests/issues-11/__snapshots__/jsfmt.spec.js.snap b/tests/issues-11/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b9b2b0a3fefb --- /dev/null +++ b/tests/issues-11/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test export.js 1`] = ` +"/* @flow */ +exports.x = 1; +exports.y = ""; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +exports.x = 1; +exports.y = ""; + +" +`; + +exports[`test import.js 1`] = ` +"/* @flow */ +var e = require('./export'); +var x: string = e.x; +var y: number = e.y; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var e = require("./export"); +var x: string = e.x; +var y: number = e.y; + +" +`; diff --git a/tests/issues-11/export.js b/tests/issues-11/export.js new file mode 100644 index 000000000000..0fe9283762c9 --- /dev/null +++ b/tests/issues-11/export.js @@ -0,0 +1,3 @@ +/* @flow */ +exports.x = 1; +exports.y = ""; diff --git a/tests/issues-11/import.js b/tests/issues-11/import.js new file mode 100644 index 000000000000..11d913911e42 --- /dev/null +++ b/tests/issues-11/import.js @@ -0,0 +1,4 @@ +/* @flow */ +var e = require('./export'); +var x: string = e.x; +var y: number = e.y; diff --git a/tests/issues-11/jsfmt.spec.js b/tests/issues-11/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/issues-11/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/iter/__snapshots__/jsfmt.spec.js.snap b/tests/iter/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0695d0d737bb --- /dev/null +++ b/tests/iter/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,73 @@ +exports[`test iter.js 1`] = ` +"var a = [true,false]; +function foo(x) { } + +for (var i=0;i<3;i++) { + foo(a[i]); +} +for (var k in a) { + foo(a[k]); // k is a string, which shouldn't be used for array access +} + +var b = (null : ?{[key: string]: string}); +for (var j in b) { + foo(b[j]); +} + +var c; +for (var m in (c = b)) { + foo(c[m]); +} + +var d; +for (var n in (d = a)) { + foo(d[n]); // d is a string, which shouldn't be used for array access +} + +for (var x in undefined) { + foo(x); // unreachable +} + +for (var x in null) { + foo(x); // unreachable +} + +for (var y in this) { + // regression test to make sure \`in this\` doesn't fatal. it's currently + // allowed, even though we can't actually enumerate all the keys on \`this\`. +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a = [ true, false ]; +function foo(x) { + +} +for (var i = 0; i < 3; i++) { + foo(a[i]); +} +for (var k in a) { + foo(a[k]);// k is a string, which shouldn't be used for array access +} +var b = (null: ?{ [key: string]: string }); +for (var j in b) { + foo(b[j]); +} +var c; +for (var m in c = b) { + foo(c[m]); +} +var d; +for (var n in d = a) { + foo(d[n]);// d is a string, which shouldn't be used for array access +} +for (var x in undefined) { + foo(x);// unreachable +} +for (var x in null) { + foo(x);// unreachable +} +for (var y in this) { + +} + +" +`; diff --git a/tests/iter/iter.js b/tests/iter/iter.js new file mode 100644 index 000000000000..62241fd8edcc --- /dev/null +++ b/tests/iter/iter.js @@ -0,0 +1,37 @@ +var a = [true,false]; +function foo(x) { } + +for (var i=0;i<3;i++) { + foo(a[i]); +} +for (var k in a) { + foo(a[k]); // k is a string, which shouldn't be used for array access +} + +var b = (null : ?{[key: string]: string}); +for (var j in b) { + foo(b[j]); +} + +var c; +for (var m in (c = b)) { + foo(c[m]); +} + +var d; +for (var n in (d = a)) { + foo(d[n]); // d is a string, which shouldn't be used for array access +} + +for (var x in undefined) { + foo(x); // unreachable +} + +for (var x in null) { + foo(x); // unreachable +} + +for (var y in this) { + // regression test to make sure `in this` doesn't fatal. it's currently + // allowed, even though we can't actually enumerate all the keys on `this`. +} diff --git a/tests/iter/jsfmt.spec.js b/tests/iter/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/iter/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/iterable/__snapshots__/jsfmt.spec.js.snap b/tests/iterable/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c0ec883c959b --- /dev/null +++ b/tests/iterable/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,270 @@ +exports[`test array.js 1`] = ` +"/* @flow */ + +var arrayTest1: Iterable = ([1, 2]: Array); +var arrayTest2: Iterable = [1,2,\"hi\"]; +var arrayTest3: Iterable<*> = [1,2,3]; + +// Error string ~> number +var arrayTest4: Iterable = [\"hi\"]; +// Error string ~> number +var arrayTest5: Iterable = [\"hi\", 1]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test caching_bug.js 1`] = ` +"/* @flow */ + +/** + * I\'ve hit a bug with the caching in flow_js.ml. Avik is removing that caching + * so it should be fixed soon. The basic idea is I flow something like + * + * Array ~> Iterable + * + * then Flow won\'t notice when I try to flow + * + * Array ~> Iterable + * + * We shouldn\'t hit the cache because the union types are different, but we do + * anyway. I\'ve fixed this temporarily by bumping the \"meaningful\" param to + * Hashtbl.hash_param + */ + +function fill_the_cache(x: Array): Iterable { return x; } + +// Error: number ~> string +function miss_the_cache(x: Array): Iterable { return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test iter.js 1`] = ` +"/* @flow */ + +function foo(strs: Iterable): void { + for (var s: string of strs) { + console.log(s); + } +} + +var m: Map = new Map(); + +foo(m.keys()); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test iterator_result.js 1`] = ` +"/* @flow */ + +function makeIterator(coin_flip: () => boolean ): Iterator { + return { + \"@@iterator\"() { return makeIterator(coin_flip); }, + next(): IteratorResult { + var done = coin_flip(); + if (!done) { + return { done, value: \"still going...\" }; + } else { + return { done }; + } + } + } +} + +function makeIterator(coin_flip: () => boolean ): Iterator { + return { + \"@@iterator\"() { return makeIterator(coin_flip); }, + next(): IteratorResult { + var done = coin_flip(); + if (done) { // Whoops, made a mistake and forgot to negate done + return { done, value: \"still going...\" }; // Error string ~> void + } else { + return { done }; // Error void ~> string + } + } + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test map.js 1`] = ` +"/* @flow */ + +function mapTest1(map: Map): Iterable<[string, number]> { + return map; +} +function mapTest2(map: Map): Iterable<[K, V]> { + return map; +}; +function mapTest3(map: Map): Iterable<*> { + return map; +} +// Error - Map is an Iterable<[K, V]> +function mapTest4(map: Map): Iterable { + return map; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test set.js 1`] = ` +"/* @flow */ + +function setTest1(set: Set): Iterable { + return set; +} +function setTest2(set: Set): Iterable { + return set; +}; +function setTest3(set: Set): Iterable<*> { + return set; +} +// Error string ~> number +function setTest4(set: Set): Iterable { + return set; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test string.js 1`] = ` +"/* @flow */ + +var stringTest1: Iterable = \"hi\"; +var stringTest3: Iterable<*> = \"hi\"; +var stringTest3: Iterable = \"hi\"; // Error - string is a Iterable +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test variance.js 1`] = ` +"/* @flow */ + +(([]: Array): Iterable); // ok, Iterable<+T> + +(([]: Array).values(): Iterable); // ok, Iterator<+T> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/iterable/array.js b/tests/iterable/array.js new file mode 100644 index 000000000000..c50c20f9352e --- /dev/null +++ b/tests/iterable/array.js @@ -0,0 +1,10 @@ +/* @flow */ + +var arrayTest1: Iterable = ([1, 2]: Array); +var arrayTest2: Iterable = [1,2,"hi"]; +var arrayTest3: Iterable<*> = [1,2,3]; + +// Error string ~> number +var arrayTest4: Iterable = ["hi"]; +// Error string ~> number +var arrayTest5: Iterable = ["hi", 1]; diff --git a/tests/iterable/caching_bug.js b/tests/iterable/caching_bug.js new file mode 100644 index 000000000000..6fffea9f95bb --- /dev/null +++ b/tests/iterable/caching_bug.js @@ -0,0 +1,21 @@ +/* @flow */ + +/** + * I've hit a bug with the caching in flow_js.ml. Avik is removing that caching + * so it should be fixed soon. The basic idea is I flow something like + * + * Array ~> Iterable + * + * then Flow won't notice when I try to flow + * + * Array ~> Iterable + * + * We shouldn't hit the cache because the union types are different, but we do + * anyway. I've fixed this temporarily by bumping the "meaningful" param to + * Hashtbl.hash_param + */ + +function fill_the_cache(x: Array): Iterable { return x; } + +// Error: number ~> string +function miss_the_cache(x: Array): Iterable { return x; } diff --git a/tests/iterable/iter.js b/tests/iterable/iter.js new file mode 100644 index 000000000000..b8c3d9cf1d9d --- /dev/null +++ b/tests/iterable/iter.js @@ -0,0 +1,11 @@ +/* @flow */ + +function foo(strs: Iterable): void { + for (var s: string of strs) { + console.log(s); + } +} + +var m: Map = new Map(); + +foo(m.keys()); diff --git a/tests/iterable/iterator_result.js b/tests/iterable/iterator_result.js new file mode 100644 index 000000000000..cb0b0b162c21 --- /dev/null +++ b/tests/iterable/iterator_result.js @@ -0,0 +1,29 @@ +/* @flow */ + +function makeIterator(coin_flip: () => boolean ): Iterator { + return { + "@@iterator"() { return makeIterator(coin_flip); }, + next(): IteratorResult { + var done = coin_flip(); + if (!done) { + return { done, value: "still going..." }; + } else { + return { done }; + } + } + } +} + +function makeIterator(coin_flip: () => boolean ): Iterator { + return { + "@@iterator"() { return makeIterator(coin_flip); }, + next(): IteratorResult { + var done = coin_flip(); + if (done) { // Whoops, made a mistake and forgot to negate done + return { done, value: "still going..." }; // Error string ~> void + } else { + return { done }; // Error void ~> string + } + } + } +} diff --git a/tests/iterable/jsfmt.spec.js b/tests/iterable/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/iterable/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/iterable/map.js b/tests/iterable/map.js new file mode 100644 index 000000000000..8125f7abf5c3 --- /dev/null +++ b/tests/iterable/map.js @@ -0,0 +1,15 @@ +/* @flow */ + +function mapTest1(map: Map): Iterable<[string, number]> { + return map; +} +function mapTest2(map: Map): Iterable<[K, V]> { + return map; +}; +function mapTest3(map: Map): Iterable<*> { + return map; +} +// Error - Map is an Iterable<[K, V]> +function mapTest4(map: Map): Iterable { + return map; +} diff --git a/tests/iterable/set.js b/tests/iterable/set.js new file mode 100644 index 000000000000..2251e52924e7 --- /dev/null +++ b/tests/iterable/set.js @@ -0,0 +1,15 @@ +/* @flow */ + +function setTest1(set: Set): Iterable { + return set; +} +function setTest2(set: Set): Iterable { + return set; +}; +function setTest3(set: Set): Iterable<*> { + return set; +} +// Error string ~> number +function setTest4(set: Set): Iterable { + return set; +} diff --git a/tests/iterable/string.js b/tests/iterable/string.js new file mode 100644 index 000000000000..bae6cec8e657 --- /dev/null +++ b/tests/iterable/string.js @@ -0,0 +1,5 @@ +/* @flow */ + +var stringTest1: Iterable = "hi"; +var stringTest3: Iterable<*> = "hi"; +var stringTest3: Iterable = "hi"; // Error - string is a Iterable diff --git a/tests/iterable/variance.js b/tests/iterable/variance.js new file mode 100644 index 000000000000..634c41db3c9f --- /dev/null +++ b/tests/iterable/variance.js @@ -0,0 +1,5 @@ +/* @flow */ + +(([]: Array): Iterable); // ok, Iterable<+T> + +(([]: Array).values(): Iterable); // ok, Iterator<+T> diff --git a/tests/jsx_intrinsics.builtin/__snapshots__/jsfmt.spec.js.snap b/tests/jsx_intrinsics.builtin/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..28d087d9ab26 --- /dev/null +++ b/tests/jsx_intrinsics.builtin/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,76 @@ +exports[`test main.js 1`] = ` +"// @flow + +var React = require(\'react\'); + +class CustomComponent extends React.Component { + props: { + prop: string + }; +} + +var a: React.Element<{prop: string}> = ; +var b: React.Element<{prop1: string}> = ; // Error: Props<{prop}> ~> Props<{prop1}> + +// Since intrinsics are typed as \`any\` out of the box, we can pass any +// attributes to intrinsics! +var c: React.Element =
; +// However, we don\'t allow such elements to be viewed as React elements with +// different attributes. +var d: React.Element<{doesntmatch: string}> =
; +// No error as long as expectations are consistent, though. +var e: React.Element<{not_a_real_attr: string}> =
; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test strings.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); + +// The builtin $JSXIntrinsics should allow any string + +var Div = \'div\'; +var Bad = \'bad\'; +var Str: string = \'str\'; + +
; // This is fine +; // This is fine +; // This is fine + +React.createElement(\'div\', {}); // This is fine +React.createElement(\'bad\', {}); // This is fine + +
; // This is fine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +// The builtin $JSXIntrinsics should allow any string +var Div = \"div\"; +var Bad = \"bad\"; +var Str: string = \"str\"; +
;// This is fine +;// This is fine +;// This is fine +React.createElement(\"div\", {});// This is fine +React.createElement(\"bad\", {});// This is fine +
;// This is fine + +" +`; diff --git a/tests/jsx_intrinsics.builtin/jsfmt.spec.js b/tests/jsx_intrinsics.builtin/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/jsx_intrinsics.builtin/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/jsx_intrinsics.builtin/main.js b/tests/jsx_intrinsics.builtin/main.js new file mode 100644 index 000000000000..4b7ee5a28510 --- /dev/null +++ b/tests/jsx_intrinsics.builtin/main.js @@ -0,0 +1,21 @@ +// @flow + +var React = require('react'); + +class CustomComponent extends React.Component { + props: { + prop: string + }; +} + +var a: React.Element<{prop: string}> = ; +var b: React.Element<{prop1: string}> = ; // Error: Props<{prop}> ~> Props<{prop1}> + +// Since intrinsics are typed as `any` out of the box, we can pass any +// attributes to intrinsics! +var c: React.Element =
; +// However, we don't allow such elements to be viewed as React elements with +// different attributes. +var d: React.Element<{doesntmatch: string}> =
; +// No error as long as expectations are consistent, though. +var e: React.Element<{not_a_real_attr: string}> =
; diff --git a/tests/jsx_intrinsics.builtin/strings.js b/tests/jsx_intrinsics.builtin/strings.js new file mode 100644 index 000000000000..f63649cec5f7 --- /dev/null +++ b/tests/jsx_intrinsics.builtin/strings.js @@ -0,0 +1,18 @@ +/* @flow */ + +var React = require('react'); + +// The builtin $JSXIntrinsics should allow any string + +var Div = 'div'; +var Bad = 'bad'; +var Str: string = 'str'; + +
; // This is fine +; // This is fine +; // This is fine + +React.createElement('div', {}); // This is fine +React.createElement('bad', {}); // This is fine + +
; // This is fine diff --git a/tests/jsx_intrinsics.custom/__snapshots__/jsfmt.spec.js.snap b/tests/jsx_intrinsics.custom/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5034c898429f --- /dev/null +++ b/tests/jsx_intrinsics.custom/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,73 @@ +exports[`test main.js 1`] = ` +"// @flow + +var React = require(\'react\'); + +class CustomComponent extends React.Component { + props: { + prop: string + }; +} + +var a: React.Element<{prop: string}> = ; +var b: React.Element<{prop1: string}> = ; // Error: Props<{prop}> ~> Props<{prop1}> + +
; +
; // Error: (\`id\` prop) number ~> string +var c: React.Element<{id: string}> =
; +var d: React.Element<{id: number}> =
; // Error: Props<{id:string}> ~> Props<{id:number}> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test strings.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); + +var Div = \'div\'; +var Bad = \'bad\'; +var Str: string = \'str\'; + +
; // This is fine +; // Error: \'bad\' not in JSXIntrinsics +; // Error: string ~> keys of JSXIntrinsics + +React.createElement(\'div\', {}); // This is fine +React.createElement(\'bad\', {}); // Error: \'bad\' not in JSXIntrinsics +React.createElement(Str, {}); // Error: string ~> keys of JSXIntrinsics + +// TODO: Make this an error +
; // Not an error but should be eventually +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Div = \"div\"; +var Bad = \"bad\"; +var Str: string = \"str\"; +
;// This is fine +;// Error: \'bad\' not in JSXIntrinsics +;// Error: string ~> keys of JSXIntrinsics +React.createElement(\"div\", {});// This is fine +React.createElement(\"bad\", {});// Error: \'bad\' not in JSXIntrinsics +React.createElement(Str, {});// Error: string ~> keys of JSXIntrinsics +// TODO: Make this an error +
;// Not an error but should be eventually + +" +`; diff --git a/tests/jsx_intrinsics.custom/jsfmt.spec.js b/tests/jsx_intrinsics.custom/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/jsx_intrinsics.custom/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/jsx_intrinsics.custom/lib/__snapshots__/jsfmt.spec.js.snap b/tests/jsx_intrinsics.custom/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1c2c02375402 --- /dev/null +++ b/tests/jsx_intrinsics.custom/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test jsx.js 1`] = ` +"declare var $React: $Exports<\'react\'>; // fake import +type $JSXIntrinsic = Class<$React.Component>; + +type $JSXIntrinsics = { + div: $JSXIntrinsic<{id: string}>, + span: $JSXIntrinsic<{id: string, class: string}>, +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/jsx_intrinsics.custom/lib/jsfmt.spec.js b/tests/jsx_intrinsics.custom/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/jsx_intrinsics.custom/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/jsx_intrinsics.custom/lib/jsx.js b/tests/jsx_intrinsics.custom/lib/jsx.js new file mode 100644 index 000000000000..7de8608bc649 --- /dev/null +++ b/tests/jsx_intrinsics.custom/lib/jsx.js @@ -0,0 +1,7 @@ +declare var $React: $Exports<'react'>; // fake import +type $JSXIntrinsic = Class<$React.Component>; + +type $JSXIntrinsics = { + div: $JSXIntrinsic<{id: string}>, + span: $JSXIntrinsic<{id: string, class: string}>, +}; diff --git a/tests/jsx_intrinsics.custom/main.js b/tests/jsx_intrinsics.custom/main.js new file mode 100644 index 000000000000..b1f753a4c5c3 --- /dev/null +++ b/tests/jsx_intrinsics.custom/main.js @@ -0,0 +1,17 @@ +// @flow + +var React = require('react'); + +class CustomComponent extends React.Component { + props: { + prop: string + }; +} + +var a: React.Element<{prop: string}> = ; +var b: React.Element<{prop1: string}> = ; // Error: Props<{prop}> ~> Props<{prop1}> + +
; +
; // Error: (`id` prop) number ~> string +var c: React.Element<{id: string}> =
; +var d: React.Element<{id: number}> =
; // Error: Props<{id:string}> ~> Props<{id:number}> diff --git a/tests/jsx_intrinsics.custom/strings.js b/tests/jsx_intrinsics.custom/strings.js new file mode 100644 index 000000000000..b11fb78d66a3 --- /dev/null +++ b/tests/jsx_intrinsics.custom/strings.js @@ -0,0 +1,18 @@ +/* @flow */ + +var React = require('react'); + +var Div = 'div'; +var Bad = 'bad'; +var Str: string = 'str'; + +
; // This is fine +; // Error: 'bad' not in JSXIntrinsics +; // Error: string ~> keys of JSXIntrinsics + +React.createElement('div', {}); // This is fine +React.createElement('bad', {}); // Error: 'bad' not in JSXIntrinsics +React.createElement(Str, {}); // Error: string ~> keys of JSXIntrinsics + +// TODO: Make this an error +
; // Not an error but should be eventually diff --git a/tests/keys/__snapshots__/jsfmt.spec.js.snap b/tests/keys/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7e35a42698d3 --- /dev/null +++ b/tests/keys/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,64 @@ +exports[`test keys.js 1`] = ` +"/* @flow */ + +function testKeysOfObject(str: string, lit: \'hi\') { + (str: $Keys); // Any string should be fine + if (str) { + (str: $Keys); // No error, truthy string should be fine + } + (\'hi\': $Keys); // String literal should be fine + + (123: $Keys); // Error: number -> keys of Object +} + +type StrDict = {[key: string]: mixed}; +function testKeysOfStrDict(str: string, lit: \'hi\') { + (str: $Keys); // Any string should be fine + if (str) { + (str: $Keys); // No error, truthy string should be fine + } + (\'hi\': $Keys); // String literal should be fine + + (123: $Keys); // Error: number -> keys of StrDict +} + +type StrLitDict = {[key: \'hi\']: mixed}; +function testKeysOfStrLitDict(str: string, lit: \'hi\') { + (str: $Keys); // Error: Not all strings are allowed + if (str) { + (str: $Keys); // Error: Not all truthy strings are allowed + } + (\'hi\': $Keys); // The right string literal is allowed + (\'bye\': $Keys); // Error: The wrong string literal is not allowed + + (123: $Keys); // Error: number -> keys of StrLitDict +} + +type ObjLit = {hi: mixed}; +function testKeysOfOtherObj(str: string, lit: \'hi\') { + (str: $Keys); // Error: string -> keys of ObjLit + if (str) { + (str: $Keys); // Error: truthy string -> keys of ObjLit + } + (\'hi\': $Keys); // String literal should be fine + + (123: $Keys); // Error: number -> keys of ObjLit +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/keys/jsfmt.spec.js b/tests/keys/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/keys/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/keys/keys.js b/tests/keys/keys.js new file mode 100644 index 000000000000..902bc52594ee --- /dev/null +++ b/tests/keys/keys.js @@ -0,0 +1,45 @@ +/* @flow */ + +function testKeysOfObject(str: string, lit: 'hi') { + (str: $Keys); // Any string should be fine + if (str) { + (str: $Keys); // No error, truthy string should be fine + } + ('hi': $Keys); // String literal should be fine + + (123: $Keys); // Error: number -> keys of Object +} + +type StrDict = {[key: string]: mixed}; +function testKeysOfStrDict(str: string, lit: 'hi') { + (str: $Keys); // Any string should be fine + if (str) { + (str: $Keys); // No error, truthy string should be fine + } + ('hi': $Keys); // String literal should be fine + + (123: $Keys); // Error: number -> keys of StrDict +} + +type StrLitDict = {[key: 'hi']: mixed}; +function testKeysOfStrLitDict(str: string, lit: 'hi') { + (str: $Keys); // Error: Not all strings are allowed + if (str) { + (str: $Keys); // Error: Not all truthy strings are allowed + } + ('hi': $Keys); // The right string literal is allowed + ('bye': $Keys); // Error: The wrong string literal is not allowed + + (123: $Keys); // Error: number -> keys of StrLitDict +} + +type ObjLit = {hi: mixed}; +function testKeysOfOtherObj(str: string, lit: 'hi') { + (str: $Keys); // Error: string -> keys of ObjLit + if (str) { + (str: $Keys); // Error: truthy string -> keys of ObjLit + } + ('hi': $Keys); // String literal should be fine + + (123: $Keys); // Error: number -> keys of ObjLit +} diff --git a/tests/keyvalue/__snapshots__/jsfmt.spec.js.snap b/tests/keyvalue/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8505dac94a90 --- /dev/null +++ b/tests/keyvalue/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test keyvalue.js 1`] = ` +"// @flow + +let tests = [ + function(x: { [key: number]: string }) { + (x[""]: number); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + function(x: { [key: number]: string }) { + (x[""]: number); + } +]; + +" +`; diff --git a/tests/keyvalue/jsfmt.spec.js b/tests/keyvalue/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/keyvalue/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/keyvalue/keyvalue.js b/tests/keyvalue/keyvalue.js new file mode 100644 index 000000000000..469501633e2c --- /dev/null +++ b/tests/keyvalue/keyvalue.js @@ -0,0 +1,7 @@ +// @flow + +let tests = [ + function(x: { [key: number]: string }) { + (x[""]: number); + } +]; diff --git a/tests/last_duplicate_property_wins/__snapshots__/jsfmt.spec.js.snap b/tests/last_duplicate_property_wins/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4e569974d5d3 --- /dev/null +++ b/tests/last_duplicate_property_wins/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,95 @@ +exports[`test test.js 1`] = ` +"// @flow + +// Classes + +class C { + foo(): number { return 0; } + foo(): string { return "hello" } // last wins + x: number; + x: string; // last wins + bar(): number { return 0; } + bar: string; // field wins over method + qux: number; + qux(): string { return "hello" } // method loses to field! +} + +// check + +((new C).foo(): boolean); // last wins +((new C).x: boolean); // last wins +((new C).bar: boolean); // last wins +((new C).qux: boolean); // weird outlier where last doesn't win in classes + +// Objects + +const o = { + foo(): number { return 0; }, + foo(): string { return "hello" }, // last wins + x: 42, + x: "hello", // last wins + bar(): number { return 0; }, + bar: "hello", // last wins + qux: 42, + qux(): string { return "hello" }, // last wins +}; + +// check + +(o.foo(): boolean); // last wins +(o.x: boolean); // last wins +(o.bar: boolean); // last wins +(o.qux(): boolean); // last wins +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// Classes +class C { + foo(): number { + return 0; + } + foo(): string { + return "hello"; + }// last wins + x: number; + x: string;// last wins + bar(): number { + return 0; + } + bar: string;// field wins over method + qux: number; + qux(): string { + return "hello"; + }// method loses to field! +} +// check +(new C().foo(): boolean);// last wins +(new C().x: boolean);// last wins +(new C().bar: boolean);// last wins +(new C().qux: boolean);// weird outlier where last doesn't win in classes +// Objects +const o = { + foo(): number { + return 0; + }, + // last wins foo(): string { + return "hello"; + }, + x: 42, + // last wins x: "hello", + bar(): number { + return 0; + }, + // last wins bar: "hello", + qux: 42, + // last wins qux(): string { + return "hello"; + } +}; +// check +(o.foo(): boolean);// last wins +(o.x: boolean);// last wins +(o.bar: boolean);// last wins +(o.qux(): boolean);// last wins + +" +`; diff --git a/tests/last_duplicate_property_wins/jsfmt.spec.js b/tests/last_duplicate_property_wins/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/last_duplicate_property_wins/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/last_duplicate_property_wins/test.js b/tests/last_duplicate_property_wins/test.js new file mode 100644 index 000000000000..8468262e3d2b --- /dev/null +++ b/tests/last_duplicate_property_wins/test.js @@ -0,0 +1,41 @@ +// @flow + +// Classes + +class C { + foo(): number { return 0; } + foo(): string { return "hello" } // last wins + x: number; + x: string; // last wins + bar(): number { return 0; } + bar: string; // field wins over method + qux: number; + qux(): string { return "hello" } // method loses to field! +} + +// check + +((new C).foo(): boolean); // last wins +((new C).x: boolean); // last wins +((new C).bar: boolean); // last wins +((new C).qux: boolean); // weird outlier where last doesn't win in classes + +// Objects + +const o = { + foo(): number { return 0; }, + foo(): string { return "hello" }, // last wins + x: 42, + x: "hello", // last wins + bar(): number { return 0; }, + bar: "hello", // last wins + qux: 42, + qux(): string { return "hello" }, // last wins +}; + +// check + +(o.foo(): boolean); // last wins +(o.x: boolean); // last wins +(o.bar: boolean); // last wins +(o.qux(): boolean); // last wins diff --git a/tests/lib/__snapshots__/jsfmt.spec.js.snap b/tests/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..173f38aad2ce --- /dev/null +++ b/tests/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test libtest.js 1`] = ` +"var x:string = NaN +var y:string = Number.MAX_VALUE; +var z:number = new TypeError().name; +var w:string = parseInt("..."); + +var a = new Map(); +a.delete('foobar'); + +var b = undefined; +if (undefined) { +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: string = NaN; +var y: string = Number.MAX_VALUE; +var z: number = new TypeError().name; +var w: string = parseInt("..."); +var a = new Map(); +a.delete("foobar"); +var b = undefined; +if (undefined) { + +} + +" +`; diff --git a/tests/lib/jsfmt.spec.js b/tests/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/lib/libtest.js b/tests/lib/libtest.js new file mode 100644 index 000000000000..567ac09d40f4 --- /dev/null +++ b/tests/lib/libtest.js @@ -0,0 +1,11 @@ +var x:string = NaN +var y:string = Number.MAX_VALUE; +var z:number = new TypeError().name; +var w:string = parseInt("..."); + +var a = new Map(); +a.delete('foobar'); + +var b = undefined; +if (undefined) { +} diff --git a/tests/lib_interfaces/declarations/__snapshots__/jsfmt.spec.js.snap b/tests/lib_interfaces/declarations/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..07222343166a --- /dev/null +++ b/tests/lib_interfaces/declarations/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test underscore.js 1`] = ` +"interface C { + foo(): CArrays; + bar(): C; +} +interface CArrays extends C> { + bar(): C; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1384:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/lib_interfaces/declarations/jsfmt.spec.js b/tests/lib_interfaces/declarations/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/lib_interfaces/declarations/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/lib_interfaces/declarations/underscore.js b/tests/lib_interfaces/declarations/underscore.js new file mode 100644 index 000000000000..305116bacbec --- /dev/null +++ b/tests/lib_interfaces/declarations/underscore.js @@ -0,0 +1,7 @@ +interface C { + foo(): CArrays; + bar(): C; +} +interface CArrays extends C> { + bar(): C; +} diff --git a/tests/libconfig/__snapshots__/jsfmt.spec.js.snap b/tests/libconfig/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b941f86bc364 --- /dev/null +++ b/tests/libconfig/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,51 @@ +exports[`test libA.js 1`] = ` +"declare function foo(x: number): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test libB.js 1`] = ` +"declare function bar(x: string): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test libtest.js 1`] = ` +"foo(123); +bar(123); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +foo(123); +bar(123); + +" +`; diff --git a/tests/libconfig/jsfmt.spec.js b/tests/libconfig/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/libconfig/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/libconfig/libA.js b/tests/libconfig/libA.js new file mode 100644 index 000000000000..304501d2cc6f --- /dev/null +++ b/tests/libconfig/libA.js @@ -0,0 +1 @@ +declare function foo(x: number): void; diff --git a/tests/libconfig/libB.js b/tests/libconfig/libB.js new file mode 100644 index 000000000000..218601f8fa85 --- /dev/null +++ b/tests/libconfig/libB.js @@ -0,0 +1 @@ +declare function bar(x: string): void; diff --git a/tests/libconfig/libtest.js b/tests/libconfig/libtest.js new file mode 100644 index 000000000000..d78728d487b9 --- /dev/null +++ b/tests/libconfig/libtest.js @@ -0,0 +1,2 @@ +foo(123); +bar(123); diff --git a/tests/libdef_ignored_module/__snapshots__/jsfmt.spec.js.snap b/tests/libdef_ignored_module/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8499e56a2b51 --- /dev/null +++ b/tests/libdef_ignored_module/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,13 @@ +exports[`test test.js 1`] = ` +"/* @flow */ + +import foo from "foo"; + +(foo.bar : string); // error number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +import foo from "foo"; +(foo.bar: string);// error number ~> string + +" +`; diff --git a/tests/libdef_ignored_module/jsfmt.spec.js b/tests/libdef_ignored_module/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/libdef_ignored_module/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/libdef_ignored_module/lib/__snapshots__/jsfmt.spec.js.snap b/tests/libdef_ignored_module/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5984291f7dc8 --- /dev/null +++ b/tests/libdef_ignored_module/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,11 @@ +exports[`test foo.js 1`] = ` +"declare module foo { + declare var bar: number; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare module foo { + declare var bar: number; +} + +" +`; diff --git a/tests/libdef_ignored_module/lib/foo.js b/tests/libdef_ignored_module/lib/foo.js new file mode 100644 index 000000000000..955a7d7f6a79 --- /dev/null +++ b/tests/libdef_ignored_module/lib/foo.js @@ -0,0 +1,3 @@ +declare module foo { + declare var bar: number; +} diff --git a/tests/libdef_ignored_module/lib/jsfmt.spec.js b/tests/libdef_ignored_module/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/libdef_ignored_module/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/libdef_ignored_module/test.js b/tests/libdef_ignored_module/test.js new file mode 100644 index 000000000000..334e7e8c21bd --- /dev/null +++ b/tests/libdef_ignored_module/test.js @@ -0,0 +1,5 @@ +/* @flow */ + +import foo from "foo"; + +(foo.bar : string); // error number ~> string diff --git a/tests/liberr/__snapshots__/jsfmt.spec.js.snap b/tests/liberr/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fb842df9ee45 --- /dev/null +++ b/tests/liberr/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test a.js 1`] = ` +"/** + * @flow + */ +// one error here, to verify lib errors sort to top. +var x: string = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +// one error here, to verify lib errors sort to top. +var x: string = 0; + +" +`; diff --git a/tests/liberr/a.js b/tests/liberr/a.js new file mode 100644 index 000000000000..f444c23835cd --- /dev/null +++ b/tests/liberr/a.js @@ -0,0 +1,5 @@ +/** + * @flow + */ +// one error here, to verify lib errors sort to top. +var x: string = 0; diff --git a/tests/liberr/jsfmt.spec.js b/tests/liberr/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/liberr/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/liberr/libs/__snapshots__/jsfmt.spec.js.snap b/tests/liberr/libs/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8c596e46cf84 --- /dev/null +++ b/tests/liberr/libs/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,51 @@ +exports[`test parse_error.js 1`] = ` +"/** + * @flow + */ +declare class ExampleClass { + + methodA: () => any // parse error, missing comma + + methodB: () => any + +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (8:2) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowObjectTypeSemicolon (/node_modules/babylon/lib/index.js:4832:10) + at Parser.pp$7.flowParseObjectType (/node_modules/babylon/lib/index.js:4813:14) + at Parser.pp$7.flowParseInterfaceish (/node_modules/babylon/lib/index.js:4575:20) + at Parser.pp$7.flowParseDeclareClass (/node_modules/babylon/lib/index.js:4437:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4474:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) +" +`; + +exports[`test type_error.js 1`] = ` +"// @flow +declare function foo(x: number): Array; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/liberr/libs/jsfmt.spec.js b/tests/liberr/libs/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/liberr/libs/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/liberr/libs/parse_error.js b/tests/liberr/libs/parse_error.js new file mode 100644 index 000000000000..08cd2a15d3c0 --- /dev/null +++ b/tests/liberr/libs/parse_error.js @@ -0,0 +1,10 @@ +/** + * @flow + */ +declare class ExampleClass { + + methodA: () => any // parse error, missing comma + + methodB: () => any + +} diff --git a/tests/liberr/libs/type_error.js b/tests/liberr/libs/type_error.js new file mode 100644 index 000000000000..1c36d039ecc4 --- /dev/null +++ b/tests/liberr/libs/type_error.js @@ -0,0 +1,2 @@ +// @flow +declare function foo(x: number): Array; diff --git a/tests/libflow-typed/__snapshots__/jsfmt.spec.js.snap b/tests/libflow-typed/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5a2c84cb0777 --- /dev/null +++ b/tests/libflow-typed/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test libtest.js 1`] = ` +"/* @flow */ +const dino : Dinosaur = "Stegosaurus" +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +const dino: Dinosaur = "Stegosaurus"; + +" +`; diff --git a/tests/libflow-typed/flow-typed/__snapshots__/jsfmt.spec.js.snap b/tests/libflow-typed/flow-typed/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fcc919445fd6 --- /dev/null +++ b/tests/libflow-typed/flow-typed/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +exports[`test dino.js 1`] = ` +"declare type Dinosaur = \"T-Rex\" | \"Apatosaurus\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/libflow-typed/flow-typed/dino.js b/tests/libflow-typed/flow-typed/dino.js new file mode 100644 index 000000000000..283429db6f73 --- /dev/null +++ b/tests/libflow-typed/flow-typed/dino.js @@ -0,0 +1 @@ +declare type Dinosaur = "T-Rex" | "Apatosaurus"; diff --git a/tests/libflow-typed/flow-typed/jsfmt.spec.js b/tests/libflow-typed/flow-typed/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/libflow-typed/flow-typed/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/libflow-typed/jsfmt.spec.js b/tests/libflow-typed/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/libflow-typed/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/libflow-typed/libtest.js b/tests/libflow-typed/libtest.js new file mode 100644 index 000000000000..8d4b83401678 --- /dev/null +++ b/tests/libflow-typed/libtest.js @@ -0,0 +1,2 @@ +/* @flow */ +const dino : Dinosaur = "Stegosaurus" diff --git a/tests/librec/__snapshots__/jsfmt.spec.js.snap b/tests/librec/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2921149267ff --- /dev/null +++ b/tests/librec/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test libtest.js 1`] = ` +"foo(123); +bar(123); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +foo(123); +bar(123); + +" +`; diff --git a/tests/librec/jsfmt.spec.js b/tests/librec/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/librec/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/librec/lib/A/__snapshots__/jsfmt.spec.js.snap b/tests/librec/lib/A/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b1e15472a048 --- /dev/null +++ b/tests/librec/lib/A/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +exports[`test libA.js 1`] = ` +"declare function foo(x: number): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/librec/lib/A/jsfmt.spec.js b/tests/librec/lib/A/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/librec/lib/A/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/librec/lib/A/libA.js b/tests/librec/lib/A/libA.js new file mode 100644 index 000000000000..304501d2cc6f --- /dev/null +++ b/tests/librec/lib/A/libA.js @@ -0,0 +1 @@ +declare function foo(x: number): void; diff --git a/tests/librec/lib/B/__snapshots__/jsfmt.spec.js.snap b/tests/librec/lib/B/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..09b44d83467e --- /dev/null +++ b/tests/librec/lib/B/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,20 @@ +exports[`test libB.js 1`] = ` +"declare function bar(x: string): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/librec/lib/B/jsfmt.spec.js b/tests/librec/lib/B/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/librec/lib/B/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/librec/lib/B/libB.js b/tests/librec/lib/B/libB.js new file mode 100644 index 000000000000..218601f8fa85 --- /dev/null +++ b/tests/librec/lib/B/libB.js @@ -0,0 +1 @@ +declare function bar(x: string): void; diff --git a/tests/librec/libtest.js b/tests/librec/libtest.js new file mode 100644 index 000000000000..d78728d487b9 --- /dev/null +++ b/tests/librec/libtest.js @@ -0,0 +1,2 @@ +foo(123); +bar(123); diff --git a/tests/literal/__snapshots__/jsfmt.spec.js.snap b/tests/literal/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..09237dbc394c --- /dev/null +++ b/tests/literal/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,104 @@ +exports[`test enum.js 1`] = ` +"var APIKeys = { + AGE: \'age\', + NAME: \'name\', +}; + +module.exports = APIKeys; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var APIKeys = { AGE: \"age\", NAME: \"name\" }; +module.exports = APIKeys; + +" +`; + +exports[`test enum_client.js 1`] = ` +"var APIKeys = require(\'./enum\'); +// object that maps \"AGE\" to \"age\", \"NAME\" to \"name\" + +function foo(x: $Keys) { } +foo(\"AGE\"); +foo(\"LOCATION\"); // error + +function bar(x: $Keys<{age: number}>) { } +bar(APIKeys.AGE); // not an error: APIKeys.AGE = \"age\" +bar(APIKeys.NAME); // error: since \"NAME\" is not in the smaller enum + +var object = {}; +object[APIKeys.AGE] = 123; // i.e., object.age = 123 +object[APIKeys.NAME] = \"FOO\"; // i.e., object.name = \"FOO\" + +var age:number = object[APIKeys.AGE]; +var name:number = object[APIKeys.NAME]; // error: object.name is a string + +var indices = { red: 0, green: 1, blue: 2 }; +var tuple = [42, \"hello\", false]; +var red:string = tuple[indices.red]; // error: tuple[0] is a number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test number.js 1`] = ` +"function test1(x: number): number { + return -x; +} + +function test2(x: string): number { + return -x; +} + +// sanity checks to make sure merging envs doesn\'t keep creating new NumT\'s +// because of the UnaryMinusT\'s, causing nontermination +function test3(x: number, flip_times: number): number { + for (var i = 0; i < flip_times; i++) { + x = -x; + } + return x; +} +function test4(flip_times: number): number { + var x = 1; + for (var i = 0; i < flip_times; i++) { + x = -x; + } + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function test1(x: number): number { + return -x; +} +function test2(x: string): number { + return -x; +} +// sanity checks to make sure merging envs doesn\'t keep creating new NumT\'s +// because of the UnaryMinusT\'s, causing nontermination +function test3(x: number, flip_times: number): number { + for (var i = 0; i < flip_times; i++) { + x = -x; + } + return x; +} +function test4(flip_times: number): number { + var x = 1; + for (var i = 0; i < flip_times; i++) { + x = -x; + } + return x; +} + +" +`; diff --git a/tests/literal/enum.js b/tests/literal/enum.js new file mode 100644 index 000000000000..6449c41bd82c --- /dev/null +++ b/tests/literal/enum.js @@ -0,0 +1,6 @@ +var APIKeys = { + AGE: 'age', + NAME: 'name', +}; + +module.exports = APIKeys; diff --git a/tests/literal/enum_client.js b/tests/literal/enum_client.js new file mode 100644 index 000000000000..2259290ad4ef --- /dev/null +++ b/tests/literal/enum_client.js @@ -0,0 +1,21 @@ +var APIKeys = require('./enum'); +// object that maps "AGE" to "age", "NAME" to "name" + +function foo(x: $Keys) { } +foo("AGE"); +foo("LOCATION"); // error + +function bar(x: $Keys<{age: number}>) { } +bar(APIKeys.AGE); // not an error: APIKeys.AGE = "age" +bar(APIKeys.NAME); // error: since "NAME" is not in the smaller enum + +var object = {}; +object[APIKeys.AGE] = 123; // i.e., object.age = 123 +object[APIKeys.NAME] = "FOO"; // i.e., object.name = "FOO" + +var age:number = object[APIKeys.AGE]; +var name:number = object[APIKeys.NAME]; // error: object.name is a string + +var indices = { red: 0, green: 1, blue: 2 }; +var tuple = [42, "hello", false]; +var red:string = tuple[indices.red]; // error: tuple[0] is a number diff --git a/tests/literal/jsfmt.spec.js b/tests/literal/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/literal/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/literal/number.js b/tests/literal/number.js new file mode 100644 index 000000000000..1ec5299191b5 --- /dev/null +++ b/tests/literal/number.js @@ -0,0 +1,23 @@ +function test1(x: number): number { + return -x; +} + +function test2(x: string): number { + return -x; +} + +// sanity checks to make sure merging envs doesn't keep creating new NumT's +// because of the UnaryMinusT's, causing nontermination +function test3(x: number, flip_times: number): number { + for (var i = 0; i < flip_times; i++) { + x = -x; + } + return x; +} +function test4(flip_times: number): number { + var x = 1; + for (var i = 0; i < flip_times; i++) { + x = -x; + } + return x; +} diff --git a/tests/locals/__snapshots__/jsfmt.spec.js.snap b/tests/locals/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6ed1110ebc93 --- /dev/null +++ b/tests/locals/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,122 @@ +exports[`test lex.js 1`] = ` +"function switch_scope(x: mixed) { + let a = \"\"; + let b = \"\"; + switch (x) { + case \"foo\": + let a; + a = 0; // doesn\'t add lower bound to outer a + b = 0; + } + (a : string); // OK + (b : string); // error: number ~> string +} + +function try_scope_finally() { + let a; + let b; + try { + a = \"\"; + b = \"\"; + } finally { + let a; + a = 0; // doesn\'t add lower bound to outer a + b = 0; + } + (a : string); // ok + (b : string); // error: number ~> string +} + +function for_scope() { + let a = \"\"; + let b = \"\"; + for (let a;;) { + a = 0; // doesn\'t add lower bound to outer a + b = 0; + } + (a : string); + (b : string); // error: number ~> string +} + +function for_in_scope(o: Object) { + let a = 0; + let b = 0; + for (let a in o) { + a = \"\"; // doesn\'t add lower bound to outer a + b = \"\"; + } + (a : number); + (b : number); // error: string ~> number +} + +function for_of_scope(xs: number[]) { + let a = \"\"; + let b = \"\"; + for (let a of xs) { + a = 0; // doesn\'t add lower bound to outer a + b = 0; + } + (a : string); + (b : string); // error: number ~> string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test locals.js 1`] = ` +"var x:string = 0; +var x:number = 1; + +//declare var T: $Type>; + +function foo(p: bool) {} + +function sorry(really: bool) { + if (really) { + var x: number | string = 1337; + } else { + var x: bool = true; + } + foo(x); +} + +function foo0(b: bool): number { + var x = 0; + if (b) { + var x = \"\"; // error: string ~> number + } + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/locals/jsfmt.spec.js b/tests/locals/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/locals/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/locals/lex.js b/tests/locals/lex.js new file mode 100644 index 000000000000..a97bd4604439 --- /dev/null +++ b/tests/locals/lex.js @@ -0,0 +1,60 @@ +function switch_scope(x: mixed) { + let a = ""; + let b = ""; + switch (x) { + case "foo": + let a; + a = 0; // doesn't add lower bound to outer a + b = 0; + } + (a : string); // OK + (b : string); // error: number ~> string +} + +function try_scope_finally() { + let a; + let b; + try { + a = ""; + b = ""; + } finally { + let a; + a = 0; // doesn't add lower bound to outer a + b = 0; + } + (a : string); // ok + (b : string); // error: number ~> string +} + +function for_scope() { + let a = ""; + let b = ""; + for (let a;;) { + a = 0; // doesn't add lower bound to outer a + b = 0; + } + (a : string); + (b : string); // error: number ~> string +} + +function for_in_scope(o: Object) { + let a = 0; + let b = 0; + for (let a in o) { + a = ""; // doesn't add lower bound to outer a + b = ""; + } + (a : number); + (b : number); // error: string ~> number +} + +function for_of_scope(xs: number[]) { + let a = ""; + let b = ""; + for (let a of xs) { + a = 0; // doesn't add lower bound to outer a + b = 0; + } + (a : string); + (b : string); // error: number ~> string +} diff --git a/tests/locals/locals.js b/tests/locals/locals.js new file mode 100644 index 000000000000..ebb8167bc4dd --- /dev/null +++ b/tests/locals/locals.js @@ -0,0 +1,23 @@ +var x:string = 0; +var x:number = 1; + +//declare var T: $Type>; + +function foo(p: bool) {} + +function sorry(really: bool) { + if (really) { + var x: number | string = 1337; + } else { + var x: bool = true; + } + foo(x); +} + +function foo0(b: bool): number { + var x = 0; + if (b) { + var x = ""; // error: string ~> number + } + return x; +} diff --git a/tests/logical/__snapshots__/jsfmt.spec.js.snap b/tests/logical/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3970bd284909 --- /dev/null +++ b/tests/logical/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,533 @@ +exports[`test logical.js 1`] = ` +"/* @flow */ + +/** + * A falsy variable on the left side of && + */ +function logical1a(): number { // expected \`: boolean\` + var x = false; + return x && \'123\'; +} + +/** + * A truthy variable on the left side of && + */ +function logical1b(): string { + var x = true; + return x && \'123\'; +} + +/** + * A literal on the left side of && + */ +function logical2a(): number { // expected \`: boolean\` + return false && \'123\'; +} + +/** + * A literal on the left side of && + */ +function logical2b(): number { + return 0 && \'123\'; +} + +/** + * A literal on the left side of && + */ +function logical2c(): string { + return \"\" && 123; +} + +/** + * A literal on the left side of && + */ +function logical2d(): string { + return true && \'123\'; +} + +/** + * A literal on the left side of && + */ +function logical2e(): number { + return \'foo\' && 123; +} + +/** + * A literal on the left side of && + */ +function logical2f(): string { + return 123 && \'foo\'; +} + +/** + * A literal on the left side of && + */ +function logical2g(): string { + return [1,2,3] && \'foo\'; +} + +/** + * A literal on the left side of && + */ +function logical2h(x: {a: number}): string { + return x && \'foo\'; +} + +/** + * A literal on the left side of && + */ +function logical2i(x: Object): string { + return x && \'foo\'; +} + +/** + * A literal on the left side of && + */ +function logical2j(x: (a: number) => number): string { + return x && \'foo\'; +} + +/** + * A literal on the left side of && + */ +function logical2k(x: Function): string { + return x && \'foo\'; +} + +/** + * An expression on the left side of && + */ +function logical3a(): string { // expected \`: boolean\` + var x: ?number = null; + return x != null && x > 10; +} + +/** + * An expression on the left side of && + */ +function logical3b(): number { // expected \`: boolean | number\` + var x: ?number = null; + return x != null && x; +} + +/** + * An expression on the left side of && + */ +function logical3c(): ?number { // expected \`: boolean | ?number\` + var x: ?number = null; + return x != undefined && x; +} + +/** + * Maybe truthy returns both types + */ +function logical4(x: boolean): string { // expected \`: boolean | string\` + return x && \'123\'; +} + +/** + * A falsy variable on the left side of || + */ +function logical5a(): number { + var x = false; + return x || 0; +} + +/** + * A maybe variable on the left side of || + */ +function logical5b(): number { + var x: ?number = null; + return x || 0; +} + +/** + * A truthy variable on the left side of || + */ +function logical5c(): string { // expected \`: boolean\` + var x = true; + return x || 0; +} + +/** + * A literal on the left side of || + */ +function logical6a(): string { + return false || \'123\'; +} + +/** + * A literal on the left side of || + */ +function logical6b(): string { + return 0 || \'123\'; +} + +/** + * A literal on the left side of || + */ +function logical6c(): number { + return \"\" || 123; +} + +/** + * A literal on the left side of || + */ +function logical6d(): number { // expected \`: boolean\` + return true || \'123\'; +} + +/** + * A literal on the left side of || + */ +function logical6e(): string { + return \'foo\' || 123; +} + +/** + * A literal on the left side of || + */ +function logical6f(): number { + return 123 || \'foo\'; +} + +/** + * A composite && and || + */ +function logical7a(): number { + var x: ?number = null; + return x != null && x || 0; +} + +/** + * A composite && and || where the truthiness is unknown + */ +function logical7b(x: boolean, y: number): number { + return x && y || 0; +} + +/** + * A composite && and || + */ +function logical7c(x: string): number { + return x && 1 || 0; +} + +/** + * A composite && and || + */ +function logical7d(x: number): string { + return x && \'foo\' || \'bar\'; +} + +/** + * A composite && and || + */ +function logical7e(x: number): string { + return false && x || \'bar\'; +} + +/** + * A composite || and && + * + * \`x || 0\` always returns a number (never a boolean) and then short + * circuits the && because 0 is falsy, so this should just return number. + */ +function logical8a(): number { + var x = false; + return (x || 0) && \'foo\'; +} + +/** + * A composite || and && + * + * \`x || 1\` always returns something truthy, so this returns a string + */ +function logical8b(): string { + var x = false; + return (x || 1) && \'foo\'; +} + +/** + * A composite || and && + * + * \`x\` is always truthy, so this returns a string + */ +function logical8c(): string { + var x = true; + return (x || 1) && \'foo\'; +} + +/** + * A composite || and && + */ +function logical8d(): number { + var x = false; + return x || (0 && \'foo\'); +} + +/** + * A composite || and && + */ +function logical8e(): string { + var x = false; + return x || (1 && \'foo\'); +} + +/** + * A composite || and && + */ +function logical8f(): string { // expected \`: boolean\` + var x = true; + return x || (1 && \'foo\'); +} + +/** + * A composite || and || + */ +function logical9a( + x: number, + y: string +): number | string { // expected \`: number | string | boolean\` + return x || y || false; +} + +/** + * A composite || and || + */ +function logical9b(x: number, y: string): number | string { + return false || x || y; +} + +/** + * A composite || and || + */ +function logical9c(x: number, y: boolean): string { + return \'a\' || x || y; +} + +/** + * A composite && and && + */ +function logical10a( + x: number, + y: string +): number | string { // expected \`: number | string | boolean\` + return x && y && false; +} + +/** + * A composite && and && + */ +function logical10b(x: number, y: string): Array { // expected \`: boolean\` + return false && x && y; +} + +/** + * A composite && and && + */ +function logical10c(x: number, y: string): Array { // expected \`number | boolean\` + return x && false && y; +} + +/** + * || in a loop + */ +function logical11a(): number { + var y = 1; + for (var x = 0; x < 5; x++) { + y = y || true; + } + return y; +} + +/** + * || in a loop + */ +function logical11b(y: number): number { + for (var x = 0; x < 5; x++) { + y = y || true; // expected a number + } + return y; +} + +/** + * && in a loop + */ +function logical12a(): number { + var y = 1; + var z = true; + for (var x = 0; x < 5; x++) { + y = z && y; + z = false; + } + return y; +} + +/** + * && in a loop + */ +function logical12b(y: number): number { + for (var x = 0; x < 5; x++) { + y = y && true; // expected a number + } + return y; +} + +/** + * Complex && + */ +function logical13(x: number): Array<{x: string}> { + return [ + {x: x && \"bar\"}, + {x: true && \"bar\"}, + {x: true && false}, + {x: false && false}, + {x: 1 && \"bar\"}, + {x: \"foo\" && \"bar\"}, + {x: \"foo\" && \"bar\"}, + {x: \"foo\" && \"bar\"}, + ]; +} + +/** + * Complex || + */ +function logical14(x: number): Array<{x: string}> { + return [ + {x: x || \"bar\"}, + {x: false || \"bar\"}, + {x: false || true}, + {x: true || false}, + {x: 0 || \"bar\"}, + {x: \"foo\" || \"bar\"}, + {x: \"foo\" || \"bar\"}, + {x: \"foo\" || \"bar\"}, + ]; +} + +/** + * || in an addition + */ +function logical15a(x: number): number { + return 5 + (x || 7); +} + +/** + * || in an addition + */ +function logical15b(x: number): number { + return (x || 7) + 5; +} + +/** + * && in an addition + */ +function logical15c(x: number): number { + return 5 + (x && 7); +} + +/** + * && in an addition + */ +function logical15d(x: number): number { + return (x && 7) + 5; +} + +/** + * || in a comparison + */ +function logical16a(x: number): boolean { + return 5 < (x || 7); +} + +/** + * || in a comparison + */ +function logical16b(x: number): boolean { + return (x || 7) < 5; +} + +/** + * && in a comparison + */ +function logical16c(x: number): boolean { + return 5 < (x && 7); +} + +/** + * && in a comparison + */ +function logical16d(x: number): boolean { + return (x && 7) < 5; +} + +/** + * || in an equality + */ +function logical17a(x: number): boolean { + return 5 == (x || 7); +} + +/** + * || in an equality + */ +function logical17b(x: number): boolean { + return (x || 7) == 5; +} + +/** + * && in an equality + */ +function logical17c(x: number): boolean { + return 5 == (x && 7); +} + +/** + * && in an equality + */ +function logical17d(x: number): boolean { + return (x && 7) == 5; +} + +/** + * Expressions on each side that return truthy things + */ +function logical18a(x: number, y: number): number { + return x - 1 || y - 1; +} + +/** + * Sentinel properties should not interfere + */ +function logical18b(x: {a: number}, y: {b: number}): number { + return x.a - 1 || y.b - 1; +} + +/** + * Layer of indirection in the LHS (get prop) + */ +function logical19a(x: { y: string, z: boolean }): boolean { + return (x.y && x.z); // error: x.y is a string +} +function logical19b(x: { y: string, z: boolean }): boolean { + return (x.y || x.z); // error: x.y is a string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/logical/jsfmt.spec.js b/tests/logical/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/logical/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/logical/logical.js b/tests/logical/logical.js new file mode 100644 index 000000000000..b4aa1dcf90aa --- /dev/null +++ b/tests/logical/logical.js @@ -0,0 +1,514 @@ +/* @flow */ + +/** + * A falsy variable on the left side of && + */ +function logical1a(): number { // expected `: boolean` + var x = false; + return x && '123'; +} + +/** + * A truthy variable on the left side of && + */ +function logical1b(): string { + var x = true; + return x && '123'; +} + +/** + * A literal on the left side of && + */ +function logical2a(): number { // expected `: boolean` + return false && '123'; +} + +/** + * A literal on the left side of && + */ +function logical2b(): number { + return 0 && '123'; +} + +/** + * A literal on the left side of && + */ +function logical2c(): string { + return "" && 123; +} + +/** + * A literal on the left side of && + */ +function logical2d(): string { + return true && '123'; +} + +/** + * A literal on the left side of && + */ +function logical2e(): number { + return 'foo' && 123; +} + +/** + * A literal on the left side of && + */ +function logical2f(): string { + return 123 && 'foo'; +} + +/** + * A literal on the left side of && + */ +function logical2g(): string { + return [1,2,3] && 'foo'; +} + +/** + * A literal on the left side of && + */ +function logical2h(x: {a: number}): string { + return x && 'foo'; +} + +/** + * A literal on the left side of && + */ +function logical2i(x: Object): string { + return x && 'foo'; +} + +/** + * A literal on the left side of && + */ +function logical2j(x: (a: number) => number): string { + return x && 'foo'; +} + +/** + * A literal on the left side of && + */ +function logical2k(x: Function): string { + return x && 'foo'; +} + +/** + * An expression on the left side of && + */ +function logical3a(): string { // expected `: boolean` + var x: ?number = null; + return x != null && x > 10; +} + +/** + * An expression on the left side of && + */ +function logical3b(): number { // expected `: boolean | number` + var x: ?number = null; + return x != null && x; +} + +/** + * An expression on the left side of && + */ +function logical3c(): ?number { // expected `: boolean | ?number` + var x: ?number = null; + return x != undefined && x; +} + +/** + * Maybe truthy returns both types + */ +function logical4(x: boolean): string { // expected `: boolean | string` + return x && '123'; +} + +/** + * A falsy variable on the left side of || + */ +function logical5a(): number { + var x = false; + return x || 0; +} + +/** + * A maybe variable on the left side of || + */ +function logical5b(): number { + var x: ?number = null; + return x || 0; +} + +/** + * A truthy variable on the left side of || + */ +function logical5c(): string { // expected `: boolean` + var x = true; + return x || 0; +} + +/** + * A literal on the left side of || + */ +function logical6a(): string { + return false || '123'; +} + +/** + * A literal on the left side of || + */ +function logical6b(): string { + return 0 || '123'; +} + +/** + * A literal on the left side of || + */ +function logical6c(): number { + return "" || 123; +} + +/** + * A literal on the left side of || + */ +function logical6d(): number { // expected `: boolean` + return true || '123'; +} + +/** + * A literal on the left side of || + */ +function logical6e(): string { + return 'foo' || 123; +} + +/** + * A literal on the left side of || + */ +function logical6f(): number { + return 123 || 'foo'; +} + +/** + * A composite && and || + */ +function logical7a(): number { + var x: ?number = null; + return x != null && x || 0; +} + +/** + * A composite && and || where the truthiness is unknown + */ +function logical7b(x: boolean, y: number): number { + return x && y || 0; +} + +/** + * A composite && and || + */ +function logical7c(x: string): number { + return x && 1 || 0; +} + +/** + * A composite && and || + */ +function logical7d(x: number): string { + return x && 'foo' || 'bar'; +} + +/** + * A composite && and || + */ +function logical7e(x: number): string { + return false && x || 'bar'; +} + +/** + * A composite || and && + * + * `x || 0` always returns a number (never a boolean) and then short + * circuits the && because 0 is falsy, so this should just return number. + */ +function logical8a(): number { + var x = false; + return (x || 0) && 'foo'; +} + +/** + * A composite || and && + * + * `x || 1` always returns something truthy, so this returns a string + */ +function logical8b(): string { + var x = false; + return (x || 1) && 'foo'; +} + +/** + * A composite || and && + * + * `x` is always truthy, so this returns a string + */ +function logical8c(): string { + var x = true; + return (x || 1) && 'foo'; +} + +/** + * A composite || and && + */ +function logical8d(): number { + var x = false; + return x || (0 && 'foo'); +} + +/** + * A composite || and && + */ +function logical8e(): string { + var x = false; + return x || (1 && 'foo'); +} + +/** + * A composite || and && + */ +function logical8f(): string { // expected `: boolean` + var x = true; + return x || (1 && 'foo'); +} + +/** + * A composite || and || + */ +function logical9a( + x: number, + y: string +): number | string { // expected `: number | string | boolean` + return x || y || false; +} + +/** + * A composite || and || + */ +function logical9b(x: number, y: string): number | string { + return false || x || y; +} + +/** + * A composite || and || + */ +function logical9c(x: number, y: boolean): string { + return 'a' || x || y; +} + +/** + * A composite && and && + */ +function logical10a( + x: number, + y: string +): number | string { // expected `: number | string | boolean` + return x && y && false; +} + +/** + * A composite && and && + */ +function logical10b(x: number, y: string): Array { // expected `: boolean` + return false && x && y; +} + +/** + * A composite && and && + */ +function logical10c(x: number, y: string): Array { // expected `number | boolean` + return x && false && y; +} + +/** + * || in a loop + */ +function logical11a(): number { + var y = 1; + for (var x = 0; x < 5; x++) { + y = y || true; + } + return y; +} + +/** + * || in a loop + */ +function logical11b(y: number): number { + for (var x = 0; x < 5; x++) { + y = y || true; // expected a number + } + return y; +} + +/** + * && in a loop + */ +function logical12a(): number { + var y = 1; + var z = true; + for (var x = 0; x < 5; x++) { + y = z && y; + z = false; + } + return y; +} + +/** + * && in a loop + */ +function logical12b(y: number): number { + for (var x = 0; x < 5; x++) { + y = y && true; // expected a number + } + return y; +} + +/** + * Complex && + */ +function logical13(x: number): Array<{x: string}> { + return [ + {x: x && "bar"}, + {x: true && "bar"}, + {x: true && false}, + {x: false && false}, + {x: 1 && "bar"}, + {x: "foo" && "bar"}, + {x: "foo" && "bar"}, + {x: "foo" && "bar"}, + ]; +} + +/** + * Complex || + */ +function logical14(x: number): Array<{x: string}> { + return [ + {x: x || "bar"}, + {x: false || "bar"}, + {x: false || true}, + {x: true || false}, + {x: 0 || "bar"}, + {x: "foo" || "bar"}, + {x: "foo" || "bar"}, + {x: "foo" || "bar"}, + ]; +} + +/** + * || in an addition + */ +function logical15a(x: number): number { + return 5 + (x || 7); +} + +/** + * || in an addition + */ +function logical15b(x: number): number { + return (x || 7) + 5; +} + +/** + * && in an addition + */ +function logical15c(x: number): number { + return 5 + (x && 7); +} + +/** + * && in an addition + */ +function logical15d(x: number): number { + return (x && 7) + 5; +} + +/** + * || in a comparison + */ +function logical16a(x: number): boolean { + return 5 < (x || 7); +} + +/** + * || in a comparison + */ +function logical16b(x: number): boolean { + return (x || 7) < 5; +} + +/** + * && in a comparison + */ +function logical16c(x: number): boolean { + return 5 < (x && 7); +} + +/** + * && in a comparison + */ +function logical16d(x: number): boolean { + return (x && 7) < 5; +} + +/** + * || in an equality + */ +function logical17a(x: number): boolean { + return 5 == (x || 7); +} + +/** + * || in an equality + */ +function logical17b(x: number): boolean { + return (x || 7) == 5; +} + +/** + * && in an equality + */ +function logical17c(x: number): boolean { + return 5 == (x && 7); +} + +/** + * && in an equality + */ +function logical17d(x: number): boolean { + return (x && 7) == 5; +} + +/** + * Expressions on each side that return truthy things + */ +function logical18a(x: number, y: number): number { + return x - 1 || y - 1; +} + +/** + * Sentinel properties should not interfere + */ +function logical18b(x: {a: number}, y: {b: number}): number { + return x.a - 1 || y.b - 1; +} + +/** + * Layer of indirection in the LHS (get prop) + */ +function logical19a(x: { y: string, z: boolean }): boolean { + return (x.y && x.z); // error: x.y is a string +} +function logical19b(x: { y: string, z: boolean }): boolean { + return (x.y || x.z); // error: x.y is a string +} diff --git a/tests/loners/__snapshots__/jsfmt.spec.js.snap b/tests/loners/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..515a6f93b424 --- /dev/null +++ b/tests/loners/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,28 @@ +exports[`test loners.js 1`] = ` +"var o = { x: 5, y: \"jello\" }; +var z = o.z; +var export_o: { x: number; } = o; + +function f(u,v?):number { return u; } +var export_f: (u: number) => number = f; + +//exports = export_o; +module.exports = export_f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/loners/jsfmt.spec.js b/tests/loners/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/loners/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/loners/loners.js b/tests/loners/loners.js new file mode 100644 index 000000000000..291e2a8398a6 --- /dev/null +++ b/tests/loners/loners.js @@ -0,0 +1,9 @@ +var o = { x: 5, y: "jello" }; +var z = o.z; +var export_o: { x: number; } = o; + +function f(u,v?):number { return u; } +var export_f: (u: number) => number = f; + +//exports = export_o; +module.exports = export_f; diff --git a/tests/method_properties/__snapshots__/jsfmt.spec.js.snap b/tests/method_properties/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a4401005ba39 --- /dev/null +++ b/tests/method_properties/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,74 @@ +exports[`test exports_optional_prop.js 1`] = ` +"// @flow + +declare class Foo { + bar?: () => string +} + +export {Foo}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"class C { + C() { } + foo() { } + static bar() { } + qux() { this.constructor.x; } +} +C.x; +(new C).foo.x; +C.bar.x; + +import {Foo} from \'./exports_optional_prop\'; +const foo = new Foo(); +(foo.bar(): string); // error, could be undefined + +function f(x) { + (x.bar(): string); // error. caused by \`f(foo)\`; annotate x to track it down. +} +f(foo); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + C() { + + } + foo() { + + } + bar() { + + } + qux() { + this.constructor.x; + } +} +C.x; +new C().foo.x; +C.bar.x; +import { Foo } from \"./exports_optional_prop\"; +const foo = new Foo(); +(foo.bar(): string);// error, could be undefined +function f(x) { + (x.bar(): string);// error. caused by \`f(foo)\`; annotate x to track it down. +} +f(foo); + +" +`; diff --git a/tests/method_properties/exports_optional_prop.js b/tests/method_properties/exports_optional_prop.js new file mode 100644 index 000000000000..b1eedca746eb --- /dev/null +++ b/tests/method_properties/exports_optional_prop.js @@ -0,0 +1,7 @@ +// @flow + +declare class Foo { + bar?: () => string +} + +export {Foo}; diff --git a/tests/method_properties/jsfmt.spec.js b/tests/method_properties/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/method_properties/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/method_properties/test.js b/tests/method_properties/test.js new file mode 100644 index 000000000000..85fa157985ee --- /dev/null +++ b/tests/method_properties/test.js @@ -0,0 +1,18 @@ +class C { + C() { } + foo() { } + static bar() { } + qux() { this.constructor.x; } +} +C.x; +(new C).foo.x; +C.bar.x; + +import {Foo} from './exports_optional_prop'; +const foo = new Foo(); +(foo.bar(): string); // error, could be undefined + +function f(x) { + (x.bar(): string); // error. caused by `f(foo)`; annotate x to track it down. +} +f(foo); diff --git a/tests/misc/A.js b/tests/misc/A.js new file mode 100644 index 000000000000..4e79aacb8bcf --- /dev/null +++ b/tests/misc/A.js @@ -0,0 +1,14 @@ + +/* @providesModule A */ + +module.exports = {}; + +var A = {x:true, ...{}}; +module.exports.cls = A; + +function f(x:boolean) { } +module.exports.fn = f; + +A.y = "?"; +A.x = A.y; +f(A.x); // A.x is now a string, by def assign diff --git a/tests/misc/B.js b/tests/misc/B.js new file mode 100644 index 000000000000..aa0fdbe1e8fe --- /dev/null +++ b/tests/misc/B.js @@ -0,0 +1,15 @@ + +/* @providesModule B */ + +var A = require('A').cls; + +function B() { + this.b = "..."; +} + +function f():number { return this.b; } + +B.prototype.s = 0; +B.prototype.fn = f; + +module.exports = B; diff --git a/tests/misc/C.js b/tests/misc/C.js new file mode 100644 index 000000000000..b882007e2382 --- /dev/null +++ b/tests/misc/C.js @@ -0,0 +1,14 @@ + +/* @providesModule C */ + +var B = require('B'); +var f = require('A').fn; + +function C() { + var o = new B(); + f(o.b); + f(o.s); + o.fn(); +} + +module.exports = C; diff --git a/tests/misc/D.js b/tests/misc/D.js new file mode 100644 index 000000000000..1caac58291a1 --- /dev/null +++ b/tests/misc/D.js @@ -0,0 +1,14 @@ + +/* @providesModule D */ + +var f = require('A').fn; + +function g():string { return this.i; } + +var o = {fn: g, ...{}}; +o.i = true; + +var i = o.fn(); +f(i); + +module.exports = "D for dummy"; diff --git a/tests/misc/E.js b/tests/misc/E.js new file mode 100644 index 000000000000..eddef9ab0577 --- /dev/null +++ b/tests/misc/E.js @@ -0,0 +1,10 @@ + +/* @providesModule E */ + +function h(x:number) { } +var proto = { fn: h } + +var o = Object.create(proto); +o.fn(false); + +module.exports = {obj: o}; diff --git a/tests/misc/F.js b/tests/misc/F.js new file mode 100644 index 000000000000..0e389f461181 --- /dev/null +++ b/tests/misc/F.js @@ -0,0 +1,6 @@ +function fn2(x) { return x.length * 4; } +fn2({length: 'hi'}); + +function foo(x: Array): string { + return x.length; +} diff --git a/tests/misc/G.js b/tests/misc/G.js new file mode 100644 index 000000000000..d27c2932240f --- /dev/null +++ b/tests/misc/G.js @@ -0,0 +1,7 @@ +var a = { length: "duck" }; +a.length = 123; +a.length(); + +var b = [ 123 ]; +b.length = "duck"; +b.length(); diff --git a/tests/misc/__snapshots__/jsfmt.spec.js.snap b/tests/misc/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6e97a6f0692a --- /dev/null +++ b/tests/misc/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,191 @@ +exports[`test A.js 1`] = ` +" +/* @providesModule A */ + +module.exports = {}; + +var A = {x:true, ...{}}; +module.exports.cls = A; + +function f(x:boolean) { } +module.exports.fn = f; + +A.y = \"?\"; +A.x = A.y; +f(A.x); // A.x is now a string, by def assign +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule A */ +module.exports = {}; +var A = { x: true, ...{} }; +module.exports.cls = A; +function f(x: boolean) { + +} +module.exports.fn = f; +A.y = \"?\"; +A.x = A.y; +f(A.x);// A.x is now a string, by def assign + +" +`; + +exports[`test B.js 1`] = ` +" +/* @providesModule B */ + +var A = require(\'A\').cls; + +function B() { + this.b = \"...\"; +} + +function f():number { return this.b; } + +B.prototype.s = 0; +B.prototype.fn = f; + +module.exports = B; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule B */ +var A = require(\"A\").cls; +function B() { + this.b = \"...\"; +} +function f(): number { + return this.b; +} +B.prototype.s = 0; +B.prototype.fn = f; +module.exports = B; + +" +`; + +exports[`test C.js 1`] = ` +" +/* @providesModule C */ + +var B = require(\'B\'); +var f = require(\'A\').fn; + +function C() { + var o = new B(); + f(o.b); + f(o.s); + o.fn(); +} + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule C */ +var B = require(\"B\"); +var f = require(\"A\").fn; +function C() { + var o = new B(); + f(o.b); + f(o.s); + o.fn(); +} +module.exports = C; + +" +`; + +exports[`test D.js 1`] = ` +" +/* @providesModule D */ + +var f = require(\'A\').fn; + +function g():string { return this.i; } + +var o = {fn: g, ...{}}; +o.i = true; + +var i = o.fn(); +f(i); + +module.exports = \"D for dummy\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule D */ +var f = require(\"A\").fn; +function g(): string { + return this.i; +} +var o = { fn: g, ...{} }; +o.i = true; +var i = o.fn(); +f(i); +module.exports = \"D for dummy\"; + +" +`; + +exports[`test E.js 1`] = ` +" +/* @providesModule E */ + +function h(x:number) { } +var proto = { fn: h } + +var o = Object.create(proto); +o.fn(false); + +module.exports = {obj: o}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule E */ +function h(x: number) { + +} +var proto = { fn: h }; +var o = Object.create(proto); +o.fn(false); +module.exports = { obj: o }; + +" +`; + +exports[`test F.js 1`] = ` +"function fn2(x) { return x.length * 4; } +fn2({length: \'hi\'}); + +function foo(x: Array): string { + return x.length; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test G.js 1`] = ` +"var a = { length: \"duck\" }; +a.length = 123; +a.length(); + +var b = [ 123 ]; +b.length = \"duck\"; +b.length(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a = { length: \"duck\" }; +a.length = 123; +a.length(); +var b = [ 123 ]; +b.length = \"duck\"; +b.length(); + +" +`; diff --git a/tests/misc/jsfmt.spec.js b/tests/misc/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/misc/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/missing_annotation/__snapshots__/jsfmt.spec.js.snap b/tests/missing_annotation/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9bb7d0b1529a --- /dev/null +++ b/tests/missing_annotation/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,107 @@ +exports[`test array.js 1`] = ` +"// @flow + +type Foo = {}; +var f: Foo = {}; +export var arr = [f]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type Foo = {}; +var f: Foo = {}; +export var arr = [ f ]; + +" +`; + +exports[`test async_return.js 1`] = ` +"// @flow + +export async function foo() { + return 123; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export async function foo() { + return 123; +} + +" +`; + +exports[`test infer.js 1`] = ` +"/* @flow */ + +var Foo = { + a: function(arg) { // missing arg annotation + return arg; + }, + + b: function(arg) { // missing arg annotation + return { + bar: arg + }; + }, + + c: function(arg: string) { // no return annotation required + return { + bar: arg + }; + }, + + d: function(arg: string): { + bar: string + } { + return { + bar: arg + }; + }, + + // return type annotation may be omitted, but if so, input positions on + // observed return type (e.g. param types in a function type) must come + // from annotations + e: function(arg: string) { + return function(x) { // missing param annotation + return x; + } + }, + + // ...if the return type is annotated explicitly, this is unnecessary + f: function(arg: string): (x:number) => number { + return function(x) { // no error + return x; + } + } + +}; + +var Bar = { + a: Foo.a(\'Foo\'), // no annotation required + + // object property types are inferred, so make sure that this doesn\'t cause + // us to also infer the parameter\'s type. + b: Foo.b(\'bar\'), // no annotation required + + c: Foo.c(\'bar\'), // no annotation required + + d: Foo.d(\'bar\'), // no annotation required +}; + +module.exports = Foo, Bar; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/missing_annotation/array.js b/tests/missing_annotation/array.js new file mode 100644 index 000000000000..4c90d239d23d --- /dev/null +++ b/tests/missing_annotation/array.js @@ -0,0 +1,5 @@ +// @flow + +type Foo = {}; +var f: Foo = {}; +export var arr = [f]; diff --git a/tests/missing_annotation/async_return.js b/tests/missing_annotation/async_return.js new file mode 100644 index 000000000000..1d533f773651 --- /dev/null +++ b/tests/missing_annotation/async_return.js @@ -0,0 +1,5 @@ +// @flow + +export async function foo() { + return 123; +} diff --git a/tests/missing_annotation/infer.js b/tests/missing_annotation/infer.js new file mode 100644 index 000000000000..d3827d4e03ff --- /dev/null +++ b/tests/missing_annotation/infer.js @@ -0,0 +1,58 @@ +/* @flow */ + +var Foo = { + a: function(arg) { // missing arg annotation + return arg; + }, + + b: function(arg) { // missing arg annotation + return { + bar: arg + }; + }, + + c: function(arg: string) { // no return annotation required + return { + bar: arg + }; + }, + + d: function(arg: string): { + bar: string + } { + return { + bar: arg + }; + }, + + // return type annotation may be omitted, but if so, input positions on + // observed return type (e.g. param types in a function type) must come + // from annotations + e: function(arg: string) { + return function(x) { // missing param annotation + return x; + } + }, + + // ...if the return type is annotated explicitly, this is unnecessary + f: function(arg: string): (x:number) => number { + return function(x) { // no error + return x; + } + } + +}; + +var Bar = { + a: Foo.a('Foo'), // no annotation required + + // object property types are inferred, so make sure that this doesn't cause + // us to also infer the parameter's type. + b: Foo.b('bar'), // no annotation required + + c: Foo.c('bar'), // no annotation required + + d: Foo.d('bar'), // no annotation required +}; + +module.exports = Foo, Bar; diff --git a/tests/missing_annotation/jsfmt.spec.js b/tests/missing_annotation/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/missing_annotation/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/modified_lib/__snapshots__/jsfmt.spec.js.snap b/tests/modified_lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..eabf387fb4aa --- /dev/null +++ b/tests/modified_lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,13 @@ +exports[`test test.js 1`] = ` +"// @flow + +import {bar} from 'foo'; + +bar(5); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { bar } from "foo"; +bar(5); + +" +`; diff --git a/tests/modified_lib/jsfmt.spec.js b/tests/modified_lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/modified_lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/modified_lib/lib/__snapshots__/jsfmt.spec.js.snap b/tests/modified_lib/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..83927dd4b0ac --- /dev/null +++ b/tests/modified_lib/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test lib.js 1`] = ` +"declare module \'foo\' { + declare function bar(str: string): number; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/modified_lib/lib/jsfmt.spec.js b/tests/modified_lib/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/modified_lib/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/modified_lib/lib/lib.js b/tests/modified_lib/lib/lib.js new file mode 100644 index 000000000000..fcb3b4a27b45 --- /dev/null +++ b/tests/modified_lib/lib/lib.js @@ -0,0 +1,3 @@ +declare module 'foo' { + declare function bar(str: string): number; +} diff --git a/tests/modified_lib/test.js b/tests/modified_lib/test.js new file mode 100644 index 000000000000..d889dc83ca19 --- /dev/null +++ b/tests/modified_lib/test.js @@ -0,0 +1,5 @@ +// @flow + +import {bar} from 'foo'; + +bar(5); diff --git a/tests/module_not_found_errors/src/__snapshots__/jsfmt.spec.js.snap b/tests/module_not_found_errors/src/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7ec34361073b --- /dev/null +++ b/tests/module_not_found_errors/src/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test index.js 1`] = ` +"// @flow + +require('module_completely_absent'); + +// node_modules/module_outside_of_root/ sits outside of the Flow project root. +// Flow should give a descriptive error about this +require('module_outside_of_root'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +require("module_completely_absent"); +// node_modules/module_outside_of_root/ sits outside of the Flow project root. +// Flow should give a descriptive error about this +require("module_outside_of_root"); + +" +`; diff --git a/tests/module_not_found_errors/src/index.js b/tests/module_not_found_errors/src/index.js new file mode 100644 index 000000000000..f4e259cbbd87 --- /dev/null +++ b/tests/module_not_found_errors/src/index.js @@ -0,0 +1,7 @@ +// @flow + +require('module_completely_absent'); + +// node_modules/module_outside_of_root/ sits outside of the Flow project root. +// Flow should give a descriptive error about this +require('module_outside_of_root'); diff --git a/tests/module_not_found_errors/src/jsfmt.spec.js b/tests/module_not_found_errors/src/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/module_not_found_errors/src/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/module_redirect/A.js b/tests/module_redirect/A.js new file mode 100644 index 000000000000..d2f6a26c0d93 --- /dev/null +++ b/tests/module_redirect/A.js @@ -0,0 +1,3 @@ +declare module A { + declare function foo(): string; +} diff --git a/tests/module_redirect/B.js b/tests/module_redirect/B.js new file mode 100644 index 000000000000..02b47f2182c0 --- /dev/null +++ b/tests/module_redirect/B.js @@ -0,0 +1,6 @@ +/** + * @providesModule B + * @flow + */ + +module.exports = require('A'); diff --git a/tests/module_redirect/C.js b/tests/module_redirect/C.js new file mode 100644 index 000000000000..04871ce2a640 --- /dev/null +++ b/tests/module_redirect/C.js @@ -0,0 +1,6 @@ +/** + * @providesModule C + * @flow + */ + +module.exports = require('B'); diff --git a/tests/module_redirect/D.js b/tests/module_redirect/D.js new file mode 100644 index 000000000000..dc166b39d33c --- /dev/null +++ b/tests/module_redirect/D.js @@ -0,0 +1,8 @@ +/** + * @providesModule D + * @flow + */ + +var bar1: string = require('A'); +var bar2: string = require('B'); +var bar3: string = require('C'); diff --git a/tests/module_redirect/__snapshots__/jsfmt.spec.js.snap b/tests/module_redirect/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5d49329b0caa --- /dev/null +++ b/tests/module_redirect/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,77 @@ +exports[`test A.js 1`] = ` +"declare module A { + declare function foo(): string; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test B.js 1`] = ` +"/** + * @providesModule B + * @flow + */ + +module.exports = require(\'A\'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule B + * @flow + */ +module.exports = require(\"A\"); + +" +`; + +exports[`test C.js 1`] = ` +"/** + * @providesModule C + * @flow + */ + +module.exports = require(\'B\'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule C + * @flow + */ +module.exports = require(\"B\"); + +" +`; + +exports[`test D.js 1`] = ` +"/** + * @providesModule D + * @flow + */ + +var bar1: string = require(\'A\'); +var bar2: string = require(\'B\'); +var bar3: string = require(\'C\'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule D + * @flow + */ +var bar1: string = require(\"A\"); +var bar2: string = require(\"B\"); +var bar3: string = require(\"C\"); + +" +`; diff --git a/tests/module_redirect/jsfmt.spec.js b/tests/module_redirect/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/module_redirect/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/module_use_strict/__snapshots__/jsfmt.spec.js.snap b/tests/module_use_strict/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..dbd713f36296 --- /dev/null +++ b/tests/module_use_strict/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test test.js 1`] = ` +"// @flow + +(01: number); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Invalid number (3:1) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.readNumber (/node_modules/babylon/lib/index.js:1180:12) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1020:21) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) +" +`; diff --git a/tests/module_use_strict/jsfmt.spec.js b/tests/module_use_strict/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/module_use_strict/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/module_use_strict/test.js b/tests/module_use_strict/test.js new file mode 100644 index 000000000000..9fcda932e9f9 --- /dev/null +++ b/tests/module_use_strict/test.js @@ -0,0 +1,3 @@ +// @flow + +(01: number); diff --git a/tests/modules/__snapshots__/jsfmt.spec.js.snap b/tests/modules/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..748288f7203b --- /dev/null +++ b/tests/modules/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,53 @@ +exports[`test cli.js 1`] = ` +"/* @flow */ + +var f = require('./lib'); + +var y:number = f(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var f = require("./lib"); +var y: number = f(0); + +" +`; + +exports[`test cli2.js 1`] = ` +"/* @flow */ + +var f = require('./lib'); + +f("..."); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var f = require("./lib"); +f("..."); + +" +`; + +exports[`test lib.js 1`] = ` +"/* @flow */ + +function g(x:string) { } + +//function f(x) { g(x); return x; } +//function f(x:number) { g(x); return x; } +function f(x:number):number { g(x); return x; } + +module.exports = f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function g(x: string) { + +} +//function f(x) { g(x); return x; } +//function f(x:number) { g(x); return x; } +function f(x: number): number { + g(x); + return x; +} +module.exports = f; + +" +`; diff --git a/tests/modules/cli.js b/tests/modules/cli.js new file mode 100644 index 000000000000..5c3529d4b6d1 --- /dev/null +++ b/tests/modules/cli.js @@ -0,0 +1,5 @@ +/* @flow */ + +var f = require('./lib'); + +var y:number = f(0); diff --git a/tests/modules/cli2.js b/tests/modules/cli2.js new file mode 100644 index 000000000000..f69b2cbe901e --- /dev/null +++ b/tests/modules/cli2.js @@ -0,0 +1,5 @@ +/* @flow */ + +var f = require('./lib'); + +f("..."); diff --git a/tests/modules/jsfmt.spec.js b/tests/modules/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/modules/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/modules/lib.js b/tests/modules/lib.js new file mode 100644 index 000000000000..f37c923f472a --- /dev/null +++ b/tests/modules/lib.js @@ -0,0 +1,9 @@ +/* @flow */ + +function g(x:string) { } + +//function f(x) { g(x); return x; } +//function f(x:number) { g(x); return x; } +function f(x:number):number { g(x); return x; } + +module.exports = f; diff --git a/tests/more_annot/__snapshots__/jsfmt.spec.js.snap b/tests/more_annot/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..eeb440765656 --- /dev/null +++ b/tests/more_annot/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,81 @@ +exports[`test client_object.js 1`] = ` +"var o = require(\'./object\'); + +var a:number = o.w.z.y; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = require(\"./object\"); +var a: number = o.w.z.y; + +" +`; + +exports[`test object.js 1`] = ` +"var o1 = { x: 0, y: \"\" }; +var o2 = { z: o1 } + +var o3 = {}; +o3.w = o2; + +//declare var exports: { w: any }; + +module.exports = o3; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o1 = { x: 0, y: \"\" }; +var o2 = { z: o1 }; +var o3 = {}; +o3.w = o2; +//declare var exports: { w: any }; +module.exports = o3; + +" +`; + +exports[`test proto.js 1`] = ` +"function Foo() { this.x = 0; } +Foo.prototype.m = function() { } + +var o1: { x: number; m(): void } = new Foo(); + +var o2: Foo = new Foo(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test super.js 1`] = ` +"class C { m() { } } +class D extends C { } + +var d: { +m: () => void } = new D(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/more_annot/client_object.js b/tests/more_annot/client_object.js new file mode 100644 index 000000000000..2a657fc3150a --- /dev/null +++ b/tests/more_annot/client_object.js @@ -0,0 +1,3 @@ +var o = require('./object'); + +var a:number = o.w.z.y; diff --git a/tests/more_annot/jsfmt.spec.js b/tests/more_annot/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/more_annot/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/more_annot/object.js b/tests/more_annot/object.js new file mode 100644 index 000000000000..db079d67aa3b --- /dev/null +++ b/tests/more_annot/object.js @@ -0,0 +1,9 @@ +var o1 = { x: 0, y: "" }; +var o2 = { z: o1 } + +var o3 = {}; +o3.w = o2; + +//declare var exports: { w: any }; + +module.exports = o3; diff --git a/tests/more_annot/proto.js b/tests/more_annot/proto.js new file mode 100644 index 000000000000..6baaa16ea640 --- /dev/null +++ b/tests/more_annot/proto.js @@ -0,0 +1,6 @@ +function Foo() { this.x = 0; } +Foo.prototype.m = function() { } + +var o1: { x: number; m(): void } = new Foo(); + +var o2: Foo = new Foo(); diff --git a/tests/more_annot/super.js b/tests/more_annot/super.js new file mode 100644 index 000000000000..de7d6a2b30e4 --- /dev/null +++ b/tests/more_annot/super.js @@ -0,0 +1,4 @@ +class C { m() { } } +class D extends C { } + +var d: { +m: () => void } = new D(); diff --git a/tests/more_classes/Bar.js b/tests/more_classes/Bar.js new file mode 100644 index 000000000000..dc757801ca4a --- /dev/null +++ b/tests/more_classes/Bar.js @@ -0,0 +1,20 @@ + +/* @providesModule Bar */ + +var Qux = require('Qux'); + +class Bar { + y:number; + self:Bar; + constructor(y:number) { + this.y = y; + this.self = this; + } + + bar(z:string,u:string):string { + new Qux().w = "?"; + return z; + } +} + +module.exports = Bar; diff --git a/tests/more_classes/Foo.js b/tests/more_classes/Foo.js new file mode 100644 index 000000000000..7def23ebcea1 --- /dev/null +++ b/tests/more_classes/Foo.js @@ -0,0 +1,26 @@ + +/* @providesModule Foo */ + +var Bar = require('Bar'); +var Qux = require('Qux'); + +class Foo extends Qux { + x:string; + constructor(x:string) { + this.x = x; + } + + foo(y:string,z):number { + this.x = y; + var u = new Foo("...").qux(); + var v = new Bar(y); + v.self = v; + return v.bar(z,u); + } + + fooqux(x:string) { + this.x; + } +} + +module.exports = Foo; diff --git a/tests/more_classes/Qux.js b/tests/more_classes/Qux.js new file mode 100644 index 000000000000..dae3dfeb102d --- /dev/null +++ b/tests/more_classes/Qux.js @@ -0,0 +1,12 @@ + +/* @providesModule Qux */ + +class Qux { + w:number; + + qux() { return this.w; } + + fooqux(x:number) { } +} + +module.exports = Qux; diff --git a/tests/more_classes/__snapshots__/jsfmt.spec.js.snap b/tests/more_classes/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c5442e72127e --- /dev/null +++ b/tests/more_classes/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,121 @@ +exports[`test Bar.js 1`] = ` +" +/* @providesModule Bar */ + +var Qux = require('Qux'); + +class Bar { + y:number; + self:Bar; + constructor(y:number) { + this.y = y; + this.self = this; + } + + bar(z:string,u:string):string { + new Qux().w = "?"; + return z; + } +} + +module.exports = Bar; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Bar */ +var Qux = require("Qux"); +class Bar { + y: number; + self: Bar; + constructor(y: number) { + this.y = y; + this.self = this; + } + bar(z: string, u: string): string { + new Qux().w = "?"; + return z; + } +} +module.exports = Bar; + +" +`; + +exports[`test Foo.js 1`] = ` +" +/* @providesModule Foo */ + +var Bar = require('Bar'); +var Qux = require('Qux'); + +class Foo extends Qux { + x:string; + constructor(x:string) { + this.x = x; + } + + foo(y:string,z):number { + this.x = y; + var u = new Foo("...").qux(); + var v = new Bar(y); + v.self = v; + return v.bar(z,u); + } + + fooqux(x:string) { + this.x; + } +} + +module.exports = Foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Foo */ +var Bar = require("Bar"); +var Qux = require("Qux"); +class Foo extends Qux { + x: string; + constructor(x: string) { + this.x = x; + } + foo(y: string, z): number { + this.x = y; + var u = new Foo("...").qux(); + var v = new Bar(y); + v.self = v; + return v.bar(z, u); + } + fooqux(x: string) { + this.x; + } +} +module.exports = Foo; + +" +`; + +exports[`test Qux.js 1`] = ` +" +/* @providesModule Qux */ + +class Qux { + w:number; + + qux() { return this.w; } + + fooqux(x:number) { } +} + +module.exports = Qux; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Qux */ +class Qux { + w: number; + qux() { + return this.w; + } + fooqux(x: number) { + + } +} +module.exports = Qux; + +" +`; diff --git a/tests/more_classes/jsfmt.spec.js b/tests/more_classes/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/more_classes/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/more_generics/__snapshots__/jsfmt.spec.js.snap b/tests/more_generics/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6d6ddfc3331d --- /dev/null +++ b/tests/more_generics/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,48 @@ +exports[`test poly.js 1`] = ` +"var foo1 = function(x:T):T { return x; } + +function foo2(x:T):S { return x; } + +var foo3 = function (x:T):T { return foo3(x); } + +function foo4(x:T):S { return foo4(x); } + +var x = []; +function foo5():Array { return x; } +/* + var a = foo5(); + a[0] = 0; + var b = foo5(); + var y: string = b[0]; +*/ + +var foo6 = function(x:R):R { return foo1(x); } + +function foo7(x:R):R { return foo5(); } + +function foo8(x:U,y):U { + var z = foo8(x,x); + y(); + return x; +} +/* + foo8(0,void 0); +*/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/more_generics/jsfmt.spec.js b/tests/more_generics/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/more_generics/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/more_generics/poly.js b/tests/more_generics/poly.js new file mode 100644 index 000000000000..dc0e5465bc93 --- /dev/null +++ b/tests/more_generics/poly.js @@ -0,0 +1,29 @@ +var foo1 = function(x:T):T { return x; } + +function foo2(x:T):S { return x; } + +var foo3 = function (x:T):T { return foo3(x); } + +function foo4(x:T):S { return foo4(x); } + +var x = []; +function foo5():Array { return x; } +/* + var a = foo5(); + a[0] = 0; + var b = foo5(); + var y: string = b[0]; +*/ + +var foo6 = function(x:R):R { return foo1(x); } + +function foo7(x:R):R { return foo5(); } + +function foo8(x:U,y):U { + var z = foo8(x,x); + y(); + return x; +} +/* + foo8(0,void 0); +*/ diff --git a/tests/more_path/Condition.js b/tests/more_path/Condition.js new file mode 100644 index 000000000000..3fbf99d6f1ff --- /dev/null +++ b/tests/more_path/Condition.js @@ -0,0 +1,57 @@ +/* @providesModule Condition */ + +function f(x:number) { } +function g() { return (42 || "hello"); } + +var x = g(); +if (typeof x === "string") { + x = 0; +} +f(x); + +class A {} +function h() { return (42 || new A()); } + +var y = h(); +if (y instanceof A) { + y = 0; +} +//f(y); + +function bar() { return true; } + +class C { qux() { } } + +function foo() { + + var c = "..."; + c = new C(); + if (bar()) { + c.qux(); + } + +} + +function goofy() { + var x = g(); + if (typeof x == 'function') { + x(); + } else { // if (typeof x == 'number') { + //f(x); + } +} + +function goofy2() { + var o = {x : 0} + if (typeof o.x == 'function') { + o.x(); + } + var y = o.x; + if (typeof y == 'function') { + y(); + } else { + //f(y); + } +} + +module.exports = true; diff --git a/tests/more_path/FlowSA.js b/tests/more_path/FlowSA.js new file mode 100644 index 000000000000..51aa51ff367a --- /dev/null +++ b/tests/more_path/FlowSA.js @@ -0,0 +1,12 @@ + +/* @providesModule FlowSA */ + +function check(x:string) { } + +function FlowSA() { + var x = 0; + x = "..."; + check(x); +} + +module.exports = FlowSA; diff --git a/tests/more_path/Sigma.js b/tests/more_path/Sigma.js new file mode 100644 index 000000000000..c5c871de1e29 --- /dev/null +++ b/tests/more_path/Sigma.js @@ -0,0 +1,40 @@ + +/* @providesModule Sigma */ + +class A { a() {} } + +class B extends A { b() {} } + +class C extends B { c() {} } + +function bar(x:B) { + if (x instanceof A) { + x.a(); + x.c(); // error + } else { + x++; // TODO no error? since unreachable (x: B implies x: A) + } +} + +function foo(x:A) { + if (x instanceof C) { + x.a(); + x.b(); + x.c(); + x.d(); // error + } else { + x.a(); + x.c(); // error + } +} + + +class D { d() {} } + +function baz(x:D) { + if (x instanceof A) { + // unreachable, TODO: this shouldn't throw + } +} + +module.exports = "sigma"; diff --git a/tests/more_path/__snapshots__/jsfmt.spec.js.snap b/tests/more_path/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..882f81ebf68b --- /dev/null +++ b/tests/more_path/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,271 @@ +exports[`test Condition.js 1`] = ` +"/* @providesModule Condition */ + +function f(x:number) { } +function g() { return (42 || "hello"); } + +var x = g(); +if (typeof x === "string") { + x = 0; +} +f(x); + +class A {} +function h() { return (42 || new A()); } + +var y = h(); +if (y instanceof A) { + y = 0; +} +//f(y); + +function bar() { return true; } + +class C { qux() { } } + +function foo() { + + var c = "..."; + c = new C(); + if (bar()) { + c.qux(); + } + +} + +function goofy() { + var x = g(); + if (typeof x == 'function') { + x(); + } else { // if (typeof x == 'number') { + //f(x); + } +} + +function goofy2() { + var o = {x : 0} + if (typeof o.x == 'function') { + o.x(); + } + var y = o.x; + if (typeof y == 'function') { + y(); + } else { + //f(y); + } +} + +module.exports = true; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Condition */ +function f(x: number) { + +} +function g() { + return 42 || "hello"; +} +var x = g(); +if (typeof x === "string") { + x = 0; +} +f(x); +class A {} +function h() { + return 42 || new A(); +} +var y = h(); +if (y instanceof A) { + y = 0; +} +//f(y); +function bar() { + return true; +} +class C { + qux() { + + } +} +function foo() { + var c = "..."; + c = new C(); + if (bar()) { + c.qux(); + } +} +function goofy() { + var x = g(); + if (typeof x == "function") { + x(); + } else { + + } +} +function goofy2() { + var o = { x: 0 }; + if (typeof o.x == "function") { + o.x(); + } + var y = o.x; + if (typeof y == "function") { + y(); + } else { + + } +} +module.exports = true; + +" +`; + +exports[`test FlowSA.js 1`] = ` +" +/* @providesModule FlowSA */ + +function check(x:string) { } + +function FlowSA() { + var x = 0; + x = "..."; + check(x); +} + +module.exports = FlowSA; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule FlowSA */ +function check(x: string) { + +} +function FlowSA() { + var x = 0; + x = "..."; + check(x); +} +module.exports = FlowSA; + +" +`; + +exports[`test Sigma.js 1`] = ` +" +/* @providesModule Sigma */ + +class A { a() {} } + +class B extends A { b() {} } + +class C extends B { c() {} } + +function bar(x:B) { + if (x instanceof A) { + x.a(); + x.c(); // error + } else { + x++; // TODO no error? since unreachable (x: B implies x: A) + } +} + +function foo(x:A) { + if (x instanceof C) { + x.a(); + x.b(); + x.c(); + x.d(); // error + } else { + x.a(); + x.c(); // error + } +} + + +class D { d() {} } + +function baz(x:D) { + if (x instanceof A) { + // unreachable, TODO: this shouldn't throw + } +} + +module.exports = "sigma"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Sigma */ +class A { + a() { + + } +} +class B extends A { + b() { + + } +} +class C extends B { + c() { + + } +} +function bar(x: B) { + if (x instanceof A) { + x.a(); + x.c();// error + } else { + x++;// TODO no error? since unreachable (x: B implies x: A) + } +} +function foo(x: A) { + if (x instanceof C) { + x.a(); + x.b(); + x.c(); + x.d();// error + } else { + x.a(); + x.c();// error + } +} +class D { + d() { + + } +} +function baz(x: D) { + if (x instanceof A) { + + } +} +module.exports = "sigma"; + +" +`; + +exports[`test test.js 1`] = ` +"class BaseClass { + baseProp: string; +} + +class ChildClass extends BaseClass { + childProp: string; +} + +function test(obj: BaseClass): string { + if (obj instanceof ChildClass) { + return obj.childProp_TYPO; // error (obj: ChildClass) + } + return obj.baseProp; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class BaseClass { + baseProp: string; +} +class ChildClass extends BaseClass { + childProp: string; +} +function test(obj: BaseClass): string { + if (obj instanceof ChildClass) { + return obj.childProp_TYPO;// error (obj: ChildClass) + } + return obj.baseProp; +} + +" +`; diff --git a/tests/more_path/jsfmt.spec.js b/tests/more_path/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/more_path/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/more_path/test.js b/tests/more_path/test.js new file mode 100644 index 000000000000..e54e1def4d8d --- /dev/null +++ b/tests/more_path/test.js @@ -0,0 +1,14 @@ +class BaseClass { + baseProp: string; +} + +class ChildClass extends BaseClass { + childProp: string; +} + +function test(obj: BaseClass): string { + if (obj instanceof ChildClass) { + return obj.childProp_TYPO; // error (obj: ChildClass) + } + return obj.baseProp; +} diff --git a/tests/more_react/API.react.js b/tests/more_react/API.react.js new file mode 100644 index 000000000000..1cb0cafd8bcd --- /dev/null +++ b/tests/more_react/API.react.js @@ -0,0 +1,8 @@ + +var app = require('JSX'); + +app.setProps({y:42}); // error, y:number but foo expects string in App.react +app.setState({z:42}); // error, z:number but foo expects string in App.react + +function bar(x:number) { } +bar(app.props.children); // No error, App doesn't specify propTypes so anything goes diff --git a/tests/more_react/App.react.js b/tests/more_react/App.react.js new file mode 100644 index 000000000000..9121b661cd2b --- /dev/null +++ b/tests/more_react/App.react.js @@ -0,0 +1,43 @@ + +/** + * @providesModule App.react + * @jsx React.DOM + */ + +var React = require('react'); + +// expect args to be strings +function foo(p:string,q:string):string { return p+q; } + +var App = React.createClass({ + + getDefaultProps: function(): { y: string } { + return {y:""}; // infer props.y: string + }, + + getInitialState: function() { + return {z:0}; // infer state.z: number + }, + + handler: function() { + this.setState({z:42}); // ok + }, + + render: function() { + var x = this.props.x; + var y = this.props.y; + var z = this.state.z; + + //this.state; + + return ( +
+ {foo(x,y)} + {foo(z,x)} // error, since z: number +
+ ); + } + +}); + +module.exports = App; diff --git a/tests/more_react/JSX.js b/tests/more_react/JSX.js new file mode 100644 index 000000000000..68a256f9c3e7 --- /dev/null +++ b/tests/more_react/JSX.js @@ -0,0 +1,12 @@ + +/* @providesModule JSX */ + +var React = require('react'); +var App = require('App.react'); + +var app = + // error, y: number but foo expects string in App.react + Some text. + ; + +module.exports = app; diff --git a/tests/more_react/__snapshots__/jsfmt.spec.js.snap b/tests/more_react/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d749aeba2738 --- /dev/null +++ b/tests/more_react/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,160 @@ +exports[`test API.react.js 1`] = ` +" +var app = require('JSX'); + +app.setProps({y:42}); // error, y:number but foo expects string in App.react +app.setState({z:42}); // error, z:number but foo expects string in App.react + +function bar(x:number) { } +bar(app.props.children); // No error, App doesn't specify propTypes so anything goes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var app = require("JSX"); +app.setProps({ y: 42 });// error, y:number but foo expects string in App.react +app.setState({ z: 42 });// error, z:number but foo expects string in App.react +function bar(x: number) { + +} +bar( + app.props.children +);// No error, App doesn't specify propTypes so anything goes + +" +`; + +exports[`test App.react.js 1`] = ` +" +/** + * @providesModule App.react + * @jsx React.DOM + */ + +var React = require('react'); + +// expect args to be strings +function foo(p:string,q:string):string { return p+q; } + +var App = React.createClass({ + + getDefaultProps: function(): { y: string } { + return {y:""}; // infer props.y: string + }, + + getInitialState: function() { + return {z:0}; // infer state.z: number + }, + + handler: function() { + this.setState({z:42}); // ok + }, + + render: function() { + var x = this.props.x; + var y = this.props.y; + var z = this.state.z; + + //this.state; + + return ( +
+ {foo(x,y)} + {foo(z,x)} // error, since z: number +
+ ); + } + +}); + +module.exports = App; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule App.react + * @jsx React.DOM + */ +var React = require("react"); +// expect args to be strings +function foo(p: string, q: string): string { + return p + q; +} +var App = React.createClass({ + getDefaultProps: function(): { y: string } { + return { y: "" };// infer props.y: string + }, + getInitialState: function() { + return { z: 0 };// infer state.z: number + }, + handler: function() { + this.setState({ z: 42 });// ok + }, + render: function() { + var x = this.props.x; + var y = this.props.y; + var z = this.state.z; + //this.state; + return ( +
+ {foo(x, y)} + {foo(z, x)}// error, since z: number
+ ); + } +}); +module.exports = App; + +" +`; + +exports[`test JSX.js 1`] = ` +" +/* @providesModule JSX */ + +var React = require('react'); +var App = require('App.react'); + +var app = + // error, y: number but foo expects string in App.react + Some text. + ; + +module.exports = app; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule JSX */ +var React = require("react"); +var App = require("App.react"); +var app = // error, y: number but foo expects string in App.react[object Object] Some text.; +module.exports = app; + +" +`; + +exports[`test propTypes.js 1`] = ` +"var React = require('React'); + +var C = React.createClass({ + propTypes: { + title: React.PropTypes.string.isRequired, + } +}); +var D = React.createClass({ + propTypes: { + name: React.PropTypes.string.isRequired, + ...C.propTypes, + } +}); + +; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require("React"); +var C = React.createClass({ + propTypes: { title: React.PropTypes.string.isRequired } +}); +var D = React.createClass({ + propTypes: { name: React.PropTypes.string.isRequired, ...C.propTypes } +}); +; + +" +`; diff --git a/tests/more_react/jsfmt.spec.js b/tests/more_react/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/more_react/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/more_react/propTypes.js b/tests/more_react/propTypes.js new file mode 100644 index 000000000000..3bb8a2a05f60 --- /dev/null +++ b/tests/more_react/propTypes.js @@ -0,0 +1,18 @@ +var React = require('React'); + +var C = React.createClass({ + propTypes: { + title: React.PropTypes.string.isRequired, + } +}); +var D = React.createClass({ + propTypes: { + name: React.PropTypes.string.isRequired, + ...C.propTypes, + } +}); + +; diff --git a/tests/more_statics/__snapshots__/jsfmt.spec.js.snap b/tests/more_statics/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2496ab6a3ed1 --- /dev/null +++ b/tests/more_statics/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test class_static.js 1`] = ` +"class B { + static foo(): string { return ""; } +} + +class C extends B { + static bar(): string { return ""; } +} + +var x: number = C.bar(); +var y: number = C.foo(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class B { + foo(): string { + return ""; + } +} +class C extends B { + bar(): string { + return ""; + } +} +var x: number = C.bar(); +var y: number = C.foo(); + +" +`; diff --git a/tests/more_statics/class_static.js b/tests/more_statics/class_static.js new file mode 100644 index 000000000000..b66fb6dd07d5 --- /dev/null +++ b/tests/more_statics/class_static.js @@ -0,0 +1,10 @@ +class B { + static foo(): string { return ""; } +} + +class C extends B { + static bar(): string { return ""; } +} + +var x: number = C.bar(); +var y: number = C.foo(); diff --git a/tests/more_statics/jsfmt.spec.js b/tests/more_statics/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/more_statics/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/name_prop/__snapshots__/jsfmt.spec.js.snap b/tests/name_prop/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..87c5c721291c --- /dev/null +++ b/tests/name_prop/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,34 @@ +exports[`test class.js 1`] = ` +"class A {} + +var test1 = A.bar; // Error bar doesn't exist +var test2: string = A.name; +var test3: number = A.name; // Error string ~> number + +var a = new A(); +var test4 = a.constructor.bar; // Error bar doesn't exist +var test5: string = a.constructor.name; +var test6: number = a.constructor.name; // Error string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A {} +var test1 = A.bar;// Error bar doesn't exist +var test2: string = A.name; +var test3: number = A.name;// Error string ~> number +var a = new A(); +var test4 = a.constructor.bar;// Error bar doesn't exist +var test5: string = a.constructor.name; +var test6: number = a.constructor.name;// Error string ~> number + +" +`; + +exports[`test function.js 1`] = ` +"/* TODO - we currently say that a function's statics are an AnyObjT and + * anything goes. When we start enforcing the statics properly, we'll need to + * know that .name exists + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/name_prop/class.js b/tests/name_prop/class.js new file mode 100644 index 000000000000..0076d3e7af4c --- /dev/null +++ b/tests/name_prop/class.js @@ -0,0 +1,10 @@ +class A {} + +var test1 = A.bar; // Error bar doesn't exist +var test2: string = A.name; +var test3: number = A.name; // Error string ~> number + +var a = new A(); +var test4 = a.constructor.bar; // Error bar doesn't exist +var test5: string = a.constructor.name; +var test6: number = a.constructor.name; // Error string ~> number diff --git a/tests/name_prop/function.js b/tests/name_prop/function.js new file mode 100644 index 000000000000..304356168f1b --- /dev/null +++ b/tests/name_prop/function.js @@ -0,0 +1,4 @@ +/* TODO - we currently say that a function's statics are an AnyObjT and + * anything goes. When we start enforcing the statics properly, we'll need to + * know that .name exists + */ diff --git a/tests/name_prop/jsfmt.spec.js b/tests/name_prop/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/name_prop/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/namespace/__snapshots__/jsfmt.spec.js.snap b/tests/namespace/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6dc7580c8a6a --- /dev/null +++ b/tests/namespace/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,47 @@ +exports[`test client.js 1`] = ` +"var ns = require(\'./namespace\') + +var bar: string = ns.foo +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var ns = require(\"./namespace\"); +var bar: string = ns.foo; + +" +`; + +exports[`test namespace.js 1`] = ` +"/*@flow*/// import type { T } from \'...\' +type T = (x:number) => void; +var f: T = function(x:string): void { } + +type Map = (x:X) => Y; + +function bar(x:U, f:Map): V { + return f(x); +} + +var y:number = bar(0, x => \"\"); + +type Seq = number | Array; +var s1:Seq = [0,[0]]; +var s2:Seq = [[\"\"]]; + +module.exports = { foo: (\"\": number) }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/namespace/client.js b/tests/namespace/client.js new file mode 100644 index 000000000000..9ce64259134b --- /dev/null +++ b/tests/namespace/client.js @@ -0,0 +1,3 @@ +var ns = require('./namespace') + +var bar: string = ns.foo diff --git a/tests/namespace/jsfmt.spec.js b/tests/namespace/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/namespace/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/namespace/namespace.js b/tests/namespace/namespace.js new file mode 100644 index 000000000000..ab51ee36eae3 --- /dev/null +++ b/tests/namespace/namespace.js @@ -0,0 +1,17 @@ +/*@flow*/// import type { T } from '...' +type T = (x:number) => void; +var f: T = function(x:string): void { } + +type Map = (x:X) => Y; + +function bar(x:U, f:Map): V { + return f(x); +} + +var y:number = bar(0, x => ""); + +type Seq = number | Array; +var s1:Seq = [0,[0]]; +var s2:Seq = [[""]]; + +module.exports = { foo: ("": number) }; diff --git a/tests/new_react/FeedUFI.react.js b/tests/new_react/FeedUFI.react.js new file mode 100644 index 000000000000..3566747e36ce --- /dev/null +++ b/tests/new_react/FeedUFI.react.js @@ -0,0 +1,42 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule FeedUFI.react + * @flow + */ + +'use strict'; + +var UFILikeCount = require('UFILikeCount.react'); +var React = require('react'); + +var FeedUFI = React.createClass({ + _renderLikeCount: function( + feedback: any + ) { + var props = { + className: "", + key: "", + feedback: {feedback}, + permalink: "", + }; + var ignored = ; + return ( + + ); + }, + + render: function(): ?React.Element { + return ( +
+ ); + } + +}); + +module.exports = FeedUFI; diff --git a/tests/new_react/Mixin.js b/tests/new_react/Mixin.js new file mode 100644 index 000000000000..8a3aebf5bbba --- /dev/null +++ b/tests/new_react/Mixin.js @@ -0,0 +1,4 @@ +/* @providesModule Mixin */ +module.exports = { + success: function() { } +}; diff --git a/tests/new_react/UFILikeCount.react.js b/tests/new_react/UFILikeCount.react.js new file mode 100644 index 000000000000..75cc89f20983 --- /dev/null +++ b/tests/new_react/UFILikeCount.react.js @@ -0,0 +1,23 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule UFILikeCount.react + * @flow + */ + +'use strict'; + +var React = require('react'); + +var UFILikeCount = React.createClass({ + propTypes: { + permalink: React.PropTypes.string, + feedback: React.PropTypes.object.isRequired + }, + + render: function(): ?React.Element { + return
; + } +}); + +module.exports = UFILikeCount; diff --git a/tests/new_react/__snapshots__/jsfmt.spec.js.snap b/tests/new_react/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4db6b5d1e26e --- /dev/null +++ b/tests/new_react/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,845 @@ +exports[`test FeedUFI.react.js 1`] = ` +"/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule FeedUFI.react + * @flow + */ + +\'use strict\'; + +var UFILikeCount = require(\'UFILikeCount.react\'); +var React = require(\'react\'); + +var FeedUFI = React.createClass({ + _renderLikeCount: function( + feedback: any + ) { + var props = { + className: \"\", + key: \"\", + feedback: {feedback}, + permalink: \"\", + }; + var ignored = ; + return ( + + ); + }, + + render: function(): ?React.Element { + return ( +
+ ); + } + +}); + +module.exports = FeedUFI; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test Mixin.js 1`] = ` +"/* @providesModule Mixin */ +module.exports = { + success: function() { } +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Mixin */ +module.exports = { + success: function() { + + } +}; + +" +`; + +exports[`test UFILikeCount.react.js 1`] = ` +"/** + * Copyright 2004-present Facebook. All Rights Reserved. + * + * @providesModule UFILikeCount.react + * @flow + */ + +\'use strict\'; + +var React = require(\'react\'); + +var UFILikeCount = React.createClass({ + propTypes: { + permalink: React.PropTypes.string, + feedback: React.PropTypes.object.isRequired + }, + + render: function(): ?React.Element { + return
; + } +}); + +module.exports = UFILikeCount; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test bad_default_props.js 1`] = ` +"var React = require(\'React\'); + +type T1 = { } +type T2 = { x: number } +type T3 = { x: number, y: number } + +class C1 extends React.Component { // error +} + +class C2 extends React.Component { // OK +} + +// no need to add type arguments to React.Component +class C3 extends React.Component { // OK + static defaultProps: T1; + props: T2; +} + +class C4 extends React.Component { // OK, recommended + // no need to declare defaultProps unless necessary + props: T2; +} + +class C5 extends React.Component { // error +} + +class C6 extends React.Component { // OK, recommended + static defaultProps: T2; + props: T3; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1180:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test classes.js 1`] = ` +"var React = require(\'React\'); + +type DefaultProps = { }; +type Props = { x: number }; +type State = { y: number }; + +class Foo extends React.Component { + props: Props; + state: State; + static defaultProps: DefaultProps; + + is_mounted: boolean; + + static bar(): void {} + + qux(): void { + var _: string = this.props.x; + } + + constructor(props) { + super(props); + this.state = { y: \"\" }; + } + + setState(o: { y_: string }): void { } + + componentDidMount(): void { + this.is_mounted = true; + } + + componentWillReceiveProps( + nextProps: Object, + nextContext: any + ): void { + this.qux(); + } + +} + +Foo.defaultProps = 0; +var foo: $jsx = ; + +Foo.bar(); + +var FooLegacy = React.createClass({ + is_mounted: (undefined: ?boolean), + + propTypes: { + x: React.PropTypes.number.isRequired + }, + + getDefaultProps(): DefaultProps { return {} }, + + statics: { + bar(): void {} + }, + + qux(): void { + var _: string = this.props.x; + }, + + getInitialState(): { y: string } { + return { y: \"\" }; + }, + + setState(o: { y_: string }): void { }, + + componentDidMount(): void { + this.is_mounted = true; + }, + + componentWillReceiveProps( + nextProps: Object, + nextContext: any + ): void { + this.qux(); + }, +}); + +FooLegacy.defaultProps = 0; // TODO: should be error +var foo_legacy: $jsx = ; + +FooLegacy.bar(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test import-react.js 1`] = ` +"/* @flow */ + +// Testing local binding of React in all kinds of ways. The only reason this +// might even be an issue is that internally, the use of JSX triggers an +// implicit require(\'react\'), so any bugs in (1) interop of CJS require and ES6 +// import (2) module re-export, as used to redirect the module name \'React\' to +// \'react\' might show up here. + +import React from \"react\"; +//import React from \"React\"; +//var React = require(\"react\"); +//var React = require(\"React\"); + +class HelloMessage extends React.Component { + props: { name: string }; +} + +; // number ~/~> string error +; // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:5687 + throw jsxError || err; + ^ + +SyntaxError: Invalid number (18:20) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.readNumber (/node_modules/babylon/lib/index.js:1180:12) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1020:21) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.pp$8.jsxParseExpressionContainer (/node_modules/babylon/lib/index.js:6285:8) + at Parser.pp$8.jsxParseAttributeValue (/node_modules/babylon/lib/index.js:6241:19) +" +`; + +exports[`test new_react.js 1`] = ` +"var React = require(\'react\'); +var Mixin = require(\'Mixin\'); +var C = React.createClass({ + mixins: [Mixin], + propTypes: { + x: React.PropTypes.string.isRequired, + y: React.PropTypes.array, + z: React.PropTypes.number + }, + replaceProps(props: { }) { }, + + getDefaultProps(): { z: number } { + return { z: 0 }; + }, + getInitialState() { return 4; }, + render() { + var foo: string = this.state; + var bar: string = this.props; + var qux: string = this.props.z; + var w:number = this.props.x; + this.props.y[0]; + var len:number = this.props.x.length; + this.success(); + return
; + } + +}) + +var element = ; +var element_ = ; + +var x: number = C.displayName; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"react\"); +var Mixin = require(\"Mixin\"); +var C = React.createClass({ + mixins: [ Mixin ], + propTypes: { + x: React.PropTypes.string.isRequired, + y: React.PropTypes.array, + z: React.PropTypes.number + }, + replaceProps(props: {}) { + + }, + getDefaultProps(): { z: number } { + return { z: 0 }; + }, + getInitialState() { + return 4; + }, + render() { + var foo: string = this.state; + var bar: string = this.props; + var qux: string = this.props.z; + var w: number = this.props.x; + this.props.y[0]; + var len: number = this.props.x.length; + this.success(); + return
; + } +}); +var element = ; +var element_ = ; +var x: number = C.displayName; + +" +`; + +exports[`test propTypes.js 1`] = ` +"var React = require(\'react\'); +var PropTypes = React.PropTypes; + +var C = React.createClass({ + propTypes: { + statistics: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string.isRequired, + value: PropTypes.number, + })).isRequired, + } +}); + +; // error (label is required, value not required) + +var props: Array<{label: string, value?: number}> = [ + {}, + {label:\"\",value:undefined}, +]; // error (same as ^) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test props.js 1`] = ` +"var React = require(\'react\'); +var TestProps = React.createClass({ + + propTypes: { + x: React.PropTypes.string, + z: React.PropTypes.number + }, + + getDefaultProps: function() { + return {x: \'\', y: 0} + }, + + test: function() { + var a: number = this.props.x; // error + var b: string = this.props.y; // error + var c: string = this.props.z; // error + } +}); + +var element = ; // 3 errors + +(element: $jsx<*>); +(element: $jsx); +var FooProps = React.createClass({ + propTypes: { w: React.PropTypes.string.isRequired } +}); +(element: $jsx); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test props2.js 1`] = ` +"var React = require(\'react\'); +var C = React.createClass({ + propTypes: { + foo: React.PropTypes.string.isRequired, + bar: React.PropTypes.string.isRequired, + } +}); +var D = React.createClass({ + getInitialState: function(): { bar: number } { + return { bar: 0 }; + }, + render: function() { + var obj = { bar: 0 }; + var s: string = this.state.bar; + return ; + } +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"react\"); +var C = React.createClass({ + propTypes: { + foo: React.PropTypes.string.isRequired, + bar: React.PropTypes.string.isRequired + } +}); +var D = React.createClass({ + getInitialState: function(): { bar: number } { + return { bar: 0 }; + }, + render: function() { + var obj = { bar: 0 }; + var s: string = this.state.bar; + return ; + } +}); + +" +`; + +exports[`test props3.js 1`] = ` +"var React = require(\'react\'); +var TestProps = React.createClass({ + // Do something illegal inside of propTypes and make sure Flow notices + propTypes: { + arr: React.PropTypes.array, + arr_rec: React.PropTypes.array.isRequired, + bool: React.PropTypes.bool, + bool_rec: React.PropTypes.bool.isRequired, + func: React.PropTypes.func, + func_rec: React.PropTypes.func.isRequired, + number: React.PropTypes.number, + number_rec: React.PropTypes.number.isRequired, + object: React.PropTypes.object, + object_rec: React.PropTypes.object.isRequired, + string: React.PropTypes.string, + string_rec: React.PropTypes.string.isRequired, + + any: React.PropTypes.any, + any_rec: React.PropTypes.any.isRequired, + element: React.PropTypes.element, + element_rec: React.PropTypes.element.isRequired, + node: React.PropTypes.node, + node_rec: React.PropTypes.node.isRequired, + + arrayOf: React.PropTypes.arrayOf(React.PropTypes.string), + arrayOf_rec: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, + instanceOf: React.PropTypes.instanceOf(Object), + instanceOf_rec: React.PropTypes.instanceOf(Object).isRequired, + objectOf: React.PropTypes.objectOf(React.PropTypes.string), + objectOf_rec: React.PropTypes.objectOf(React.PropTypes.string).isRequired, + oneOf: React.PropTypes.oneOf([\"yes\", \"no\"]), + oneOf_rec: React.PropTypes.oneOf([\"yes\", \"no\"]).isRequired, + oneOfType: React.PropTypes.oneOfType( + [React.PropTypes.string, React.PropTypes.number] + ), + oneOfType_rec: React.PropTypes.oneOfType( + [React.PropTypes.string, React.PropTypes.number] + ).isRequired, + shape: React.PropTypes.shape({ + foo: React.PropTypes.string, + bar: React.PropTypes.number, + }), + shape_rec: React.PropTypes.shape({ + foo: React.PropTypes.string, + bar: React.PropTypes.number, + }).isRequired, + + // And do something bad here + bad_one: React.PropTypes.imaginaryType, + bad_two: React.PropTypes.string.inRequired, + }, +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"react\"); +var TestProps = React.createClass({ + // Do something illegal inside of propTypes and make sure Flow notices + propTypes: { + arr: React.PropTypes.array, + arr_rec: React.PropTypes.array.isRequired, + bool: React.PropTypes.bool, + bool_rec: React.PropTypes.bool.isRequired, + func: React.PropTypes.func, + func_rec: React.PropTypes.func.isRequired, + number: React.PropTypes.number, + number_rec: React.PropTypes.number.isRequired, + object: React.PropTypes.object, + object_rec: React.PropTypes.object.isRequired, + string: React.PropTypes.string, + string_rec: React.PropTypes.string.isRequired, + any: React.PropTypes.any, + any_rec: React.PropTypes.any.isRequired, + element: React.PropTypes.element, + element_rec: React.PropTypes.element.isRequired, + node: React.PropTypes.node, + node_rec: React.PropTypes.node.isRequired, + arrayOf: React.PropTypes.arrayOf(React.PropTypes.string), + arrayOf_rec: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, + instanceOf: React.PropTypes.instanceOf(Object), + instanceOf_rec: React.PropTypes.instanceOf(Object).isRequired, + objectOf: React.PropTypes.objectOf(React.PropTypes.string), + objectOf_rec: React.PropTypes.objectOf(React.PropTypes.string).isRequired, + oneOf: React.PropTypes.oneOf([ \"yes\", \"no\" ]), + oneOf_rec: React.PropTypes.oneOf([ \"yes\", \"no\" ]).isRequired, + oneOfType: React.PropTypes.oneOfType( + [ React.PropTypes.string, React.PropTypes.number ] + ), + oneOfType_rec: React.PropTypes.oneOfType( + [ React.PropTypes.string, React.PropTypes.number ] + ).isRequired, + shape: React.PropTypes.shape({ + foo: React.PropTypes.string, + bar: React.PropTypes.number + }), + shape_rec: React.PropTypes.shape({ + foo: React.PropTypes.string, + bar: React.PropTypes.number + }).isRequired, + // And do something bad here bad_one: React.PropTypes.imaginaryType, + bad_two: React.PropTypes.string.inRequired + } +}); + +" +`; + +exports[`test props4.js 1`] = ` +"// @flow + +import React from \"React\"; + +class JDiv extends React.Component { + // static defaultProps: { }; + props: { + id: string + }; +} + +// Should be a type error (\'id\' takes a string, not a number..) +; + +class Example extends React.Component { + props: { bar: string }; + + render() { + return
{this.props.bar}
+ } +} + +React.render( + , + document.body +); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import React from \"React\"; +class JDiv extends React.Component { + // static defaultProps: { }; + props: { id: string }; +} +// Should be a type error (\'id\' takes a string, not a number..) +; +class Example extends React.Component { + props: { bar: string }; + render() { + return
{this.props.bar}
; + } +} +React.render(, document.body); + +" +`; + +exports[`test props5.js 1`] = ` +"var React = require(\'React\'); + +var C = React.createClass({ + getDefaultProps: function() { + return { x: 0 }; + } +}); + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"React\"); +var C = React.createClass({ + getDefaultProps: function() { + return { x: 0 }; + } +}); +module.exports = C; + +" +`; + +exports[`test state.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); + +type State = { + bar: ?{ qux: string; }; +}; + +var ReactClass = React.createClass({ + getInitialState: function():State { + return { bar: null }; + }, + + render: function(): any { + // Any state access here seems to make state any + this.state; + return ( +
+ {this.state.bar.qux} +
+ ); + } +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +type State = { bar: ?{ qux: string } }; +var ReactClass = React.createClass({ + getInitialState: function(): State { + return { bar: null }; + }, + render: function(): any { + // Any state access here seems to make state any + this.state; + return ( +
+ {this.state.bar.qux} +
+ ); + } +}); + +" +`; + +exports[`test state2.js 1`] = ` +"// @flow + +var React = require(\'react\'); + +type FooState = { + key: ?Object; +}; + +var Comp = React.createClass({ + getInitialState: function(): FooState { + return { + key: null, // this used to cause a missing annotation error + }; + } +}); + +module.exports = Comp; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var React = require(\"react\"); +type FooState = { key: ?Object }; +var Comp = React.createClass({ + getInitialState: function(): FooState { + return { // this used to cause a missing annotation error key: null }; + } +}); +module.exports = Comp; + +" +`; + +exports[`test state3.js 1`] = ` +"var React = require(\'react\'); +var TestState = React.createClass({ + + getInitialState: function(): { x: string; } { + return { + x: \'\' + } + }, + + test: function() { + var a: number = this.state.x; // error + + this.setState({ + x: false // error + }) + } + +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"react\"); +var TestState = React.createClass({ + getInitialState: function(): { x: string } { + return { x: \"\" }; + }, + test: function() { + var a: number = this.state.x;// error + this.setState({ // error x: false }); + } +}); + +" +`; + +exports[`test state4.js 1`] = ` +"var React = require(\'React\'); + +var C = React.createClass({ + getInitialState: function() { + return { x: 0 }; + }, + + render() { + this.setState({ y: 0 }); + return
{this.state.z}
+ } + +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"React\"); +var C = React.createClass({ + getInitialState: function() { + return { x: 0 }; + }, + render() { + this.setState({ y: 0 }); + return
{this.state.z}
; + } +}); + +" +`; + +exports[`test state5.js 1`] = ` +"var React = require(\'React\'); + +class C extends React.Component { + foo(): number { + return this.state.x; // error: need to declare type of state + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require(\"React\"); +class C extends React.Component { + foo(): number { + return this.state.x;// error: need to declare type of state + } +} + +" +`; diff --git a/tests/new_react/bad_default_props.js b/tests/new_react/bad_default_props.js new file mode 100644 index 000000000000..9dd3159f431a --- /dev/null +++ b/tests/new_react/bad_default_props.js @@ -0,0 +1,30 @@ +var React = require('React'); + +type T1 = { } +type T2 = { x: number } +type T3 = { x: number, y: number } + +class C1 extends React.Component { // error +} + +class C2 extends React.Component { // OK +} + +// no need to add type arguments to React.Component +class C3 extends React.Component { // OK + static defaultProps: T1; + props: T2; +} + +class C4 extends React.Component { // OK, recommended + // no need to declare defaultProps unless necessary + props: T2; +} + +class C5 extends React.Component { // error +} + +class C6 extends React.Component { // OK, recommended + static defaultProps: T2; + props: T3; +} diff --git a/tests/new_react/classes.js b/tests/new_react/classes.js new file mode 100644 index 000000000000..7574a00af3b7 --- /dev/null +++ b/tests/new_react/classes.js @@ -0,0 +1,83 @@ +var React = require('React'); + +type DefaultProps = { }; +type Props = { x: number }; +type State = { y: number }; + +class Foo extends React.Component { + props: Props; + state: State; + static defaultProps: DefaultProps; + + is_mounted: boolean; + + static bar(): void {} + + qux(): void { + var _: string = this.props.x; + } + + constructor(props) { + super(props); + this.state = { y: "" }; + } + + setState(o: { y_: string }): void { } + + componentDidMount(): void { + this.is_mounted = true; + } + + componentWillReceiveProps( + nextProps: Object, + nextContext: any + ): void { + this.qux(); + } + +} + +Foo.defaultProps = 0; +var foo: $jsx = ; + +Foo.bar(); + +var FooLegacy = React.createClass({ + is_mounted: (undefined: ?boolean), + + propTypes: { + x: React.PropTypes.number.isRequired + }, + + getDefaultProps(): DefaultProps { return {} }, + + statics: { + bar(): void {} + }, + + qux(): void { + var _: string = this.props.x; + }, + + getInitialState(): { y: string } { + return { y: "" }; + }, + + setState(o: { y_: string }): void { }, + + componentDidMount(): void { + this.is_mounted = true; + }, + + componentWillReceiveProps( + nextProps: Object, + nextContext: any + ): void { + this.qux(); + }, +}); + +FooLegacy.defaultProps = 0; // TODO: should be error +var foo_legacy: $jsx = ; + +FooLegacy.bar(); diff --git a/tests/new_react/fakelib/__snapshots__/jsfmt.spec.js.snap b/tests/new_react/fakelib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4a9d5f412fd7 --- /dev/null +++ b/tests/new_react/fakelib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test type_aliases.js 1`] = ` +"declare var $React: $Exports<\'react\'>; // fake import +// Strawman: revised definition of $jsx (alternatively, React.Element). +// Using bounded poly to specify a constraint on a type parameter, and +// existentials to elide type arguments. +type _ReactElement, C: $React.Component> = $React.Element; +type $jsx = _ReactElement<*, *, *, C>; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/new_react/fakelib/jsfmt.spec.js b/tests/new_react/fakelib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/new_react/fakelib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/new_react/fakelib/type_aliases.js b/tests/new_react/fakelib/type_aliases.js new file mode 100644 index 000000000000..864772039b5c --- /dev/null +++ b/tests/new_react/fakelib/type_aliases.js @@ -0,0 +1,6 @@ +declare var $React: $Exports<'react'>; // fake import +// Strawman: revised definition of $jsx (alternatively, React.Element). +// Using bounded poly to specify a constraint on a type parameter, and +// existentials to elide type arguments. +type _ReactElement, C: $React.Component> = $React.Element; +type $jsx = _ReactElement<*, *, *, C>; diff --git a/tests/new_react/import-react.js b/tests/new_react/import-react.js new file mode 100644 index 000000000000..f4fda4d77d95 --- /dev/null +++ b/tests/new_react/import-react.js @@ -0,0 +1,19 @@ +/* @flow */ + +// Testing local binding of React in all kinds of ways. The only reason this +// might even be an issue is that internally, the use of JSX triggers an +// implicit require('react'), so any bugs in (1) interop of CJS require and ES6 +// import (2) module re-export, as used to redirect the module name 'React' to +// 'react' might show up here. + +import React from "react"; +//import React from "React"; +//var React = require("react"); +//var React = require("React"); + +class HelloMessage extends React.Component { + props: { name: string }; +} + +; // number ~/~> string error +; // ok diff --git a/tests/new_react/jsfmt.spec.js b/tests/new_react/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/new_react/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/new_react/new_react.js b/tests/new_react/new_react.js new file mode 100644 index 000000000000..70444d1cf288 --- /dev/null +++ b/tests/new_react/new_react.js @@ -0,0 +1,32 @@ +var React = require('react'); +var Mixin = require('Mixin'); +var C = React.createClass({ + mixins: [Mixin], + propTypes: { + x: React.PropTypes.string.isRequired, + y: React.PropTypes.array, + z: React.PropTypes.number + }, + replaceProps(props: { }) { }, + + getDefaultProps(): { z: number } { + return { z: 0 }; + }, + getInitialState() { return 4; }, + render() { + var foo: string = this.state; + var bar: string = this.props; + var qux: string = this.props.z; + var w:number = this.props.x; + this.props.y[0]; + var len:number = this.props.x.length; + this.success(); + return
; + } + +}) + +var element = ; +var element_ = ; + +var x: number = C.displayName; diff --git a/tests/new_react/propTypes.js b/tests/new_react/propTypes.js new file mode 100644 index 000000000000..2acaef6fafcf --- /dev/null +++ b/tests/new_react/propTypes.js @@ -0,0 +1,21 @@ +var React = require('react'); +var PropTypes = React.PropTypes; + +var C = React.createClass({ + propTypes: { + statistics: PropTypes.arrayOf(PropTypes.shape({ + label: PropTypes.string.isRequired, + value: PropTypes.number, + })).isRequired, + } +}); + +; // error (label is required, value not required) + +var props: Array<{label: string, value?: number}> = [ + {}, + {label:"",value:undefined}, +]; // error (same as ^) diff --git a/tests/new_react/props.js b/tests/new_react/props.js new file mode 100644 index 000000000000..055d608ef2f3 --- /dev/null +++ b/tests/new_react/props.js @@ -0,0 +1,27 @@ +var React = require('react'); +var TestProps = React.createClass({ + + propTypes: { + x: React.PropTypes.string, + z: React.PropTypes.number + }, + + getDefaultProps: function() { + return {x: '', y: 0} + }, + + test: function() { + var a: number = this.props.x; // error + var b: string = this.props.y; // error + var c: string = this.props.z; // error + } +}); + +var element = ; // 3 errors + +(element: $jsx<*>); +(element: $jsx); +var FooProps = React.createClass({ + propTypes: { w: React.PropTypes.string.isRequired } +}); +(element: $jsx); diff --git a/tests/new_react/props2.js b/tests/new_react/props2.js new file mode 100644 index 000000000000..6f8fd76c440f --- /dev/null +++ b/tests/new_react/props2.js @@ -0,0 +1,17 @@ +var React = require('react'); +var C = React.createClass({ + propTypes: { + foo: React.PropTypes.string.isRequired, + bar: React.PropTypes.string.isRequired, + } +}); +var D = React.createClass({ + getInitialState: function(): { bar: number } { + return { bar: 0 }; + }, + render: function() { + var obj = { bar: 0 }; + var s: string = this.state.bar; + return ; + } +}); diff --git a/tests/new_react/props3.js b/tests/new_react/props3.js new file mode 100644 index 000000000000..169b85c9afc4 --- /dev/null +++ b/tests/new_react/props3.js @@ -0,0 +1,52 @@ +var React = require('react'); +var TestProps = React.createClass({ + // Do something illegal inside of propTypes and make sure Flow notices + propTypes: { + arr: React.PropTypes.array, + arr_rec: React.PropTypes.array.isRequired, + bool: React.PropTypes.bool, + bool_rec: React.PropTypes.bool.isRequired, + func: React.PropTypes.func, + func_rec: React.PropTypes.func.isRequired, + number: React.PropTypes.number, + number_rec: React.PropTypes.number.isRequired, + object: React.PropTypes.object, + object_rec: React.PropTypes.object.isRequired, + string: React.PropTypes.string, + string_rec: React.PropTypes.string.isRequired, + + any: React.PropTypes.any, + any_rec: React.PropTypes.any.isRequired, + element: React.PropTypes.element, + element_rec: React.PropTypes.element.isRequired, + node: React.PropTypes.node, + node_rec: React.PropTypes.node.isRequired, + + arrayOf: React.PropTypes.arrayOf(React.PropTypes.string), + arrayOf_rec: React.PropTypes.arrayOf(React.PropTypes.string).isRequired, + instanceOf: React.PropTypes.instanceOf(Object), + instanceOf_rec: React.PropTypes.instanceOf(Object).isRequired, + objectOf: React.PropTypes.objectOf(React.PropTypes.string), + objectOf_rec: React.PropTypes.objectOf(React.PropTypes.string).isRequired, + oneOf: React.PropTypes.oneOf(["yes", "no"]), + oneOf_rec: React.PropTypes.oneOf(["yes", "no"]).isRequired, + oneOfType: React.PropTypes.oneOfType( + [React.PropTypes.string, React.PropTypes.number] + ), + oneOfType_rec: React.PropTypes.oneOfType( + [React.PropTypes.string, React.PropTypes.number] + ).isRequired, + shape: React.PropTypes.shape({ + foo: React.PropTypes.string, + bar: React.PropTypes.number, + }), + shape_rec: React.PropTypes.shape({ + foo: React.PropTypes.string, + bar: React.PropTypes.number, + }).isRequired, + + // And do something bad here + bad_one: React.PropTypes.imaginaryType, + bad_two: React.PropTypes.string.inRequired, + }, +}); diff --git a/tests/new_react/props4.js b/tests/new_react/props4.js new file mode 100644 index 000000000000..ba428355b20a --- /dev/null +++ b/tests/new_react/props4.js @@ -0,0 +1,26 @@ +// @flow + +import React from "React"; + +class JDiv extends React.Component { + // static defaultProps: { }; + props: { + id: string + }; +} + +// Should be a type error ('id' takes a string, not a number..) +; + +class Example extends React.Component { + props: { bar: string }; + + render() { + return
{this.props.bar}
+ } +} + +React.render( + , + document.body +); diff --git a/tests/new_react/props5.js b/tests/new_react/props5.js new file mode 100644 index 000000000000..0e236158260a --- /dev/null +++ b/tests/new_react/props5.js @@ -0,0 +1,9 @@ +var React = require('React'); + +var C = React.createClass({ + getDefaultProps: function() { + return { x: 0 }; + } +}); + +module.exports = C; diff --git a/tests/new_react/state.js b/tests/new_react/state.js new file mode 100644 index 000000000000..aa3bac629751 --- /dev/null +++ b/tests/new_react/state.js @@ -0,0 +1,23 @@ +/* @flow */ + +var React = require('react'); + +type State = { + bar: ?{ qux: string; }; +}; + +var ReactClass = React.createClass({ + getInitialState: function():State { + return { bar: null }; + }, + + render: function(): any { + // Any state access here seems to make state any + this.state; + return ( +
+ {this.state.bar.qux} +
+ ); + } +}); diff --git a/tests/new_react/state2.js b/tests/new_react/state2.js new file mode 100644 index 000000000000..213d7679f51e --- /dev/null +++ b/tests/new_react/state2.js @@ -0,0 +1,17 @@ +// @flow + +var React = require('react'); + +type FooState = { + key: ?Object; +}; + +var Comp = React.createClass({ + getInitialState: function(): FooState { + return { + key: null, // this used to cause a missing annotation error + }; + } +}); + +module.exports = Comp; diff --git a/tests/new_react/state3.js b/tests/new_react/state3.js new file mode 100644 index 000000000000..4b7541d604d4 --- /dev/null +++ b/tests/new_react/state3.js @@ -0,0 +1,18 @@ +var React = require('react'); +var TestState = React.createClass({ + + getInitialState: function(): { x: string; } { + return { + x: '' + } + }, + + test: function() { + var a: number = this.state.x; // error + + this.setState({ + x: false // error + }) + } + +}); diff --git a/tests/new_react/state4.js b/tests/new_react/state4.js new file mode 100644 index 000000000000..9b1ea8251736 --- /dev/null +++ b/tests/new_react/state4.js @@ -0,0 +1,13 @@ +var React = require('React'); + +var C = React.createClass({ + getInitialState: function() { + return { x: 0 }; + }, + + render() { + this.setState({ y: 0 }); + return
{this.state.z}
+ } + +}); diff --git a/tests/new_react/state5.js b/tests/new_react/state5.js new file mode 100644 index 000000000000..f14b3db25a1e --- /dev/null +++ b/tests/new_react/state5.js @@ -0,0 +1,7 @@ +var React = require('React'); + +class C extends React.Component { + foo(): number { + return this.state.x; // error: need to declare type of state + } +} diff --git a/tests/node_haste/__snapshots__/jsfmt.spec.js.snap b/tests/node_haste/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2794c8648aa9 --- /dev/null +++ b/tests/node_haste/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test client.js 1`] = ` +"var md5 = require('./md5'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var md5 = require("./md5"); + +" +`; + +exports[`test md5.js 1`] = ` +"/* @providesModule md5 */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/node_haste/client.js b/tests/node_haste/client.js new file mode 100644 index 000000000000..7c4f789d466a --- /dev/null +++ b/tests/node_haste/client.js @@ -0,0 +1 @@ +var md5 = require('./md5'); diff --git a/tests/node_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap b/tests/node_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..af2f32ce6008 --- /dev/null +++ b/tests/node_haste/external/_d3/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,6 @@ +exports[`test min.js 1`] = ` +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/node_haste/external/_d3/jsfmt.spec.js b/tests/node_haste/external/_d3/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_haste/external/_d3/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_haste/external/_d3/min.js b/tests/node_haste/external/_d3/min.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/node_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap b/tests/node_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..86fe21ff2a9b --- /dev/null +++ b/tests/node_haste/foo/bar/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test client.js 1`] = ` +"var docblock = require('qux/docblock'); +var min = require('d3/min.js'); +var corge = require('qux/corge'); + +// make sure we don't pick up non-header @providesModule +// annotations - see node_modules/qux/docblock.js +var unreachable = require('annotation'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var docblock = require("qux/docblock"); +var min = require("d3/min.js"); +var corge = require("qux/corge"); +// make sure we don't pick up non-header @providesModule +// annotations - see node_modules/qux/docblock.js +var unreachable = require("annotation"); + +" +`; diff --git a/tests/node_haste/foo/bar/client.js b/tests/node_haste/foo/bar/client.js new file mode 100644 index 000000000000..f77729c44c56 --- /dev/null +++ b/tests/node_haste/foo/bar/client.js @@ -0,0 +1,7 @@ +var docblock = require('qux/docblock'); +var min = require('d3/min.js'); +var corge = require('qux/corge'); + +// make sure we don't pick up non-header @providesModule +// annotations - see node_modules/qux/docblock.js +var unreachable = require('annotation'); diff --git a/tests/node_haste/foo/bar/jsfmt.spec.js b/tests/node_haste/foo/bar/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_haste/foo/bar/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_haste/jsfmt.spec.js b/tests/node_haste/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_haste/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_haste/md5.js b/tests/node_haste/md5.js new file mode 100644 index 000000000000..c358d72168a6 --- /dev/null +++ b/tests/node_haste/md5.js @@ -0,0 +1 @@ +/* @providesModule md5 */ diff --git a/tests/node_haste/ws/__snapshots__/jsfmt.spec.js.snap b/tests/node_haste/ws/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..72caaf084cb1 --- /dev/null +++ b/tests/node_haste/ws/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,6 @@ +exports[`test index.js 1`] = ` +"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/node_haste/ws/index.js b/tests/node_haste/ws/index.js new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/tests/node_haste/ws/jsfmt.spec.js b/tests/node_haste/ws/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_haste/ws/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_haste/ws/test/__snapshots__/jsfmt.spec.js.snap b/tests/node_haste/ws/test/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f54d0216ceb7 --- /dev/null +++ b/tests/node_haste/ws/test/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test client.js 1`] = ` +"var ws = require('../'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var ws = require("../"); + +" +`; diff --git a/tests/node_haste/ws/test/client.js b/tests/node_haste/ws/test/client.js new file mode 100644 index 000000000000..2fb0ed6d4dfd --- /dev/null +++ b/tests/node_haste/ws/test/client.js @@ -0,0 +1 @@ +var ws = require('../'); diff --git a/tests/node_haste/ws/test/jsfmt.spec.js b/tests/node_haste/ws/test/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_haste/ws/test/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_modules_with_symlinks/root/__snapshots__/jsfmt.spec.js.snap b/tests/node_modules_with_symlinks/root/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b2745f3910e8 --- /dev/null +++ b/tests/node_modules_with_symlinks/root/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,13 @@ +exports[`test foo.js 1`] = ` +"var x = require('symlink_lib'); +var y = require('symlink_lib_outside_root'); +console.log(x); +console.log(y); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("symlink_lib"); +var y = require("symlink_lib_outside_root"); +console.log(x); +console.log(y); + +" +`; diff --git a/tests/node_modules_with_symlinks/root/foo.js b/tests/node_modules_with_symlinks/root/foo.js new file mode 100644 index 000000000000..a281d0aade1d --- /dev/null +++ b/tests/node_modules_with_symlinks/root/foo.js @@ -0,0 +1,4 @@ +var x = require('symlink_lib'); +var y = require('symlink_lib_outside_root'); +console.log(x); +console.log(y); diff --git a/tests/node_modules_with_symlinks/root/jsfmt.spec.js b/tests/node_modules_with_symlinks/root/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_modules_with_symlinks/root/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_modules_with_symlinks/root/symlink_lib/__snapshots__/jsfmt.spec.js.snap b/tests/node_modules_with_symlinks/root/symlink_lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9ccacc6e6df6 --- /dev/null +++ b/tests/node_modules_with_symlinks/root/symlink_lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test index.js 1`] = ` +"module.exports = { bar: "bar" }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = { bar: "bar" }; + +" +`; diff --git a/tests/node_modules_with_symlinks/root/symlink_lib/index.js b/tests/node_modules_with_symlinks/root/symlink_lib/index.js new file mode 100644 index 000000000000..206c5837e74d --- /dev/null +++ b/tests/node_modules_with_symlinks/root/symlink_lib/index.js @@ -0,0 +1 @@ +module.exports = { bar: "bar" }; diff --git a/tests/node_modules_with_symlinks/root/symlink_lib/jsfmt.spec.js b/tests/node_modules_with_symlinks/root/symlink_lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_modules_with_symlinks/root/symlink_lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_modules_with_symlinks/symlink_lib_outside_root/__snapshots__/jsfmt.spec.js.snap b/tests/node_modules_with_symlinks/symlink_lib_outside_root/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9ccacc6e6df6 --- /dev/null +++ b/tests/node_modules_with_symlinks/symlink_lib_outside_root/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test index.js 1`] = ` +"module.exports = { bar: "bar" }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = { bar: "bar" }; + +" +`; diff --git a/tests/node_modules_with_symlinks/symlink_lib_outside_root/index.js b/tests/node_modules_with_symlinks/symlink_lib_outside_root/index.js new file mode 100644 index 000000000000..206c5837e74d --- /dev/null +++ b/tests/node_modules_with_symlinks/symlink_lib_outside_root/index.js @@ -0,0 +1 @@ +module.exports = { bar: "bar" }; diff --git a/tests/node_modules_with_symlinks/symlink_lib_outside_root/jsfmt.spec.js b/tests/node_modules_with_symlinks/symlink_lib_outside_root/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_modules_with_symlinks/symlink_lib_outside_root/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_modules_without_json/__snapshots__/jsfmt.spec.js.snap b/tests/node_modules_without_json/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9b9f9ace19db --- /dev/null +++ b/tests/node_modules_without_json/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test test.js 1`] = ` +"// @flow + +let foo = require('foo'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let foo = require("foo"); + +" +`; diff --git a/tests/node_modules_without_json/jsfmt.spec.js b/tests/node_modules_without_json/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_modules_without_json/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_modules_without_json/test.js b/tests/node_modules_without_json/test.js new file mode 100644 index 000000000000..0929d36bbcdb --- /dev/null +++ b/tests/node_modules_without_json/test.js @@ -0,0 +1,3 @@ +// @flow + +let foo = require('foo'); diff --git a/tests/node_tests/assert/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/assert/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..917ce8adb7d3 --- /dev/null +++ b/tests/node_tests/assert/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,14 @@ +exports[`test assert.js 1`] = ` +"/* @flow */ + +var assert = require("assert") +assert(true) // ok +assert.ok(true) // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var assert = require("assert"); +assert(true);// ok +assert.ok(true);// ok + +" +`; diff --git a/tests/node_tests/assert/assert.js b/tests/node_tests/assert/assert.js new file mode 100644 index 000000000000..cc8f9feeffdd --- /dev/null +++ b/tests/node_tests/assert/assert.js @@ -0,0 +1,5 @@ +/* @flow */ + +var assert = require("assert") +assert(true) // ok +assert.ok(true) // ok diff --git a/tests/node_tests/assert/jsfmt.spec.js b/tests/node_tests/assert/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/assert/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/basic/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/basic/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..cd7e6db3e4d9 --- /dev/null +++ b/tests/node_tests/basic/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test bar.js 1`] = ` +"module.exports = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = "bar"; + +" +`; + +exports[`test foo.js 1`] = ` +"var x = require('./bar.js'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("./bar.js"); +console.log(x); + +" +`; diff --git a/tests/node_tests/basic/bar.js b/tests/node_tests/basic/bar.js new file mode 100644 index 000000000000..a7f281456cc7 --- /dev/null +++ b/tests/node_tests/basic/bar.js @@ -0,0 +1 @@ +module.exports = "bar"; diff --git a/tests/node_tests/basic/foo.js b/tests/node_tests/basic/foo.js new file mode 100644 index 000000000000..cebd25bedbde --- /dev/null +++ b/tests/node_tests/basic/foo.js @@ -0,0 +1,2 @@ +var x = require('./bar.js'); +console.log(x); diff --git a/tests/node_tests/basic/jsfmt.spec.js b/tests/node_tests/basic/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/basic/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/basic_file/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/basic_file/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b4a5902fad5e --- /dev/null +++ b/tests/node_tests/basic_file/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test bar.js 1`] = ` +"module.exports = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = "bar"; + +" +`; + +exports[`test foo.js 1`] = ` +"var x = require('./bar'); // bar.js does not work +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("./bar");// bar.js does not work +console.log(x); + +" +`; diff --git a/tests/node_tests/basic_file/bar.js b/tests/node_tests/basic_file/bar.js new file mode 100644 index 000000000000..a7f281456cc7 --- /dev/null +++ b/tests/node_tests/basic_file/bar.js @@ -0,0 +1 @@ +module.exports = "bar"; diff --git a/tests/node_tests/basic_file/foo.js b/tests/node_tests/basic_file/foo.js new file mode 100644 index 000000000000..93cbf0128dbf --- /dev/null +++ b/tests/node_tests/basic_file/foo.js @@ -0,0 +1,2 @@ +var x = require('./bar'); // bar.js does not work +console.log(x); diff --git a/tests/node_tests/basic_file/jsfmt.spec.js b/tests/node_tests/basic_file/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/basic_file/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/basic_node_modules/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/basic_node_modules/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..677c14aba703 --- /dev/null +++ b/tests/node_tests/basic_node_modules/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('bar.js'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("bar.js"); +console.log(x); + +" +`; diff --git a/tests/node_tests/basic_node_modules/foo.js b/tests/node_tests/basic_node_modules/foo.js new file mode 100644 index 000000000000..8f06577c8d27 --- /dev/null +++ b/tests/node_tests/basic_node_modules/foo.js @@ -0,0 +1,2 @@ +var x = require('bar.js'); +console.log(x); diff --git a/tests/node_tests/basic_node_modules/jsfmt.spec.js b/tests/node_tests/basic_node_modules/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/basic_node_modules/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/basic_node_modules_with_path/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/basic_node_modules_with_path/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a17a80ce4244 --- /dev/null +++ b/tests/node_tests/basic_node_modules_with_path/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('bar_lib/bar'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("bar_lib/bar"); +console.log(x); + +" +`; diff --git a/tests/node_tests/basic_node_modules_with_path/foo.js b/tests/node_tests/basic_node_modules_with_path/foo.js new file mode 100644 index 000000000000..ba511e6ca239 --- /dev/null +++ b/tests/node_tests/basic_node_modules_with_path/foo.js @@ -0,0 +1,2 @@ +var x = require('bar_lib/bar'); +console.log(x); diff --git a/tests/node_tests/basic_node_modules_with_path/jsfmt.spec.js b/tests/node_tests/basic_node_modules_with_path/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/basic_node_modules_with_path/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/basic_package/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/basic_package/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..02758dca30b4 --- /dev/null +++ b/tests/node_tests/basic_package/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('./bar_lib'); // 'bar_lib' does not work! +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("./bar_lib");// 'bar_lib' does not work! +console.log(x); + +" +`; diff --git a/tests/node_tests/basic_package/bar_lib/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/basic_package/bar_lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..23901fc4ada1 --- /dev/null +++ b/tests/node_tests/basic_package/bar_lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test bar.js 1`] = ` +"module.exports = "bar"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = "bar"; + +" +`; diff --git a/tests/node_tests/basic_package/bar_lib/bar.js b/tests/node_tests/basic_package/bar_lib/bar.js new file mode 100644 index 000000000000..a7f281456cc7 --- /dev/null +++ b/tests/node_tests/basic_package/bar_lib/bar.js @@ -0,0 +1 @@ +module.exports = "bar"; diff --git a/tests/node_tests/basic_package/bar_lib/jsfmt.spec.js b/tests/node_tests/basic_package/bar_lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/basic_package/bar_lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/basic_package/foo.js b/tests/node_tests/basic_package/foo.js new file mode 100644 index 000000000000..11c0d1d81528 --- /dev/null +++ b/tests/node_tests/basic_package/foo.js @@ -0,0 +1,2 @@ +var x = require('./bar_lib'); // 'bar_lib' does not work! +console.log(x); diff --git a/tests/node_tests/basic_package/jsfmt.spec.js b/tests/node_tests/basic_package/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/basic_package/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/buffer/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/buffer/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a5d8d12edbc7 --- /dev/null +++ b/tests/node_tests/buffer/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,76 @@ +exports[`test buffer.js 1`] = ` +"/* @flow */ + +let bool: boolean = false; +let buffer: Buffer = new Buffer(0); +let num: number = 0; +let maybeNum: ?number; + +// Uint8Array properties. All of these should type check ok. +buffer.length; +buffer.buffer; +buffer.byteOffset; +buffer.byteLength; +buffer[1]; + +// A few Uint8Array instance methods. All of these should type check ok. +buffer.copyWithin(0, 0); +buffer.copyWithin(0, 0, 0); + +const it1: Iterator<[number, number]> = buffer.entries(); + +bool = buffer.every((element: number) => false); +bool = buffer.every((element: number) => false, buffer); + +buffer = buffer.fill(1); +buffer = buffer.fill(1, 0, 0); +buffer = buffer.fill(\"a\"); +buffer = buffer.fill(\"a\", 0, 0); +buffer = buffer.fill(\"a\", 0, 0, \"utf8\"); +buffer = buffer.fill(\"a\", \"utf8\"); + +maybeNum = buffer.find((element: number, index: number, array:Uint8Array) => false); +maybeNum = buffer.find((element: number, index: number, array:Uint8Array) => false, buffer); + +num = buffer.findIndex((element: number, index: number, array:Uint8Array) => false); +num = buffer.findIndex((element: number, index: number, array:Uint8Array) => false, buffer); + +buffer.forEach((value: number) => console.log(value), buffer); +buffer.forEach((value: number, index:number, array:Uint8Array) => console.log(value), buffer); + +bool = buffer.includes(3); +bool = buffer.includes(3, 4); + +num = buffer.indexOf(3); +num = buffer.indexOf(3, 4); + +// static methods +buffer = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); +const typedArray = new Uint8Array([0x34]); +buffer = Buffer.from(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); +buffer = Buffer.from(new Buffer(0)); +buffer = Buffer.from(\"foo\", \"utf8\"); + +// This call to from() does type check ok, but should not. Unfortunately, Buffer +// extends Uint8Array but gets rid of this signature to .from(). Understandably, +// flow doesn\'t support a subclass hiding a superclass member, so this checks out as +// ok, even though it is not correct. +buffer = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72], (a:number) => a + 1, {}); // should error but doesn\'t +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/node_tests/buffer/buffer.js b/tests/node_tests/buffer/buffer.js new file mode 100644 index 000000000000..9c53197948c6 --- /dev/null +++ b/tests/node_tests/buffer/buffer.js @@ -0,0 +1,57 @@ +/* @flow */ + +let bool: boolean = false; +let buffer: Buffer = new Buffer(0); +let num: number = 0; +let maybeNum: ?number; + +// Uint8Array properties. All of these should type check ok. +buffer.length; +buffer.buffer; +buffer.byteOffset; +buffer.byteLength; +buffer[1]; + +// A few Uint8Array instance methods. All of these should type check ok. +buffer.copyWithin(0, 0); +buffer.copyWithin(0, 0, 0); + +const it1: Iterator<[number, number]> = buffer.entries(); + +bool = buffer.every((element: number) => false); +bool = buffer.every((element: number) => false, buffer); + +buffer = buffer.fill(1); +buffer = buffer.fill(1, 0, 0); +buffer = buffer.fill("a"); +buffer = buffer.fill("a", 0, 0); +buffer = buffer.fill("a", 0, 0, "utf8"); +buffer = buffer.fill("a", "utf8"); + +maybeNum = buffer.find((element: number, index: number, array:Uint8Array) => false); +maybeNum = buffer.find((element: number, index: number, array:Uint8Array) => false, buffer); + +num = buffer.findIndex((element: number, index: number, array:Uint8Array) => false); +num = buffer.findIndex((element: number, index: number, array:Uint8Array) => false, buffer); + +buffer.forEach((value: number) => console.log(value), buffer); +buffer.forEach((value: number, index:number, array:Uint8Array) => console.log(value), buffer); + +bool = buffer.includes(3); +bool = buffer.includes(3, 4); + +num = buffer.indexOf(3); +num = buffer.indexOf(3, 4); + +// static methods +buffer = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72]); +const typedArray = new Uint8Array([0x34]); +buffer = Buffer.from(typedArray.buffer, typedArray.byteOffset, typedArray.byteLength); +buffer = Buffer.from(new Buffer(0)); +buffer = Buffer.from("foo", "utf8"); + +// This call to from() does type check ok, but should not. Unfortunately, Buffer +// extends Uint8Array but gets rid of this signature to .from(). Understandably, +// flow doesn't support a subclass hiding a superclass member, so this checks out as +// ok, even though it is not correct. +buffer = Buffer.from([0x62, 0x75, 0x66, 0x66, 0x65, 0x72], (a:number) => a + 1, {}); // should error but doesn't diff --git a/tests/node_tests/buffer/jsfmt.spec.js b/tests/node_tests/buffer/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/buffer/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/child_process/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/child_process/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ad8791456df2 --- /dev/null +++ b/tests/node_tests/child_process/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,200 @@ +exports[`test exec.js 1`] = ` +"/* @flow */ + +var exec = require(\'child_process\').exec; + +// callback only. +exec(\'ls\', function(error, stdout, stderr) { + console.info(stdout); +}); + +// options only. +exec(\'ls\', {timeout: 250}); + +// options + callback. +exec(\'ls\', {maxBuffer: 100}, function(error, stdout, stderr) { + console.info(stdout); +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var exec = require(\"child_process\").exec; +// callback only. +exec( + \"ls\", + function(error, stdout, stderr) { + console.info(stdout); + } +); +// options only. +exec(\"ls\", { timeout: 250 }); +// options + callback. +exec( + \"ls\", + { maxBuffer: 100 }, + function(error, stdout, stderr) { + console.info(stdout); + } +); + +" +`; + +exports[`test execFile.js 1`] = ` +"/* @flow */ + +var execFile = require(\'child_process\').execFile; + +// args only. +execFile(\'ls\', [\'-lh\']); + +// callback only. +execFile(\'ls\', function(error, stdout, stderr) { + console.info(stdout); +}); + +// options only. +execFile(\'wc\', {timeout: 250}); + +// args + callback. +execFile(\'ls\', [\'-l\'], function(error, stdout, stderr) { + console.info(stdout); +}); + +// args + options. +execFile(\'ls\', [\'-l\'], {timeout: 250}); + +// Put it all together. +execFile(\'ls\', [\'-l\'], {timeout: 250}, function(error, stdout, stderr) { + console.info(stdout); +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var execFile = require(\"child_process\").execFile; +// args only. +execFile(\"ls\", [ \"-lh\" ]); +// callback only. +execFile( + \"ls\", + function(error, stdout, stderr) { + console.info(stdout); + } +); +// options only. +execFile(\"wc\", { timeout: 250 }); +// args + callback. +execFile( + \"ls\", + [ \"-l\" ], + function(error, stdout, stderr) { + console.info(stdout); + } +); +// args + options. +execFile(\"ls\", [ \"-l\" ], { timeout: 250 }); +// Put it all together. +execFile( + \"ls\", + [ \"-l\" ], + { timeout: 250 }, + function(error, stdout, stderr) { + console.info(stdout); + } +); + +" +`; + +exports[`test execSync.js 1`] = ` +"/* @flow */ + +var execSync = require(\'child_process\').execSync; + +(execSync(\'ls\'): Buffer); // returns Buffer +(execSync(\'ls\', {encoding: \'buffer\'}): Buffer); // returns Buffer +(execSync(\'ls\', {encoding: \'utf8\'}): string); // returns string +(execSync(\'ls\', {timeout: \'250\'})); // error, no signatures match +(execSync(\'ls\', {stdio: \'inherit\'})); // error, no signatures match +(execSync(\'ls\', {stdio: [\'inherit\']})); // error, no signatures match +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var execSync = require(\"child_process\").execSync; +(execSync(\"ls\"): Buffer);// returns Buffer +(execSync(\"ls\", { encoding: \"buffer\" }): Buffer);// returns Buffer +(execSync(\"ls\", { encoding: \"utf8\" }): string);// returns string +execSync(\"ls\", { timeout: \"250\" });// error, no signatures match +execSync(\"ls\", { stdio: \"inherit\" });// error, no signatures match +execSync(\"ls\", { stdio: [ \"inherit\" ] });// error, no signatures match + +" +`; + +exports[`test spawn.js 1`] = ` +"/* @flow */ + +var child_process = require(\'child_process\'); + +var ls = child_process.spawn(\'ls\'); +var wc = child_process.spawn(\'wc\', [\'-l\']); + +// args + options. +child_process.spawn(\'echo\', [\'-n\', \'\"Testing...\"\'], {env: {TEST: \'foo\'}}); + +// options only. +child_process.spawn(\'echo\', {env: {FOO: 2}}); + +ls.stdout.on(\'data\', function(data) { + wc.stdin.write(data); +}); + +ls.stderr.on(\'data\', function(data) { + console.warn(data); +}); + +ls.on(\'close\', function(code) { + if (code !== 0) { + console.warn(\'\`ls\` exited with code %s\', code); + } + wc.stdin.end(); +}); + +wc.stdout.pipe(process.stdout); +wc.stderr.pipe(process.stderr); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var child_process = require(\"child_process\"); +var ls = child_process.spawn(\"ls\"); +var wc = child_process.spawn(\"wc\", [ \"-l\" ]); +// args + options. +child_process.spawn( + \"echo\", + [ \"-n\", \"\\\"Testing...\\\"\" ], + { env: { TEST: \"foo\" } } +); +// options only. +child_process.spawn(\"echo\", { env: { FOO: 2 } }); +ls.stdout.on( + \"data\", + function(data) { + wc.stdin.write(data); + } +); +ls.stderr.on( + \"data\", + function(data) { + console.warn(data); + } +); +ls.on( + \"close\", + function(code) { + if (code !== 0) { + console.warn(\"\`ls\` exited with code %s\", code); + } + wc.stdin.end(); + } +); +wc.stdout.pipe(process.stdout); +wc.stderr.pipe(process.stderr); + +" +`; diff --git a/tests/node_tests/child_process/exec.js b/tests/node_tests/child_process/exec.js new file mode 100644 index 000000000000..395a75b59946 --- /dev/null +++ b/tests/node_tests/child_process/exec.js @@ -0,0 +1,16 @@ +/* @flow */ + +var exec = require('child_process').exec; + +// callback only. +exec('ls', function(error, stdout, stderr) { + console.info(stdout); +}); + +// options only. +exec('ls', {timeout: 250}); + +// options + callback. +exec('ls', {maxBuffer: 100}, function(error, stdout, stderr) { + console.info(stdout); +}); diff --git a/tests/node_tests/child_process/execFile.js b/tests/node_tests/child_process/execFile.js new file mode 100644 index 000000000000..65963c46413e --- /dev/null +++ b/tests/node_tests/child_process/execFile.js @@ -0,0 +1,27 @@ +/* @flow */ + +var execFile = require('child_process').execFile; + +// args only. +execFile('ls', ['-lh']); + +// callback only. +execFile('ls', function(error, stdout, stderr) { + console.info(stdout); +}); + +// options only. +execFile('wc', {timeout: 250}); + +// args + callback. +execFile('ls', ['-l'], function(error, stdout, stderr) { + console.info(stdout); +}); + +// args + options. +execFile('ls', ['-l'], {timeout: 250}); + +// Put it all together. +execFile('ls', ['-l'], {timeout: 250}, function(error, stdout, stderr) { + console.info(stdout); +}); diff --git a/tests/node_tests/child_process/execSync.js b/tests/node_tests/child_process/execSync.js new file mode 100644 index 000000000000..171fd1748834 --- /dev/null +++ b/tests/node_tests/child_process/execSync.js @@ -0,0 +1,10 @@ +/* @flow */ + +var execSync = require('child_process').execSync; + +(execSync('ls'): Buffer); // returns Buffer +(execSync('ls', {encoding: 'buffer'}): Buffer); // returns Buffer +(execSync('ls', {encoding: 'utf8'}): string); // returns string +(execSync('ls', {timeout: '250'})); // error, no signatures match +(execSync('ls', {stdio: 'inherit'})); // error, no signatures match +(execSync('ls', {stdio: ['inherit']})); // error, no signatures match diff --git a/tests/node_tests/child_process/jsfmt.spec.js b/tests/node_tests/child_process/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/child_process/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/child_process/spawn.js b/tests/node_tests/child_process/spawn.js new file mode 100644 index 000000000000..760c3cf25c9d --- /dev/null +++ b/tests/node_tests/child_process/spawn.js @@ -0,0 +1,30 @@ +/* @flow */ + +var child_process = require('child_process'); + +var ls = child_process.spawn('ls'); +var wc = child_process.spawn('wc', ['-l']); + +// args + options. +child_process.spawn('echo', ['-n', '"Testing..."'], {env: {TEST: 'foo'}}); + +// options only. +child_process.spawn('echo', {env: {FOO: 2}}); + +ls.stdout.on('data', function(data) { + wc.stdin.write(data); +}); + +ls.stderr.on('data', function(data) { + console.warn(data); +}); + +ls.on('close', function(code) { + if (code !== 0) { + console.warn('`ls` exited with code %s', code); + } + wc.stdin.end(); +}); + +wc.stdout.pipe(process.stdout); +wc.stderr.pipe(process.stderr); diff --git a/tests/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..34bdcbc30cc0 --- /dev/null +++ b/tests/node_tests/crypto/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,57 @@ +exports[`test crypto.js 1`] = ` +"/* @flow */ + +const crypto = require(\'crypto\'); + +let tests = [ + // Hmac is a duplex stream + function() { + const hmac = crypto.createHmac(\'sha256\', \'a secret\'); + + hmac.on(\'readable\', () => { + (hmac.read(): ?(string | Buffer)); + (hmac.read(): number); // 4 errors: null, void, string, Buffer + }); + + hmac.write(\'some data to hash\'); + hmac.write(123); // 2 errors: not a string or a Buffer + hmac.end(); + }, + + // Hmac supports update and digest functions too + function(buf: Buffer) { + const hmac = crypto.createHmac(\'sha256\', \'a secret\'); + + hmac.update(\'some data to hash\'); + hmac.update(\'foo\', \'utf8\'); + hmac.update(\'foo\', \'bogus\'); // 1 error + hmac.update(buf); + hmac.update(buf, \'utf8\'); // 1 error: no encoding when passing a buffer + + // it\'s also chainable + (hmac.update(\'some data to hash\').update(buf).digest(): Buffer); + + (hmac.digest(\'hex\'): string); + (hmac.digest(): Buffer); + (hmac.digest(\'hex\'): void); // 1 error + (hmac.digest(): void); // 1 error + } +] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1412:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/node_tests/crypto/crypto.js b/tests/node_tests/crypto/crypto.js new file mode 100644 index 000000000000..a8544654e399 --- /dev/null +++ b/tests/node_tests/crypto/crypto.js @@ -0,0 +1,38 @@ +/* @flow */ + +const crypto = require('crypto'); + +let tests = [ + // Hmac is a duplex stream + function() { + const hmac = crypto.createHmac('sha256', 'a secret'); + + hmac.on('readable', () => { + (hmac.read(): ?(string | Buffer)); + (hmac.read(): number); // 4 errors: null, void, string, Buffer + }); + + hmac.write('some data to hash'); + hmac.write(123); // 2 errors: not a string or a Buffer + hmac.end(); + }, + + // Hmac supports update and digest functions too + function(buf: Buffer) { + const hmac = crypto.createHmac('sha256', 'a secret'); + + hmac.update('some data to hash'); + hmac.update('foo', 'utf8'); + hmac.update('foo', 'bogus'); // 1 error + hmac.update(buf); + hmac.update(buf, 'utf8'); // 1 error: no encoding when passing a buffer + + // it's also chainable + (hmac.update('some data to hash').update(buf).digest(): Buffer); + + (hmac.digest('hex'): string); + (hmac.digest(): Buffer); + (hmac.digest('hex'): void); // 1 error + (hmac.digest(): void); // 1 error + } +] diff --git a/tests/node_tests/crypto/jsfmt.spec.js b/tests/node_tests/crypto/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/crypto/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/fs/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/fs/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..76ebd2adc28a --- /dev/null +++ b/tests/node_tests/fs/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,76 @@ +exports[`test fs.js 1`] = ` +"var fs = require("fs"); + +/* readFile */ + +fs.readFile("file.exp", (_, data) => { + (data : Buffer); +}); + +fs.readFile("file.exp", "blah", (_, data) => { + (data : string); +}); + +fs.readFile("file.exp", { encoding: "blah" }, (_, data) => { + (data : string); +}); + +fs.readFile("file.exp", {}, (_, data) => { + (data : Buffer); +}); + +/* readFileSync */ + +(fs.readFileSync("file.exp") : Buffer); +(fs.readFileSync("file.exp") : string); // error + +(fs.readFileSync("file.exp", "blah") : string); +(fs.readFileSync("file.exp", "blah") : Buffer); // error + +(fs.readFileSync("file.exp", { encoding: "blah" }) : string); +(fs.readFileSync("file.exp", { encoding: "blah" }) : Buffer); // error + +(fs.readFileSync("file.exp", {}) : Buffer); +(fs.readFileSync("file.exp", {}) : string); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var fs = require("fs"); +/* readFile */ +fs.readFile( + "file.exp", + (_, data) => { + (data: Buffer); + } +); +fs.readFile( + "file.exp", + "blah", + (_, data) => { + (data: string); + } +); +fs.readFile( + "file.exp", + { encoding: "blah" }, + (_, data) => { + (data: string); + } +); +fs.readFile( + "file.exp", + {}, + (_, data) => { + (data: Buffer); + } +); +/* readFileSync */ +(fs.readFileSync("file.exp"): Buffer); +(fs.readFileSync("file.exp"): string);// error +(fs.readFileSync("file.exp", "blah"): string); +(fs.readFileSync("file.exp", "blah"): Buffer);// error +(fs.readFileSync("file.exp", { encoding: "blah" }): string); +(fs.readFileSync("file.exp", { encoding: "blah" }): Buffer);// error +(fs.readFileSync("file.exp", {}): Buffer); +(fs.readFileSync("file.exp", {}): string);// error + +" +`; diff --git a/tests/node_tests/fs/fs.js b/tests/node_tests/fs/fs.js new file mode 100644 index 000000000000..8a05bd98a384 --- /dev/null +++ b/tests/node_tests/fs/fs.js @@ -0,0 +1,33 @@ +var fs = require("fs"); + +/* readFile */ + +fs.readFile("file.exp", (_, data) => { + (data : Buffer); +}); + +fs.readFile("file.exp", "blah", (_, data) => { + (data : string); +}); + +fs.readFile("file.exp", { encoding: "blah" }, (_, data) => { + (data : string); +}); + +fs.readFile("file.exp", {}, (_, data) => { + (data : Buffer); +}); + +/* readFileSync */ + +(fs.readFileSync("file.exp") : Buffer); +(fs.readFileSync("file.exp") : string); // error + +(fs.readFileSync("file.exp", "blah") : string); +(fs.readFileSync("file.exp", "blah") : Buffer); // error + +(fs.readFileSync("file.exp", { encoding: "blah" }) : string); +(fs.readFileSync("file.exp", { encoding: "blah" }) : Buffer); // error + +(fs.readFileSync("file.exp", {}) : Buffer); +(fs.readFileSync("file.exp", {}) : string); // error diff --git a/tests/node_tests/fs/jsfmt.spec.js b/tests/node_tests/fs/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/fs/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/json_file/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/json_file/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5d8a9dd3ad97 --- /dev/null +++ b/tests/node_tests/json_file/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,42 @@ +exports[`test test.js 1`] = ` +"// @flow + +let data = require(\'./package/index.json\'); +(data.foo: void); // error, should be object literal +(data.foo.bar: void); // error, should be boolean +(data.abc: boolean); // error, should be ?string + +let data2 = require(\'./package\'); +(data2.baz: void); // error, should be string + +let data3 = require(\'./package2\'); +(data3.foo: void); // error, should be number (not string! index.js wins) + +let data4 = require(\'./json_array\'); +(data4: Array); +(data4: void); // error, should be Array + +(require(\'./json_string\'): void); // error, should be string +(require(\'./json_number\'): void); // error, should be number +(require(\'./json_true\'): void); // error, should be true +(require(\'./json_false\'): void); // error, should be false +(require(\'./json_null\'): void); // error, should be null +(require(\'./json_negative_number\'): -1); // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/node_tests/json_file/jsfmt.spec.js b/tests/node_tests/json_file/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/json_file/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/json_file/package2/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/json_file/package2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fd6af48c9dd6 --- /dev/null +++ b/tests/node_tests/json_file/package2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,12 @@ +exports[`test index.js 1`] = ` +"// @flow + +module.exports = { + foo: 123 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +module.exports = { foo: 123 }; + +" +`; diff --git a/tests/node_tests/json_file/package2/index.js b/tests/node_tests/json_file/package2/index.js new file mode 100644 index 000000000000..30453d22029a --- /dev/null +++ b/tests/node_tests/json_file/package2/index.js @@ -0,0 +1,5 @@ +// @flow + +module.exports = { + foo: 123 +}; diff --git a/tests/node_tests/json_file/package2/jsfmt.spec.js b/tests/node_tests/json_file/package2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/json_file/package2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/json_file/test.js b/tests/node_tests/json_file/test.js new file mode 100644 index 000000000000..c18576cfc6cf --- /dev/null +++ b/tests/node_tests/json_file/test.js @@ -0,0 +1,23 @@ +// @flow + +let data = require('./package/index.json'); +(data.foo: void); // error, should be object literal +(data.foo.bar: void); // error, should be boolean +(data.abc: boolean); // error, should be ?string + +let data2 = require('./package'); +(data2.baz: void); // error, should be string + +let data3 = require('./package2'); +(data3.foo: void); // error, should be number (not string! index.js wins) + +let data4 = require('./json_array'); +(data4: Array); +(data4: void); // error, should be Array + +(require('./json_string'): void); // error, should be string +(require('./json_number'): void); // error, should be number +(require('./json_true'): void); // error, should be true +(require('./json_false'): void); // error, should be false +(require('./json_null'): void); // error, should be null +(require('./json_negative_number'): -1); // ok diff --git a/tests/node_tests/os/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/os/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fb845385abea --- /dev/null +++ b/tests/node_tests/os/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,31 @@ +exports[`test userInfo.js 1`] = ` +"/* @flow */ + +var os = require('os'); + +var u1 = os.userInfo(); +(u1.username: string); +(u1.username: Buffer); // error + +var u2 = os.userInfo({encoding: 'utf8'}); +(u2.username: string); +(u2.username: Buffer); // error + +var u3 = os.userInfo({encoding: 'buffer'}); +(u3.username: string); // error +(u3.username: Buffer); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var os = require("os"); +var u1 = os.userInfo(); +(u1.username: string); +(u1.username: Buffer);// error +var u2 = os.userInfo({ encoding: "utf8" }); +(u2.username: string); +(u2.username: Buffer);// error +var u3 = os.userInfo({ encoding: "buffer" }); +(u3.username: string);// error +(u3.username: Buffer); + +" +`; diff --git a/tests/node_tests/os/jsfmt.spec.js b/tests/node_tests/os/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/os/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/os/userInfo.js b/tests/node_tests/os/userInfo.js new file mode 100644 index 000000000000..d2644f249bc6 --- /dev/null +++ b/tests/node_tests/os/userInfo.js @@ -0,0 +1,15 @@ +/* @flow */ + +var os = require('os'); + +var u1 = os.userInfo(); +(u1.username: string); +(u1.username: Buffer); // error + +var u2 = os.userInfo({encoding: 'utf8'}); +(u2.username: string); +(u2.username: Buffer); // error + +var u3 = os.userInfo({encoding: 'buffer'}); +(u3.username: string); // error +(u3.username: Buffer); diff --git a/tests/node_tests/package_file/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/package_file/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..addfa1957571 --- /dev/null +++ b/tests/node_tests/package_file/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test bar_lib.js 1`] = ` +"module.exports = "bar_lib"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = "bar_lib"; + +" +`; + +exports[`test foo.js 1`] = ` +"var x: string = require('./bar_lib'); // 'bar_lib' does not work! +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: string = require("./bar_lib");// 'bar_lib' does not work! +console.log(x); + +" +`; diff --git a/tests/node_tests/package_file/bar_lib.js b/tests/node_tests/package_file/bar_lib.js new file mode 100644 index 000000000000..411baf0101f2 --- /dev/null +++ b/tests/node_tests/package_file/bar_lib.js @@ -0,0 +1 @@ +module.exports = "bar_lib"; diff --git a/tests/node_tests/package_file/bar_lib/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/package_file/bar_lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e0181c12d007 --- /dev/null +++ b/tests/node_tests/package_file/bar_lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test bar.js 1`] = ` +"module.exports = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = 0; + +" +`; diff --git a/tests/node_tests/package_file/bar_lib/bar.js b/tests/node_tests/package_file/bar_lib/bar.js new file mode 100644 index 000000000000..d5b2e8bb3efb --- /dev/null +++ b/tests/node_tests/package_file/bar_lib/bar.js @@ -0,0 +1 @@ +module.exports = 0; diff --git a/tests/node_tests/package_file/bar_lib/jsfmt.spec.js b/tests/node_tests/package_file/bar_lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/package_file/bar_lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/package_file/foo.js b/tests/node_tests/package_file/foo.js new file mode 100644 index 000000000000..24c3a1e4a93e --- /dev/null +++ b/tests/node_tests/package_file/foo.js @@ -0,0 +1,2 @@ +var x: string = require('./bar_lib'); // 'bar_lib' does not work! +console.log(x); diff --git a/tests/node_tests/package_file/jsfmt.spec.js b/tests/node_tests/package_file/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/package_file/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/package_file_node_modules/foo/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/package_file_node_modules/foo/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d1860d5e0c67 --- /dev/null +++ b/tests/node_tests/package_file_node_modules/foo/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x: string = require('bar_lib'); // 'bar_lib' does not work! +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: string = require("bar_lib");// 'bar_lib' does not work! +console.log(x); + +" +`; diff --git a/tests/node_tests/package_file_node_modules/foo/foo.js b/tests/node_tests/package_file_node_modules/foo/foo.js new file mode 100644 index 000000000000..680a16b26253 --- /dev/null +++ b/tests/node_tests/package_file_node_modules/foo/foo.js @@ -0,0 +1,2 @@ +var x: string = require('bar_lib'); // 'bar_lib' does not work! +console.log(x); diff --git a/tests/node_tests/package_file_node_modules/foo/jsfmt.spec.js b/tests/node_tests/package_file_node_modules/foo/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/package_file_node_modules/foo/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/path_node_modules/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/path_node_modules/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c35d8d2fd0f5 --- /dev/null +++ b/tests/node_tests/path_node_modules/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('bar_lib/src/lib/bar'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("bar_lib/src/lib/bar"); +console.log(x); + +" +`; diff --git a/tests/node_tests/path_node_modules/foo.js b/tests/node_tests/path_node_modules/foo.js new file mode 100644 index 000000000000..ff7947a598eb --- /dev/null +++ b/tests/node_tests/path_node_modules/foo.js @@ -0,0 +1,2 @@ +var x = require('bar_lib/src/lib/bar'); +console.log(x); diff --git a/tests/node_tests/path_node_modules/jsfmt.spec.js b/tests/node_tests/path_node_modules/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/path_node_modules/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/path_node_modules_with_short_main/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/path_node_modules_with_short_main/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f63b520200fb --- /dev/null +++ b/tests/node_tests/path_node_modules_with_short_main/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('bar_lib'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("bar_lib"); +console.log(x); + +" +`; diff --git a/tests/node_tests/path_node_modules_with_short_main/foo.js b/tests/node_tests/path_node_modules_with_short_main/foo.js new file mode 100644 index 000000000000..bb32aaa21c20 --- /dev/null +++ b/tests/node_tests/path_node_modules_with_short_main/foo.js @@ -0,0 +1,2 @@ +var x = require('bar_lib'); +console.log(x); diff --git a/tests/node_tests/path_node_modules_with_short_main/jsfmt.spec.js b/tests/node_tests/path_node_modules_with_short_main/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/path_node_modules_with_short_main/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/path_node_modules_without_main/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/path_node_modules_without_main/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f63b520200fb --- /dev/null +++ b/tests/node_tests/path_node_modules_without_main/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('bar_lib'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("bar_lib"); +console.log(x); + +" +`; diff --git a/tests/node_tests/path_node_modules_without_main/foo.js b/tests/node_tests/path_node_modules_without_main/foo.js new file mode 100644 index 000000000000..bb32aaa21c20 --- /dev/null +++ b/tests/node_tests/path_node_modules_without_main/foo.js @@ -0,0 +1,2 @@ +var x = require('bar_lib'); +console.log(x); diff --git a/tests/node_tests/path_node_modules_without_main/jsfmt.spec.js b/tests/node_tests/path_node_modules_without_main/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/path_node_modules_without_main/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/path_package/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/path_package/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bfaab3d36a4f --- /dev/null +++ b/tests/node_tests/path_package/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test foo.js 1`] = ` +"var x = require('bar_lib/src/lib'); +console.log(x); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = require("bar_lib/src/lib"); +console.log(x); + +" +`; diff --git a/tests/node_tests/path_package/foo.js b/tests/node_tests/path_package/foo.js new file mode 100644 index 000000000000..a063eb60223b --- /dev/null +++ b/tests/node_tests/path_package/foo.js @@ -0,0 +1,2 @@ +var x = require('bar_lib/src/lib'); +console.log(x); diff --git a/tests/node_tests/path_package/jsfmt.spec.js b/tests/node_tests/path_package/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/path_package/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/stream/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/stream/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3c48fa7d08e2 --- /dev/null +++ b/tests/node_tests/stream/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,84 @@ +exports[`test stream.js 1`] = ` +"/* @flow */ + +var child_process = require('child_process'); +var fs = require('fs'); +var stream = require('stream'); +var ls = child_process.spawn('ls'); + +var data = "foo"; + +ls.stdin.write(data); +ls.stdin.write(data, "utf-8"); +ls.stdin.write(data, () => {}); +ls.stdin.write(data, "utf-8", () => {}); + +ls.stdin.end(); +ls.stdin.end(data); +ls.stdin.end(data, "utf-8"); +ls.stdin.end(data, () => {}); +ls.stdin.end(data, "utf-8", () => {}); + +var ws = fs.createWriteStream('/dev/null'); +ls.stdout.pipe(ws).end(); + +class MyReadStream extends stream.Readable {} +class MyWriteStream extends stream.Writable {} +class MyDuplex extends stream.Duplex {} +class MyTransform extends stream.Duplex {} + +new MyReadStream() + .pipe(new MyDuplex()) + .pipe(new MyTransform()) + .pipe(new MyWriteStream()); + +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var child_process = require("child_process"); +var fs = require("fs"); +var stream = require("stream"); +var ls = child_process.spawn("ls"); +var data = "foo"; +ls.stdin.write(data); +ls.stdin.write(data, "utf-8"); +ls.stdin.write( + data, + () => { + + } +); +ls.stdin.write( + data, + "utf-8", + () => { + + } +); +ls.stdin.end(); +ls.stdin.end(data); +ls.stdin.end(data, "utf-8"); +ls.stdin.end( + data, + () => { + + } +); +ls.stdin.end( + data, + "utf-8", + () => { + + } +); +var ws = fs.createWriteStream("/dev/null"); +ls.stdout.pipe(ws).end(); +class MyReadStream extends stream.Readable {} +class MyWriteStream extends stream.Writable {} +class MyDuplex extends stream.Duplex {} +class MyTransform extends stream.Duplex {} +new MyReadStream().pipe(new MyDuplex()).pipe(new MyTransform()).pipe( + new MyWriteStream() +); + +" +`; diff --git a/tests/node_tests/stream/jsfmt.spec.js b/tests/node_tests/stream/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/stream/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/stream/stream.js b/tests/node_tests/stream/stream.js new file mode 100644 index 000000000000..61cd149e3f64 --- /dev/null +++ b/tests/node_tests/stream/stream.js @@ -0,0 +1,33 @@ +/* @flow */ + +var child_process = require('child_process'); +var fs = require('fs'); +var stream = require('stream'); +var ls = child_process.spawn('ls'); + +var data = "foo"; + +ls.stdin.write(data); +ls.stdin.write(data, "utf-8"); +ls.stdin.write(data, () => {}); +ls.stdin.write(data, "utf-8", () => {}); + +ls.stdin.end(); +ls.stdin.end(data); +ls.stdin.end(data, "utf-8"); +ls.stdin.end(data, () => {}); +ls.stdin.end(data, "utf-8", () => {}); + +var ws = fs.createWriteStream('/dev/null'); +ls.stdout.pipe(ws).end(); + +class MyReadStream extends stream.Readable {} +class MyWriteStream extends stream.Writable {} +class MyDuplex extends stream.Duplex {} +class MyTransform extends stream.Duplex {} + +new MyReadStream() + .pipe(new MyDuplex()) + .pipe(new MyTransform()) + .pipe(new MyWriteStream()); + diff --git a/tests/node_tests/timers/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/timers/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..309a91c9044f --- /dev/null +++ b/tests/node_tests/timers/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test timers.js 1`] = ` +"// @flow + +function setImmediateCallback(): number { + return 0; +} + +setImmediate(setImmediateCallback); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function setImmediateCallback(): number { + return 0; +} +setImmediate(setImmediateCallback); + +" +`; diff --git a/tests/node_tests/timers/jsfmt.spec.js b/tests/node_tests/timers/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/timers/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/timers/timers.js b/tests/node_tests/timers/timers.js new file mode 100644 index 000000000000..28f9462aea1b --- /dev/null +++ b/tests/node_tests/timers/timers.js @@ -0,0 +1,7 @@ +// @flow + +function setImmediateCallback(): number { + return 0; +} + +setImmediate(setImmediateCallback); diff --git a/tests/node_tests/url/__snapshots__/jsfmt.spec.js.snap b/tests/node_tests/url/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..786180dca476 --- /dev/null +++ b/tests/node_tests/url/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test url.js 1`] = ` +"const url = require('url'); +url.format(url.parse('https://example.com/foo')); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +const url = require("url"); +url.format(url.parse("https://example.com/foo")); + +" +`; diff --git a/tests/node_tests/url/jsfmt.spec.js b/tests/node_tests/url/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/node_tests/url/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/node_tests/url/url.js b/tests/node_tests/url/url.js new file mode 100644 index 000000000000..45b9072eda4b --- /dev/null +++ b/tests/node_tests/url/url.js @@ -0,0 +1,2 @@ +const url = require('url'); +url.format(url.parse('https://example.com/foo')); diff --git a/tests/nullable/__snapshots__/jsfmt.spec.js.snap b/tests/nullable/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3beb79eaa81c --- /dev/null +++ b/tests/nullable/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,77 @@ +exports[`test maybe.js 1`] = ` +"// @flow + +// unwrapping nested maybes should work +((\'foo\': ?(?string)): ?string); // ok +((123: ?(?number)): ?string); // error (only num ~> string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// unwrapping nested maybes should work +((\"foo\": ??string): ?string);// ok +((123: ??number): ?string);// error (only num ~> string) + +" +`; + +exports[`test nullable.js 1`] = ` +"function foo():string { return null; } + +function bar():?string { return null; } + +function qux(x:string) { } + +function corge(x:number) { } + +var x = bar(); // x: ?string +if (x != null) qux(x); // x: ?string | null +if (x != null) corge(x); // x: ?string | null + +function grault() { x = null; } +if (x != null) { + grault(); qux(x); +} + +var array_of_nullable: Array = [null, 3]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test simple_nullable.js 1`] = ` +"function foo(x:?string) {} +function bar(x:?number) {} +foo(\'hmm\'); +bar(\'hmm\'); + +function fn(data: ?{}) {} +fn({some: \'literal\'}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(x: ?string) { + +} +function bar(x: ?number) { + +} +foo(\"hmm\"); +bar(\"hmm\"); +function fn(data: ?{}) { + +} +fn({ some: \"literal\" }); + +" +`; diff --git a/tests/nullable/jsfmt.spec.js b/tests/nullable/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/nullable/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/nullable/maybe.js b/tests/nullable/maybe.js new file mode 100644 index 000000000000..f6bb901ab3ef --- /dev/null +++ b/tests/nullable/maybe.js @@ -0,0 +1,5 @@ +// @flow + +// unwrapping nested maybes should work +(('foo': ?(?string)): ?string); // ok +((123: ?(?number)): ?string); // error (only num ~> string) diff --git a/tests/nullable/nullable.js b/tests/nullable/nullable.js new file mode 100644 index 000000000000..642e8a55b0f1 --- /dev/null +++ b/tests/nullable/nullable.js @@ -0,0 +1,18 @@ +function foo():string { return null; } + +function bar():?string { return null; } + +function qux(x:string) { } + +function corge(x:number) { } + +var x = bar(); // x: ?string +if (x != null) qux(x); // x: ?string | null +if (x != null) corge(x); // x: ?string | null + +function grault() { x = null; } +if (x != null) { + grault(); qux(x); +} + +var array_of_nullable: Array = [null, 3]; diff --git a/tests/nullable/simple_nullable.js b/tests/nullable/simple_nullable.js new file mode 100644 index 000000000000..d537956c14e5 --- /dev/null +++ b/tests/nullable/simple_nullable.js @@ -0,0 +1,7 @@ +function foo(x:?string) {} +function bar(x:?number) {} +foo('hmm'); +bar('hmm'); + +function fn(data: ?{}) {} +fn({some: 'literal'}); diff --git a/tests/number_constants/__snapshots__/jsfmt.spec.js.snap b/tests/number_constants/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1c8a6bf8971a --- /dev/null +++ b/tests/number_constants/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,29 @@ +exports[`test number_constants.js 1`] = ` +"var a: number = Number.MAX_SAFE_INTEGER; +var b: string = Number.MAX_SAFE_INTEGER; +var c: number = Number.MIN_SAFE_INTEGER; +var d: string = Number.MIN_SAFE_INTEGER; +var e: number = Number.MAX_VALUE; +var f: string = Number.MAX_VALUE; +var g: number = Number.MIN_VALUE; +var h: string = Number.MIN_VALUE; +var i: number = Number.NaN; +var j: string = Number.NaN; +var k: number = Number.EPSILON; +var l: string = Number.EPSILON; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a: number = Number.MAX_SAFE_INTEGER; +var b: string = Number.MAX_SAFE_INTEGER; +var c: number = Number.MIN_SAFE_INTEGER; +var d: string = Number.MIN_SAFE_INTEGER; +var e: number = Number.MAX_VALUE; +var f: string = Number.MAX_VALUE; +var g: number = Number.MIN_VALUE; +var h: string = Number.MIN_VALUE; +var i: number = Number.NaN; +var j: string = Number.NaN; +var k: number = Number.EPSILON; +var l: string = Number.EPSILON; + +" +`; diff --git a/tests/number_constants/jsfmt.spec.js b/tests/number_constants/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/number_constants/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/number_constants/number_constants.js b/tests/number_constants/number_constants.js new file mode 100644 index 000000000000..51f89d21e00f --- /dev/null +++ b/tests/number_constants/number_constants.js @@ -0,0 +1,12 @@ +var a: number = Number.MAX_SAFE_INTEGER; +var b: string = Number.MAX_SAFE_INTEGER; +var c: number = Number.MIN_SAFE_INTEGER; +var d: string = Number.MIN_SAFE_INTEGER; +var e: number = Number.MAX_VALUE; +var f: string = Number.MAX_VALUE; +var g: number = Number.MIN_VALUE; +var h: string = Number.MIN_VALUE; +var i: number = Number.NaN; +var j: string = Number.NaN; +var k: number = Number.EPSILON; +var l: string = Number.EPSILON; diff --git a/tests/object-method/__snapshots__/jsfmt.spec.js.snap b/tests/object-method/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..96b4ef5f3b1e --- /dev/null +++ b/tests/object-method/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,150 @@ +exports[`test id.js 1`] = ` +"declare function id(_: X): X; + +module.exports = id; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test subtype.js 1`] = ` +"interface Interface { + m(): void; +} +import type { ObjectType } from \'./test\'; + +function subtypeCheck(x: Interface): ObjectType { return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test test.js 1`] = ` +"const id = require(\'./id\'); + +export type ObjectType = { + +m: () => void, +}; + +function methodCaller(x: ObjectType) { + x.m(); +}; + +module.exports = id( + methodCaller +); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"/* @flow */ + +function f() { + return this.p; +} + +var a = { + p: 0, + f +} + +var b = { + f +} + +a.f(); // okey-dokie +b.f(); // error, property \`p\` not found +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function f() { + return this.p; +} +var a = { p: 0, f }; +var b = { f }; +a.f();// okey-dokie +b.f();// error, property \`p\` not found + +" +`; + +exports[`test test3.js 1`] = ` +"/* @flow */ + +function foo() { + this.m(); +} + +function bar(f: () => void) { + f(); // passing global object as \`this\` + ({ f }).f(); // passing container object as \`this\` +} + +bar(foo); // error, since \`this\` is used non-trivially in \`foo\` + +function qux(o: { f: () => void }) { + o.f(); // passing o as \`this\` +} + +qux({ f: foo }); // error, since \`this\` is used non-trivially in \`foo\` +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/object-method/id.js b/tests/object-method/id.js new file mode 100644 index 000000000000..73650e97515d --- /dev/null +++ b/tests/object-method/id.js @@ -0,0 +1,3 @@ +declare function id(_: X): X; + +module.exports = id; diff --git a/tests/object-method/jsfmt.spec.js b/tests/object-method/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/object-method/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/object-method/subtype.js b/tests/object-method/subtype.js new file mode 100644 index 000000000000..810b2c8d0ffe --- /dev/null +++ b/tests/object-method/subtype.js @@ -0,0 +1,6 @@ +interface Interface { + m(): void; +} +import type { ObjectType } from './test'; + +function subtypeCheck(x: Interface): ObjectType { return x; } diff --git a/tests/object-method/test.js b/tests/object-method/test.js new file mode 100644 index 000000000000..033b1abf3229 --- /dev/null +++ b/tests/object-method/test.js @@ -0,0 +1,13 @@ +const id = require('./id'); + +export type ObjectType = { + +m: () => void, +}; + +function methodCaller(x: ObjectType) { + x.m(); +}; + +module.exports = id( + methodCaller +); diff --git a/tests/object-method/test2.js b/tests/object-method/test2.js new file mode 100644 index 000000000000..652c93c8735f --- /dev/null +++ b/tests/object-method/test2.js @@ -0,0 +1,17 @@ +/* @flow */ + +function f() { + return this.p; +} + +var a = { + p: 0, + f +} + +var b = { + f +} + +a.f(); // okey-dokie +b.f(); // error, property `p` not found diff --git a/tests/object-method/test3.js b/tests/object-method/test3.js new file mode 100644 index 000000000000..365e8e460805 --- /dev/null +++ b/tests/object-method/test3.js @@ -0,0 +1,18 @@ +/* @flow */ + +function foo() { + this.m(); +} + +function bar(f: () => void) { + f(); // passing global object as `this` + ({ f }).f(); // passing container object as `this` +} + +bar(foo); // error, since `this` is used non-trivially in `foo` + +function qux(o: { f: () => void }) { + o.f(); // passing o as `this` +} + +qux({ f: foo }); // error, since `this` is used non-trivially in `foo` diff --git a/tests/object_annot/__snapshots__/jsfmt.spec.js.snap b/tests/object_annot/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..83a6c2b5f013 --- /dev/null +++ b/tests/object_annot/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test test.js 1`] = ` +"function foo(x: Array): Array { + return x.sort((a, b) => a.foo - b.foo); +} + +// Make sure Object works with Object.keys() +function bar(x: Object): Array { + return Object.keys(x); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/object_annot/jsfmt.spec.js b/tests/object_annot/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/object_annot/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/object_annot/test.js b/tests/object_annot/test.js new file mode 100644 index 000000000000..88565b11935c --- /dev/null +++ b/tests/object_annot/test.js @@ -0,0 +1,8 @@ +function foo(x: Array): Array { + return x.sort((a, b) => a.foo - b.foo); +} + +// Make sure Object works with Object.keys() +function bar(x: Object): Array { + return Object.keys(x); +} diff --git a/tests/object_api/__snapshots__/jsfmt.spec.js.snap b/tests/object_api/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..53a9dd7b2de1 --- /dev/null +++ b/tests/object_api/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,401 @@ +exports[`test a.js 1`] = ` +"/* @flow */ + +module.exports = { a() {} };~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports = { + a() { + + } +}; + +" +`; + +exports[`test b.js 1`] = ` +"/* @flow */ + +var a = require(\'./a\'); +var b = Object.assign({ bar() {}, ...{} }, a); +b.a(); // works here +module.exports = b; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var a = require(\"./a\"); +var b = Object.assign( + { + bar() { + + }, + ...{} + }, + a +); +b.a();// works here +module.exports = b; + +" +`; + +exports[`test c.js 1`] = ` +"/* @flow */ + +var c = require(\'./b\'); +c.a(); +c.foo();~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var c = require(\"./b\"); +c.a(); +c.foo(); + +" +`; + +exports[`test object_assign.js 1`] = ` +"/* @flow */ + +var export_ = Object.assign({}, { + foo: function(param) { return param; } +}); + +var decl_export_: { foo: any; bar: any } = Object.assign({}, export_); + +let anyObj: Object = {}; +Object.assign(anyObj, anyObj); // makes sure this terminates + +module.exports = export_; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var export_ = Object.assign( + {}, + { + foo: function(param) { + return param; + } + } +); +var decl_export_: { foo: any, bar: any } = Object.assign({}, export_); +let anyObj: Object = {}; +Object.assign(anyObj, anyObj);// makes sure this terminates +module.exports = export_; + +" +`; + +exports[`test object_create.js 1`] = ` +"/* @flow */ + +class C { foo: string; } + +// OK, \`instanceof C\` would be true +(Object.create(C.prototype): C); + +// OK, \`instanceof C\` would be true +(Object.create(new C): C); + +// error, object literals don\'t structurally match instances +({ foo: \"foo\" }: C); + +// error, object types don\'t structurally match instances +type O = { foo: string; } +declare var o: O; +(o: C); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class C { + foo: string; +} +// OK, \`instanceof C\` would be true +(Object.create(C.prototype): C); +// OK, \`instanceof C\` would be true +(Object.create(new C()): C); +// error, object literals don\'t structurally match instances +({ foo: \"foo\" }: C); +// error, object types don\'t structurally match instances +type O = { foo: string }; +declare var o: O; +(o: C); + +" +`; + +exports[`test object_getprototypeof.js 1`] = ` +"// @flow + +class Foo {} +class Bar extends Foo {} + +let tests = [ + function() { + const x = new Bar(); + (Object.getPrototypeOf(x): Foo); + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class Foo {} +class Bar extends Foo {} +let tests = [ + function() { + const x = new Bar(); + (Object.getPrototypeOf(x): Foo); + } +]; + +" +`; + +exports[`test object_keys.js 1`] = ` +"/* @flow */ + +var sealed = {one: \'one\', two: \'two\'}; +(Object.keys(sealed): Array<\'one\'|\'two\'>); +(Object.keys(sealed): void); // error, Array + +var unsealed = {}; +Object.keys(unsealed).forEach(k => { + (k : number) // error: number ~> string +}); + +var dict: { [k: number]: string } = {}; +Object.keys(dict).forEach(k => { + (k : number) // error: number ~> string +}); + +var any: Object = {}; +(Object.keys(any): Array); // error, Array + +class Foo { + prop: string; + foo() {} +} +// constructor and foo not enumerable +(Object.keys(new Foo()): Array<\'error\'>); // error: prop ~> error + +class Bar extends Foo { + bar_prop: string; + bar() {} +} +// only own enumerable props +(Object.keys(new Bar()): Array<\'error\'>); // error: bar_prop ~> error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test object_missing.js 1`] = ` +"// @flow + +let tests = [ + function() { + Object.doesNotExist(); + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + function() { + Object.doesNotExist(); + } +]; + +" +`; + +exports[`test object_prototype.js 1`] = ` +"/* @flow */ + +function takesABool(x: boolean) {} +function takesAString(x: string) {} +function takesANumber(x: number) {} +function takesAnObject(x: Object) {} + +class Foo {} + +var a = { foo: \'bar\' }; +var b = { foo: \'bar\', ...{}}; +var c = { foo: \'bar\', toString: function(): number { return 123; }}; +var d : { [key: string]: string } = { foo: \'bar\' }; +var x = new Date(); +var y = new Foo(); + +// +// toString +// + +// call +takesAString(a.toString()); +d.toString(); // ok, even though dict specifies strings, this is a function + +// get +var aToString : () => string = a.toString; +var aToString2 = a.toString; +takesAString(aToString2()); + +// set +b.toString = function(): string { return \'foo\'; }; +c.toString = function(): number { return 123; }; + +// override +var cToString : () => number = c.toString; + +// ... on a built-in instance +var xToString : number = x.toString; // error +var xToString2 : () => number = x.toString; // error +takesAString(x.toString()); + +// ... on an instance +var yToString : number = y.toString; // error +takesAString(y.toString()); + +// ... on a primitive +(123).toString(); +(123).toString; +(123).toString = function() {}; // error +(123).toString(2); +(123).toString(\'foo\'); // error +(123).toString(null); // error + + +// +// hasOwnProperty +// + +// call +takesABool(a.hasOwnProperty(\'foo\')); + +// get +var aHasOwnProperty : (prop: string) => boolean = a.hasOwnProperty; +var aHasOwnProperty2 = a.hasOwnProperty; +takesABool(aHasOwnProperty2(\'bar\')); + +// set +b.hasOwnProperty = function() { return false; }; + +// ... on a built-in instance +var xHasOwnProperty : number = x.hasOwnProperty; // error +var xHasOwnProperty2 : (prop: string) => number = x.hasOwnProperty; // error +takesABool(x.hasOwnProperty(\'foo\')); + +// ... on an instance +var yHasOwnProperty : number = y.hasOwnProperty; // error +takesABool(y.hasOwnProperty(\'foo\')); + + +// +// propertyIsEnumerable +// + +// call +takesABool(a.propertyIsEnumerable(\'foo\')); + +// get +var aPropertyIsEnumerable : (prop: string) => boolean = a.propertyIsEnumerable; +var aPropertyIsEnumerable2 = a.propertyIsEnumerable; +takesABool(aPropertyIsEnumerable2(\'bar\')); + +// set +b.propertyIsEnumerable = function() { return false; }; + +// ... on a built-in instance +var xPropertyIsEnumerable : number = x.propertyIsEnumerable; // error +var xPropertyIsEnumerable2 : (prop: string) => number = + x.propertyIsEnumerable; // error +takesABool(x.propertyIsEnumerable(\'foo\')); + +// ... on an instance +var yPropertyIsEnumerable : number = y.propertyIsEnumerable; // error +takesABool(y.propertyIsEnumerable(\'foo\')); + + +// +// valueOf +// + +// call +takesAnObject(a.valueOf()); + +// get +var aValueOf : () => Object = a.valueOf; +var aValueOf2 = a.valueOf; +takesAnObject(aValueOf2()); + +// set +b.valueOf = function() { return {}; }; + +// ... on a built-in instance +var xValueOf : number = x.valueOf; // error +takesANumber(x.valueOf()); + +// ... on an instance +var yValueOf : number = y.valueOf; // error +takesAnObject(y.valueOf()); + +// ... on a literal +var strValueOf : string = (\"foo\").valueOf(); +var numValueOf : number = (123).valueOf(); +var boolValueOf : boolean = (true).valueOf(); + +// +// toLocaleString +// + +// call +takesAString(a.toLocaleString()); + +// get +var aToLocaleString : () => string = a.toLocaleString; +var aToLocaleString2 = a.toLocaleString; +takesAString(aToLocaleString2()); + +// set +b.toLocaleString = function() { return \'derp\'; }; + +// ... on a built-in instance +var xToLocaleString : number = x.toLocaleString; // error +var xToLocaleString2 : () => number = x.toLocaleString; // error +takesAString(x.toLocaleString()); + +// ... on an instance +var yToLocaleString : number = y.toLocaleString; // error +takesAString(y.toLocaleString()); + + +// +// constructor +// + +var k : Object = a.constructor; +(123).constructor; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/object_api/a.js b/tests/object_api/a.js new file mode 100644 index 000000000000..934ca8eb8e02 --- /dev/null +++ b/tests/object_api/a.js @@ -0,0 +1,3 @@ +/* @flow */ + +module.exports = { a() {} }; \ No newline at end of file diff --git a/tests/object_api/b.js b/tests/object_api/b.js new file mode 100644 index 000000000000..8b324fb26c73 --- /dev/null +++ b/tests/object_api/b.js @@ -0,0 +1,6 @@ +/* @flow */ + +var a = require('./a'); +var b = Object.assign({ bar() {}, ...{} }, a); +b.a(); // works here +module.exports = b; diff --git a/tests/object_api/c.js b/tests/object_api/c.js new file mode 100644 index 000000000000..69a6c4b46ea1 --- /dev/null +++ b/tests/object_api/c.js @@ -0,0 +1,5 @@ +/* @flow */ + +var c = require('./b'); +c.a(); +c.foo(); \ No newline at end of file diff --git a/tests/object_api/jsfmt.spec.js b/tests/object_api/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/object_api/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/object_api/object_assign.js b/tests/object_api/object_assign.js new file mode 100644 index 000000000000..16e86b66e88c --- /dev/null +++ b/tests/object_api/object_assign.js @@ -0,0 +1,12 @@ +/* @flow */ + +var export_ = Object.assign({}, { + foo: function(param) { return param; } +}); + +var decl_export_: { foo: any; bar: any } = Object.assign({}, export_); + +let anyObj: Object = {}; +Object.assign(anyObj, anyObj); // makes sure this terminates + +module.exports = export_; diff --git a/tests/object_api/object_create.js b/tests/object_api/object_create.js new file mode 100644 index 000000000000..b73c200590db --- /dev/null +++ b/tests/object_api/object_create.js @@ -0,0 +1,17 @@ +/* @flow */ + +class C { foo: string; } + +// OK, `instanceof C` would be true +(Object.create(C.prototype): C); + +// OK, `instanceof C` would be true +(Object.create(new C): C); + +// error, object literals don't structurally match instances +({ foo: "foo" }: C); + +// error, object types don't structurally match instances +type O = { foo: string; } +declare var o: O; +(o: C); diff --git a/tests/object_api/object_getprototypeof.js b/tests/object_api/object_getprototypeof.js new file mode 100644 index 000000000000..74d5355376f2 --- /dev/null +++ b/tests/object_api/object_getprototypeof.js @@ -0,0 +1,11 @@ +// @flow + +class Foo {} +class Bar extends Foo {} + +let tests = [ + function() { + const x = new Bar(); + (Object.getPrototypeOf(x): Foo); + }, +]; diff --git a/tests/object_api/object_keys.js b/tests/object_api/object_keys.js new file mode 100644 index 000000000000..2af5c7fc21d6 --- /dev/null +++ b/tests/object_api/object_keys.js @@ -0,0 +1,32 @@ +/* @flow */ + +var sealed = {one: 'one', two: 'two'}; +(Object.keys(sealed): Array<'one'|'two'>); +(Object.keys(sealed): void); // error, Array + +var unsealed = {}; +Object.keys(unsealed).forEach(k => { + (k : number) // error: number ~> string +}); + +var dict: { [k: number]: string } = {}; +Object.keys(dict).forEach(k => { + (k : number) // error: number ~> string +}); + +var any: Object = {}; +(Object.keys(any): Array); // error, Array + +class Foo { + prop: string; + foo() {} +} +// constructor and foo not enumerable +(Object.keys(new Foo()): Array<'error'>); // error: prop ~> error + +class Bar extends Foo { + bar_prop: string; + bar() {} +} +// only own enumerable props +(Object.keys(new Bar()): Array<'error'>); // error: bar_prop ~> error diff --git a/tests/object_api/object_missing.js b/tests/object_api/object_missing.js new file mode 100644 index 000000000000..8c33c2d94029 --- /dev/null +++ b/tests/object_api/object_missing.js @@ -0,0 +1,7 @@ +// @flow + +let tests = [ + function() { + Object.doesNotExist(); + }, +]; diff --git a/tests/object_api/object_prototype.js b/tests/object_api/object_prototype.js new file mode 100644 index 000000000000..233028a7e6c0 --- /dev/null +++ b/tests/object_api/object_prototype.js @@ -0,0 +1,164 @@ +/* @flow */ + +function takesABool(x: boolean) {} +function takesAString(x: string) {} +function takesANumber(x: number) {} +function takesAnObject(x: Object) {} + +class Foo {} + +var a = { foo: 'bar' }; +var b = { foo: 'bar', ...{}}; +var c = { foo: 'bar', toString: function(): number { return 123; }}; +var d : { [key: string]: string } = { foo: 'bar' }; +var x = new Date(); +var y = new Foo(); + +// +// toString +// + +// call +takesAString(a.toString()); +d.toString(); // ok, even though dict specifies strings, this is a function + +// get +var aToString : () => string = a.toString; +var aToString2 = a.toString; +takesAString(aToString2()); + +// set +b.toString = function(): string { return 'foo'; }; +c.toString = function(): number { return 123; }; + +// override +var cToString : () => number = c.toString; + +// ... on a built-in instance +var xToString : number = x.toString; // error +var xToString2 : () => number = x.toString; // error +takesAString(x.toString()); + +// ... on an instance +var yToString : number = y.toString; // error +takesAString(y.toString()); + +// ... on a primitive +(123).toString(); +(123).toString; +(123).toString = function() {}; // error +(123).toString(2); +(123).toString('foo'); // error +(123).toString(null); // error + + +// +// hasOwnProperty +// + +// call +takesABool(a.hasOwnProperty('foo')); + +// get +var aHasOwnProperty : (prop: string) => boolean = a.hasOwnProperty; +var aHasOwnProperty2 = a.hasOwnProperty; +takesABool(aHasOwnProperty2('bar')); + +// set +b.hasOwnProperty = function() { return false; }; + +// ... on a built-in instance +var xHasOwnProperty : number = x.hasOwnProperty; // error +var xHasOwnProperty2 : (prop: string) => number = x.hasOwnProperty; // error +takesABool(x.hasOwnProperty('foo')); + +// ... on an instance +var yHasOwnProperty : number = y.hasOwnProperty; // error +takesABool(y.hasOwnProperty('foo')); + + +// +// propertyIsEnumerable +// + +// call +takesABool(a.propertyIsEnumerable('foo')); + +// get +var aPropertyIsEnumerable : (prop: string) => boolean = a.propertyIsEnumerable; +var aPropertyIsEnumerable2 = a.propertyIsEnumerable; +takesABool(aPropertyIsEnumerable2('bar')); + +// set +b.propertyIsEnumerable = function() { return false; }; + +// ... on a built-in instance +var xPropertyIsEnumerable : number = x.propertyIsEnumerable; // error +var xPropertyIsEnumerable2 : (prop: string) => number = + x.propertyIsEnumerable; // error +takesABool(x.propertyIsEnumerable('foo')); + +// ... on an instance +var yPropertyIsEnumerable : number = y.propertyIsEnumerable; // error +takesABool(y.propertyIsEnumerable('foo')); + + +// +// valueOf +// + +// call +takesAnObject(a.valueOf()); + +// get +var aValueOf : () => Object = a.valueOf; +var aValueOf2 = a.valueOf; +takesAnObject(aValueOf2()); + +// set +b.valueOf = function() { return {}; }; + +// ... on a built-in instance +var xValueOf : number = x.valueOf; // error +takesANumber(x.valueOf()); + +// ... on an instance +var yValueOf : number = y.valueOf; // error +takesAnObject(y.valueOf()); + +// ... on a literal +var strValueOf : string = ("foo").valueOf(); +var numValueOf : number = (123).valueOf(); +var boolValueOf : boolean = (true).valueOf(); + +// +// toLocaleString +// + +// call +takesAString(a.toLocaleString()); + +// get +var aToLocaleString : () => string = a.toLocaleString; +var aToLocaleString2 = a.toLocaleString; +takesAString(aToLocaleString2()); + +// set +b.toLocaleString = function() { return 'derp'; }; + +// ... on a built-in instance +var xToLocaleString : number = x.toLocaleString; // error +var xToLocaleString2 : () => number = x.toLocaleString; // error +takesAString(x.toLocaleString()); + +// ... on an instance +var yToLocaleString : number = y.toLocaleString; // error +takesAString(y.toLocaleString()); + + +// +// constructor +// + +var k : Object = a.constructor; +(123).constructor; diff --git a/tests/object_assign/A.js b/tests/object_assign/A.js new file mode 100644 index 000000000000..8a7fa79901e7 --- /dev/null +++ b/tests/object_assign/A.js @@ -0,0 +1,26 @@ +/** + * @flow + */ + +var EventEmitter = require('events').EventEmitter; + +// This pattern seems to cause the trouble. +var Bad = Object.assign({}, EventEmitter.prototype, { + foo: function(): string { return 'hi'; } +}); + +// Calling Bad.foo() in the same file doesn't error +var bad: number = Bad.foo(); + +// Doesn't repro if I extend the class myself +class MyEventEmitter extends events$EventEmitter {} +var Good = Object.assign({}, MyEventEmitter.prototype, { + foo: function(): string { return 'hi'; } +}); +// Calling Good.foo() in the same file doesn't error +var good: number = Good.foo(); + +module.exports = { + Bad: Bad, + Good: Good, +}; diff --git a/tests/object_assign/B.js b/tests/object_assign/B.js new file mode 100644 index 000000000000..40278d660844 --- /dev/null +++ b/tests/object_assign/B.js @@ -0,0 +1,17 @@ +/** + * @flow + */ + +var A = require('./A.js'); + +var good: number = A.Good.foo(); + +var f = A.Bad.foo; // Property access is fine +var bad_: number = f(); // Calling the function is fine + +var bad: number = A.Bad.foo(); // Method call is not fine +/* +B.js|12 col 1 error| call of method foo +|| Property not found in +A.js|8 col 23 error| object literal +*/ diff --git a/tests/object_assign/__snapshots__/jsfmt.spec.js.snap b/tests/object_assign/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..47c18dc07b7e --- /dev/null +++ b/tests/object_assign/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,166 @@ +exports[`test A.js 1`] = ` +"/** + * @flow + */ + +var EventEmitter = require('events').EventEmitter; + +// This pattern seems to cause the trouble. +var Bad = Object.assign({}, EventEmitter.prototype, { + foo: function(): string { return 'hi'; } +}); + +// Calling Bad.foo() in the same file doesn't error +var bad: number = Bad.foo(); + +// Doesn't repro if I extend the class myself +class MyEventEmitter extends events$EventEmitter {} +var Good = Object.assign({}, MyEventEmitter.prototype, { + foo: function(): string { return 'hi'; } +}); +// Calling Good.foo() in the same file doesn't error +var good: number = Good.foo(); + +module.exports = { + Bad: Bad, + Good: Good, +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +var EventEmitter = require("events").EventEmitter; +// This pattern seems to cause the trouble. +var Bad = Object.assign( + {}, + EventEmitter.prototype, + { + foo: function(): string { + return "hi"; + } + } +); +// Calling Bad.foo() in the same file doesn't error +var bad: number = Bad.foo(); +// Doesn't repro if I extend the class myself +class MyEventEmitter extends events$EventEmitter {} +var Good = Object.assign( + {}, + MyEventEmitter.prototype, + { + foo: function(): string { + return "hi"; + } + } +); +// Calling Good.foo() in the same file doesn't error +var good: number = Good.foo(); +module.exports = { Bad: Bad, Good: Good }; + +" +`; + +exports[`test B.js 1`] = ` +"/** + * @flow + */ + +var A = require('./A.js'); + +var good: number = A.Good.foo(); + +var f = A.Bad.foo; // Property access is fine +var bad_: number = f(); // Calling the function is fine + +var bad: number = A.Bad.foo(); // Method call is not fine +/* +B.js|12 col 1 error| call of method foo +|| Property not found in +A.js|8 col 23 error| object literal +*/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +var A = require("./A.js"); +var good: number = A.Good.foo(); +var f = A.Bad.foo;// Property access is fine +var bad_: number = f();// Calling the function is fine +var bad: number = A.Bad.foo();// Method call is not fine/* +B.js|12 col 1 error| call of method foo +|| Property not found in +A.js|8 col 23 error| object literal +*/ + +" +`; + +exports[`test apply.js 1`] = ` +"// @flow + +(Object.assign.apply(null, [{}, {a: 1}, {b: 'foo'}]): {a: number, b: string}); +(Object.assign({}, ...[{a: 1}, {b: 'foo'}]): {a: number, b: string}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +(Object.assign.apply(null, [ {}, { a: 1 }, { b: "foo" } ]): { + a: number, + b: string +}); +(Object.assign({}, ...[ { a: 1 }, { b: "foo" } ]): { a: number, b: string }); + +" +`; + +exports[`test non_objects.js 1`] = ` +"/* @flow */ + +Object.assign("123", {a: "foo"}); +Object.assign(123, {a: "foo"}); +Object.assign({a: "foo"}, 123); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +Object.assign("123", { a: "foo" }); +Object.assign(123, { a: "foo" }); +Object.assign({ a: "foo" }, 123); + +" +`; + +exports[`test undefined.js 1`] = ` +"/* @flow */ + +var React = require('react'); + +type DefaultProps = { + foo: number, +} + +type Props = { + foo: number, +} + +class MyReactThing extends React.Component { + props: Props; + static defaultProps: DefaultProps; + getFoo(): number { return this.props.foo; } +} + +; // works +; // also works +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require("react"); +type DefaultProps = { foo: number }; +type Props = { foo: number }; +class MyReactThing extends React.Component { + props: Props; + static defaultProps: DefaultProps; + getFoo(): number { + return this.props.foo; + } +} +;// works +;// also works + +" +`; diff --git a/tests/object_assign/apply.js b/tests/object_assign/apply.js new file mode 100644 index 000000000000..6bb4c551eab8 --- /dev/null +++ b/tests/object_assign/apply.js @@ -0,0 +1,4 @@ +// @flow + +(Object.assign.apply(null, [{}, {a: 1}, {b: 'foo'}]): {a: number, b: string}); +(Object.assign({}, ...[{a: 1}, {b: 'foo'}]): {a: number, b: string}); diff --git a/tests/object_assign/jsfmt.spec.js b/tests/object_assign/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/object_assign/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/object_assign/non_objects.js b/tests/object_assign/non_objects.js new file mode 100644 index 000000000000..8cb9b564d6ee --- /dev/null +++ b/tests/object_assign/non_objects.js @@ -0,0 +1,5 @@ +/* @flow */ + +Object.assign("123", {a: "foo"}); +Object.assign(123, {a: "foo"}); +Object.assign({a: "foo"}, 123); diff --git a/tests/object_assign/undefined.js b/tests/object_assign/undefined.js new file mode 100644 index 000000000000..27b1d0b9f44d --- /dev/null +++ b/tests/object_assign/undefined.js @@ -0,0 +1,20 @@ +/* @flow */ + +var React = require('react'); + +type DefaultProps = { + foo: number, +} + +type Props = { + foo: number, +} + +class MyReactThing extends React.Component { + props: Props; + static defaultProps: DefaultProps; + getFoo(): number { return this.props.foo; } +} + +; // works +; // also works diff --git a/tests/object_freeze/__snapshots__/jsfmt.spec.js.snap b/tests/object_freeze/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2eed145c9e9b --- /dev/null +++ b/tests/object_freeze/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,41 @@ +exports[`test object_freeze.js 1`] = ` +"/* @flow */ + +var foo = Object.freeze({bar: '12345'}); +foo.bar = '23456'; // error + +Object.assign(foo, {bar: '12345'}); // error + +var baz = {baz: 12345}; +var bliffl = Object.freeze({bar: '12345', ...baz}); +bliffl.bar = '23456'; // error +bliffl.baz = 3456; // error +bliffl.corge; // error +bliffl.constructor = baz; // error +bliffl.toString = function() {}; // error + +baz.baz = 0; + +var x : number = Object.freeze(123); + +var xx : { x: number } = Object.freeze({ x: "error" }) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var foo = Object.freeze({ bar: "12345" }); +foo.bar = "23456";// error +Object.assign(foo, { bar: "12345" });// error +var baz = { baz: 12345 }; +var bliffl = Object.freeze({ bar: "12345", ...baz }); +bliffl.bar = "23456";// error +bliffl.baz = 3456;// error +bliffl.corge;// error +bliffl.constructor = baz;// error +bliffl.toString = function() { + +};// error +baz.baz = 0; +var x: number = Object.freeze(123); +var xx: { x: number } = Object.freeze({ x: "error" }); + +" +`; diff --git a/tests/object_freeze/jsfmt.spec.js b/tests/object_freeze/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/object_freeze/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/object_freeze/object_freeze.js b/tests/object_freeze/object_freeze.js new file mode 100644 index 000000000000..cc192b2115aa --- /dev/null +++ b/tests/object_freeze/object_freeze.js @@ -0,0 +1,20 @@ +/* @flow */ + +var foo = Object.freeze({bar: '12345'}); +foo.bar = '23456'; // error + +Object.assign(foo, {bar: '12345'}); // error + +var baz = {baz: 12345}; +var bliffl = Object.freeze({bar: '12345', ...baz}); +bliffl.bar = '23456'; // error +bliffl.baz = 3456; // error +bliffl.corge; // error +bliffl.constructor = baz; // error +bliffl.toString = function() {}; // error + +baz.baz = 0; + +var x : number = Object.freeze(123); + +var xx : { x: number } = Object.freeze({ x: "error" }) diff --git a/tests/object_is/__snapshots__/jsfmt.spec.js.snap b/tests/object_is/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..712ce14a0089 --- /dev/null +++ b/tests/object_is/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,46 @@ +exports[`test object_is.js 1`] = ` +"Object.is(1, 1); +Object.is(1, 2); +Object.is(1, {}); +Object.is(1, NaN); +Object.is(0, 0); +Object.is(0, -0); +Object.is(NaN, NaN); +Object.is({}, {}); + +var emptyObject = {}; +var emptyArray = []; +Object.is(emptyObject, emptyObject); +Object.is(emptyArray, emptyArray); +Object.is(emptyObject, emptyArray); + +var squared = x => x * x; +Object.is(squared, squared); + +var a: boolean = Object.is('a', 'a'); +var b: string = Object.is('a', 'a'); +var c: boolean = Object.is('a'); +var d: boolean = Object.is('a', 'b', 'c'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Object.is(1, 1); +Object.is(1, 2); +Object.is(1, {}); +Object.is(1, NaN); +Object.is(0, 0); +Object.is(0, -0); +Object.is(NaN, NaN); +Object.is({}, {}); +var emptyObject = {}; +var emptyArray = [ ]; +Object.is(emptyObject, emptyObject); +Object.is(emptyArray, emptyArray); +Object.is(emptyObject, emptyArray); +var squared = x => x * x; +Object.is(squared, squared); +var a: boolean = Object.is("a", "a"); +var b: string = Object.is("a", "a"); +var c: boolean = Object.is("a"); +var d: boolean = Object.is("a", "b", "c"); + +" +`; diff --git a/tests/object_is/jsfmt.spec.js b/tests/object_is/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/object_is/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/object_is/object_is.js b/tests/object_is/object_is.js new file mode 100644 index 000000000000..a13f2e3baed7 --- /dev/null +++ b/tests/object_is/object_is.js @@ -0,0 +1,22 @@ +Object.is(1, 1); +Object.is(1, 2); +Object.is(1, {}); +Object.is(1, NaN); +Object.is(0, 0); +Object.is(0, -0); +Object.is(NaN, NaN); +Object.is({}, {}); + +var emptyObject = {}; +var emptyArray = []; +Object.is(emptyObject, emptyObject); +Object.is(emptyArray, emptyArray); +Object.is(emptyObject, emptyArray); + +var squared = x => x * x; +Object.is(squared, squared); + +var a: boolean = Object.is('a', 'a'); +var b: string = Object.is('a', 'a'); +var c: boolean = Object.is('a'); +var d: boolean = Object.is('a', 'b', 'c'); diff --git a/tests/objects/__snapshots__/jsfmt.spec.js.snap b/tests/objects/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..daae00078b05 --- /dev/null +++ b/tests/objects/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,125 @@ +exports[`test conversion.js 1`] = ` +"/* @flow */ + +(Object({foo: \'bar\'}): {foo: string}); +(Object(\"123\"): String); +(Object(123): Number); +(Object(true): Boolean); +(Object(null): {}); +(Object(undefined): {}); +(Object(void(0)): {}); +(Object(undefined): Number); // error + +var x = Object(null); +x.foo = \"bar\"; + +var y = Object(\"123\"); +(y.charAt(0): string); + +var z = Object(123); // error (next line makes this not match any signatures) +(z.charAt(0): string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +(Object({ foo: \"bar\" }): { foo: string }); +(Object(\"123\"): String); +(Object(123): Number); +(Object(true): Boolean); +(Object(null): {}); +(Object(undefined): {}); +(Object(void 0): {}); +(Object(undefined): Number);// error +var x = Object(null); +x.foo = \"bar\"; +var y = Object(\"123\"); +(y.charAt(0): string); +var z = Object(123);// error (next line makes this not match any signatures) +(z.charAt(0): string); + +" +`; + +exports[`test objects.js 1`] = ` +"/* @flow */ + +var x : {\'123\': string, bar: string} = {\'123\': \'val\', bar: \'bar\'}; +(x.foo : string); // error, key doesn\'t exist +(x[\'foo\'] : string); // error, key doesn\'t exist +(x[123] : boolean); // TODO: use the number\'s value to error here +(x.bar: boolean); // error, string !~> boolean +(x[\'123\'] : boolean); // error, string !~> boolean +x[\'123\'] = false; // error, boolean !~> string +x[123] = false; // TODO: use the number\'s value to error here +x[\'foo\'+\'bar\'] = \'derp\'; // ok since we can\'t tell +(x[\`foo\`]: string); // error, key doesn\'t exist + +var y : {foo: string} = {foo: \'bar\'}; +y[\'foo\'] = 123; // error, number !~> string +y[\'bar\'] = \'abc\'; // error, property not found + +(y[\'hasOwnProperty\']: string); // error, prototype method is not a string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var x: { \"123\": string, bar: string } = { \"123\": \"val\", bar: \"bar\" }; +(x.foo: string);// error, key doesn\'t exist +(x[\"foo\"]: string);// error, key doesn\'t exist +(x[123]: boolean);// TODO: use the number\'s value to error here +(x.bar: boolean);// error, string !~> boolean +(x[\"123\"]: boolean);// error, string !~> boolean +x[\"123\"] = false;// error, boolean !~> string +x[123] = false;// TODO: use the number\'s value to error here +x[\"foo\" + \"bar\"] = \"derp\";// ok since we can\'t tell +(x[\`foo\`]: string);// error, key doesn\'t exist +var y: { foo: string } = { foo: \"bar\" }; +y[\"foo\"] = 123;// error, number !~> string +y[\"bar\"] = \"abc\";// error, property not found +(y[\"hasOwnProperty\"]: string);// error, prototype method is not a string + +" +`; + +exports[`test unaliased_assign.js 1`] = ` +"/** + * test handling of unaliased value assignment. + * + * An unaliased object rvalue may be assigned to a supertype lvalue, + * because later widening mutations on the rvalue can\'t break assumptions + * made by other lvalues. + * + * However, upon assignment the rvalue must take on the type of the + * lvalue, to avoid both false positives and false negatives + * (unsoundness), as shown below. + * + * @flow + */ + +var glob: { x: string } = { x: \"hey\" }; + +function assign_then_alias() { + var obj: { x: string | number }; + obj = { x: \"hey\" }; + glob = obj; // error: subsequent assignment might make glob.x a number +} + +function assign_then_widen() { + var obj: { x: string | number }; + obj = { x: \"hey\" }; + obj.x = 10; // ok, by lvalue\'s given type +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/objects/conversion.js b/tests/objects/conversion.js new file mode 100644 index 000000000000..48cc52980743 --- /dev/null +++ b/tests/objects/conversion.js @@ -0,0 +1,19 @@ +/* @flow */ + +(Object({foo: 'bar'}): {foo: string}); +(Object("123"): String); +(Object(123): Number); +(Object(true): Boolean); +(Object(null): {}); +(Object(undefined): {}); +(Object(void(0)): {}); +(Object(undefined): Number); // error + +var x = Object(null); +x.foo = "bar"; + +var y = Object("123"); +(y.charAt(0): string); + +var z = Object(123); // error (next line makes this not match any signatures) +(z.charAt(0): string); diff --git a/tests/objects/jsfmt.spec.js b/tests/objects/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/objects/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/objects/objects.js b/tests/objects/objects.js new file mode 100644 index 000000000000..5eea185f7041 --- /dev/null +++ b/tests/objects/objects.js @@ -0,0 +1,18 @@ +/* @flow */ + +var x : {'123': string, bar: string} = {'123': 'val', bar: 'bar'}; +(x.foo : string); // error, key doesn't exist +(x['foo'] : string); // error, key doesn't exist +(x[123] : boolean); // TODO: use the number's value to error here +(x.bar: boolean); // error, string !~> boolean +(x['123'] : boolean); // error, string !~> boolean +x['123'] = false; // error, boolean !~> string +x[123] = false; // TODO: use the number's value to error here +x['foo'+'bar'] = 'derp'; // ok since we can't tell +(x[`foo`]: string); // error, key doesn't exist + +var y : {foo: string} = {foo: 'bar'}; +y['foo'] = 123; // error, number !~> string +y['bar'] = 'abc'; // error, property not found + +(y['hasOwnProperty']: string); // error, prototype method is not a string diff --git a/tests/objects/unaliased_assign.js b/tests/objects/unaliased_assign.js new file mode 100644 index 000000000000..c1cebeea5260 --- /dev/null +++ b/tests/objects/unaliased_assign.js @@ -0,0 +1,27 @@ +/** + * test handling of unaliased value assignment. + * + * An unaliased object rvalue may be assigned to a supertype lvalue, + * because later widening mutations on the rvalue can't break assumptions + * made by other lvalues. + * + * However, upon assignment the rvalue must take on the type of the + * lvalue, to avoid both false positives and false negatives + * (unsoundness), as shown below. + * + * @flow + */ + +var glob: { x: string } = { x: "hey" }; + +function assign_then_alias() { + var obj: { x: string | number }; + obj = { x: "hey" }; + glob = obj; // error: subsequent assignment might make glob.x a number +} + +function assign_then_widen() { + var obj: { x: string | number }; + obj = { x: "hey" }; + obj.x = 10; // ok, by lvalue's given type +} diff --git a/tests/objmap/__snapshots__/jsfmt.spec.js.snap b/tests/objmap/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..59efee2952c0 --- /dev/null +++ b/tests/objmap/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,37 @@ +exports[`test objmap.js 1`] = ` +"declare function promiseAllByKey(o: O): Promise<$ObjMap>; +declare function keyMirror(o: O): $ObjMapi(k:K) => K>; + +var o = keyMirror({ + FOO: null, + BAR: null, +}); + +(o.FOO : \'FOO\'); // ok +(o.FOO : \'BAR\'); // error, \'FOO\' incompatible with \'BAR\' + +promiseAllByKey({ + foo: Promise.resolve(0), + bar: \'bar\', +}).then(o => { + (o.foo: string); // error, number ~> string + (o.bar: \'bar\'); // ok +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/objmap/jsfmt.spec.js b/tests/objmap/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/objmap/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/objmap/objmap.js b/tests/objmap/objmap.js new file mode 100644 index 000000000000..2bdd9fd2ddc9 --- /dev/null +++ b/tests/objmap/objmap.js @@ -0,0 +1,18 @@ +declare function promiseAllByKey(o: O): Promise<$ObjMap>; +declare function keyMirror(o: O): $ObjMapi(k:K) => K>; + +var o = keyMirror({ + FOO: null, + BAR: null, +}); + +(o.FOO : 'FOO'); // ok +(o.FOO : 'BAR'); // error, 'FOO' incompatible with 'BAR' + +promiseAllByKey({ + foo: Promise.resolve(0), + bar: 'bar', +}).then(o => { + (o.foo: string); // error, number ~> string + (o.bar: 'bar'); // ok +}); diff --git a/tests/optional/__snapshots__/jsfmt.spec.js.snap b/tests/optional/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..df6981ed082c --- /dev/null +++ b/tests/optional/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,407 @@ +exports[`test client_optional.js 1`] = ` +"var qux = require(\'./optional\'); + +qux(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var qux = require(\"./optional\"); +qux(0); + +" +`; + +exports[`test default.js 1`] = ` +"function f(foo, bar = foo): [T, T] { + return [foo, bar]; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test generic.js 1`] = ` +"function x(x: T = 0) {} + +class C { + x(x: T = 0) {} +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test maybe.js 1`] = ` +"function foo(x?: string): ?string { + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(x: string): ?string { + return x; +} + +" +`; + +exports[`test nullable.js 1`] = ` +"/* @flow */ + +function optionalNullable1(x: {y?: ?number}) { + if (x.y !== null && x.y !== undefined) { + x.y++; + } +} + +function optionalNullable2(x: {y?: ?number}) { + if (x.y !== undefined && x.y !== null) { + x.y++; + } +} + +function optionalNullable3(x: {y?: ?number}) { + if (!(x.y !== null && x.y !== undefined)) { + x.y++; // should error + } +} + +function optionalNullable4(x: {y?: ?number}) { + if (!(x.y !== undefined && x.y !== null)) { + x.y++; // should error + } +} + +function optionalNullable5(x: {y?: ?number}) { + if (x.y === null || x.y === undefined) { + x.y++; // should error + } +} + +function optionalNullable6(x: {y?: ?number}) { + if (x.y === undefined || x.y === null) { + x.y++; // should error + } +} + +function optionalNullable7(x: {y?: ?number}) { + if (!(x.y === null || x.y === undefined)) { + x.y++; + } +} + +function optionalNullable8(x: {y?: ?number}) { + if (!(x.y === undefined || x.y === null)) { + x.y++; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function optionalNullable1(x: { y?: ?number }) { + if (x.y !== null && x.y !== undefined) { + x.y++; + } +} +function optionalNullable2(x: { y?: ?number }) { + if (x.y !== undefined && x.y !== null) { + x.y++; + } +} +function optionalNullable3(x: { y?: ?number }) { + if (!(x.y !== null && x.y !== undefined)) { + x.y++;// should error + } +} +function optionalNullable4(x: { y?: ?number }) { + if (!(x.y !== undefined && x.y !== null)) { + x.y++;// should error + } +} +function optionalNullable5(x: { y?: ?number }) { + if (x.y === null || x.y === undefined) { + x.y++;// should error + } +} +function optionalNullable6(x: { y?: ?number }) { + if (x.y === undefined || x.y === null) { + x.y++;// should error + } +} +function optionalNullable7(x: { y?: ?number }) { + if (!(x.y === null || x.y === undefined)) { + x.y++; + } +} +function optionalNullable8(x: { y?: ?number }) { + if (!(x.y === undefined || x.y === null)) { + x.y++; + } +} + +" +`; + +exports[`test optional.js 1`] = ` +"function bar(x?,y?) { x * 0; } +bar(0); + +var foo:(x?:number)=>void = bar; +foo(); + +function qux(x=\"hello\",...y):string { foo(x); return y[0]; } + +qux(0,0); +qux(0,...[\"\",42]); + +module.exports = qux; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test optional_param.js 1`] = ` +"/* @flow */ +function foo(x?: string): string { + if (x == null) { return \'foo\'; } + return x; +} + +function bar(obj: {x?: string}): string { + if (obj.x == null) { return \'foo\'; } + return obj.x; +} + +function baz(bar?) { + if (!bar) { return 1; } + return bar.duck +} + +function testOptionalNullable(x?: ?string): string { + if (x == null) { return \'foo\'; } + return x; +} + +function testOptionalNullableDefault(x?: ?string = \"hi\"): string { + if (x == null) { return \'foo\'; } + return x; +} + +function testOptionalNullableProperty(obj: {x?: ?string}): string { + if (obj.x == null) { return \'foo\'; } + return obj.x; +} + +function testOptionalNullableFlowingToNullable(x?: ?string): ?string { + var f = function(y: ?string) {}; + f(x); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo(x: string): string { + if (x == null) { + return \"foo\"; + } + return x; +} +function bar(obj: { x?: string }): string { + if (obj.x == null) { + return \"foo\"; + } + return obj.x; +} +function baz(bar) { + if (!bar) { + return 1; + } + return bar.duck; +} +function testOptionalNullable(x: ?string): string { + if (x == null) { + return \"foo\"; + } + return x; +} +function testOptionalNullableDefault(x: ?string = \"hi\"): string { + if (x == null) { + return \"foo\"; + } + return x; +} +function testOptionalNullableProperty(obj: { x?: ?string }): string { + if (obj.x == null) { + return \"foo\"; + } + return obj.x; +} +function testOptionalNullableFlowingToNullable(x: ?string): ?string { + var f = function(y: ?string) { + + }; + f(x); +} + +" +`; + +exports[`test optional_param2.js 1`] = ` +"declare class I { + map( + mapper: (value?: V) => M + ): I; +} +var i:I = new I(); +var j:I = i.map(id => id); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1368:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test optional_param3.js 1`] = ` +"function foo(x?: number) {} +foo(undefined); // ok + +function bar(x = \"bar\"): string { + return x; +} +bar(undefined); // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(x: number) { + +} +foo(undefined);// ok +function bar(x = \"bar\"): string { + return x; +} +bar(undefined);// ok + +" +`; + +exports[`test optional_param4.js 1`] = ` +"/* @flow */ + +function foo(x?: number, ...y: Array): [?number, Array] { + return [x, y]; +} + +foo(); // OK +foo(123), // OK +foo(123, \'hello\'); // OK + + +foo(true); // ERROR boolean ~> number +foo(123, true); // ERROR boolean ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test undefined.js 1`] = ` +"var x; + +function foo(bar? = undefined) { + x = bar; +} + +function bar() { + return x.duck; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x; +function foo(bar = undefined) { + x = bar; +} +function bar() { + return x.duck; +} + +" +`; + +exports[`test undefined2.js 1`] = ` +"var x; + +function foo(bar?) { + x = bar; +} + +function bar() { + return x.duck; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x; +function foo(bar) { + x = bar; +} +function bar() { + return x.duck; +} + +" +`; diff --git a/tests/optional/client_optional.js b/tests/optional/client_optional.js new file mode 100644 index 000000000000..1f7d6b7bb0b1 --- /dev/null +++ b/tests/optional/client_optional.js @@ -0,0 +1,3 @@ +var qux = require('./optional'); + +qux(0); diff --git a/tests/optional/default.js b/tests/optional/default.js new file mode 100644 index 000000000000..48d31c63ba77 --- /dev/null +++ b/tests/optional/default.js @@ -0,0 +1,3 @@ +function f(foo, bar = foo): [T, T] { + return [foo, bar]; +} diff --git a/tests/optional/generic.js b/tests/optional/generic.js new file mode 100644 index 000000000000..3fb2a4d6c460 --- /dev/null +++ b/tests/optional/generic.js @@ -0,0 +1,5 @@ +function x(x: T = 0) {} + +class C { + x(x: T = 0) {} +} diff --git a/tests/optional/jsfmt.spec.js b/tests/optional/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/optional/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/optional/maybe.js b/tests/optional/maybe.js new file mode 100644 index 000000000000..d2266e6d22a4 --- /dev/null +++ b/tests/optional/maybe.js @@ -0,0 +1,3 @@ +function foo(x?: string): ?string { + return x; +} diff --git a/tests/optional/nullable.js b/tests/optional/nullable.js new file mode 100644 index 000000000000..509397894097 --- /dev/null +++ b/tests/optional/nullable.js @@ -0,0 +1,49 @@ +/* @flow */ + +function optionalNullable1(x: {y?: ?number}) { + if (x.y !== null && x.y !== undefined) { + x.y++; + } +} + +function optionalNullable2(x: {y?: ?number}) { + if (x.y !== undefined && x.y !== null) { + x.y++; + } +} + +function optionalNullable3(x: {y?: ?number}) { + if (!(x.y !== null && x.y !== undefined)) { + x.y++; // should error + } +} + +function optionalNullable4(x: {y?: ?number}) { + if (!(x.y !== undefined && x.y !== null)) { + x.y++; // should error + } +} + +function optionalNullable5(x: {y?: ?number}) { + if (x.y === null || x.y === undefined) { + x.y++; // should error + } +} + +function optionalNullable6(x: {y?: ?number}) { + if (x.y === undefined || x.y === null) { + x.y++; // should error + } +} + +function optionalNullable7(x: {y?: ?number}) { + if (!(x.y === null || x.y === undefined)) { + x.y++; + } +} + +function optionalNullable8(x: {y?: ?number}) { + if (!(x.y === undefined || x.y === null)) { + x.y++; + } +} diff --git a/tests/optional/optional.js b/tests/optional/optional.js new file mode 100644 index 000000000000..79fa1d5317b9 --- /dev/null +++ b/tests/optional/optional.js @@ -0,0 +1,12 @@ +function bar(x?,y?) { x * 0; } +bar(0); + +var foo:(x?:number)=>void = bar; +foo(); + +function qux(x="hello",...y):string { foo(x); return y[0]; } + +qux(0,0); +qux(0,...["",42]); + +module.exports = qux; diff --git a/tests/optional/optional_param.js b/tests/optional/optional_param.js new file mode 100644 index 000000000000..5ba9b9a660ca --- /dev/null +++ b/tests/optional/optional_param.js @@ -0,0 +1,35 @@ +/* @flow */ +function foo(x?: string): string { + if (x == null) { return 'foo'; } + return x; +} + +function bar(obj: {x?: string}): string { + if (obj.x == null) { return 'foo'; } + return obj.x; +} + +function baz(bar?) { + if (!bar) { return 1; } + return bar.duck +} + +function testOptionalNullable(x?: ?string): string { + if (x == null) { return 'foo'; } + return x; +} + +function testOptionalNullableDefault(x?: ?string = "hi"): string { + if (x == null) { return 'foo'; } + return x; +} + +function testOptionalNullableProperty(obj: {x?: ?string}): string { + if (obj.x == null) { return 'foo'; } + return obj.x; +} + +function testOptionalNullableFlowingToNullable(x?: ?string): ?string { + var f = function(y: ?string) {}; + f(x); +} diff --git a/tests/optional/optional_param2.js b/tests/optional/optional_param2.js new file mode 100644 index 000000000000..c26f546d3e84 --- /dev/null +++ b/tests/optional/optional_param2.js @@ -0,0 +1,7 @@ +declare class I { + map( + mapper: (value?: V) => M + ): I; +} +var i:I = new I(); +var j:I = i.map(id => id); diff --git a/tests/optional/optional_param3.js b/tests/optional/optional_param3.js new file mode 100644 index 000000000000..1171945a726d --- /dev/null +++ b/tests/optional/optional_param3.js @@ -0,0 +1,7 @@ +function foo(x?: number) {} +foo(undefined); // ok + +function bar(x = "bar"): string { + return x; +} +bar(undefined); // ok diff --git a/tests/optional/optional_param4.js b/tests/optional/optional_param4.js new file mode 100644 index 000000000000..c880d64e6fef --- /dev/null +++ b/tests/optional/optional_param4.js @@ -0,0 +1,13 @@ +/* @flow */ + +function foo(x?: number, ...y: Array): [?number, Array] { + return [x, y]; +} + +foo(); // OK +foo(123), // OK +foo(123, 'hello'); // OK + + +foo(true); // ERROR boolean ~> number +foo(123, true); // ERROR boolean ~> string diff --git a/tests/optional/undefined.js b/tests/optional/undefined.js new file mode 100644 index 000000000000..5a23002c0cab --- /dev/null +++ b/tests/optional/undefined.js @@ -0,0 +1,9 @@ +var x; + +function foo(bar? = undefined) { + x = bar; +} + +function bar() { + return x.duck; +} diff --git a/tests/optional/undefined2.js b/tests/optional/undefined2.js new file mode 100644 index 000000000000..921c7383c757 --- /dev/null +++ b/tests/optional/undefined2.js @@ -0,0 +1,9 @@ +var x; + +function foo(bar?) { + x = bar; +} + +function bar() { + return x.duck; +} diff --git a/tests/optional_props/__snapshots__/jsfmt.spec.js.snap b/tests/optional_props/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0c27bae9581e --- /dev/null +++ b/tests/optional_props/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,199 @@ +exports[`test test.js 1`] = ` +"var x: { } = { foo: 0 }; +var y: { foo?: string } = x; // OK in TypeScript, not OK in Flow + +var z: string = y.foo || \"\"; + +var o = { }; +y = o; // OK; we know that narrowing could not have happened +o.foo = 0; // future widening is constrained + +function bar(config: { foo?: number }) {} +bar({}); +bar({foo: \"\"}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: {} = { foo: 0 }; +var y: { foo?: string } = x;// OK in TypeScript, not OK in Flow +var z: string = y.foo || \"\"; +var o = {}; +y = o;// OK; we know that narrowing could not have happened +o.foo = 0;// future widening is constrained +function bar(config: { foo?: number }) { + +} +bar({}); +bar({ foo: \"\" }); + +" +`; + +exports[`test test2.js 1`] = ` +"var a: { foo?: string } = {}; +a.foo = undefined; // This is not an error +a.foo = null; // But this is an error + +var b: { foo?: ?string } = {}; +b.foo = undefined; // This is fine +b.foo = null; // Also fine + +var c: { foo?: string } = { foo: undefined }; // This is not an error +var d: { foo?: string } = { foo: null }; // But this is an error + +var e: { foo?: ?string } = { foo: undefined }; // This is fine +var f: { foo?: ?string } = { foo: null }; // Also fine +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a: { foo?: string } = {}; +a.foo = undefined;// This is not an error +a.foo = null;// But this is an error +var b: { foo?: ?string } = {}; +b.foo = undefined;// This is fine +b.foo = null;// Also fine +var c: { foo?: string } = { foo: undefined };// This is not an error +var d: { foo?: string } = { foo: null };// But this is an error +var e: { foo?: ?string } = { foo: undefined };// This is fine +var f: { foo?: ?string } = { foo: null };// Also fine + +" +`; + +exports[`test test3.js 1`] = ` +"// @flow + +/* + object literals are sealed. this is simply a heuristic + decision: most of the time, the rule gives the \'right\' + errors. + + an exception is when a literal is used as an initializer + for an lvalue whose type specifies optional properties + missing from the literal, as below. + + the problem becomes visible when a property assignment + is then used to (legitimately) extend the object with an + optional property - the variable\'s specific (path- + dependent) type has become that of the literal which. + without adjustment, will reject the property addition. + + the solution in cases where a sealed object type (as from + an object literal) flows to an object type with optional + properties, is to have the sealed type acquire the optional + properties. + */ + +// x has optional property b. +// (note that the initializer here does not play into +// the problem, it\'s just a placeholder. initializers +// do not narrow the types of annotated variables as do +// subsequent assignments.) +// +var x: { a: number, b?: number } = { a: 0 }; + +// now assign an object literal lacking property b. +// the literal\'s type is sealed and has only a at creation. +// but it then flows, specific ~> general, to x\'s annotation +// type. at that point, it acquires b as an optional property. +// +x = { a: 0 }; + +// ...which allows this assignment to take place. +x.b = 1; + +// T7810506 +class A { + x: { a: number, b?: string }; + foo() { + // Something similar should happen here, but doesn\'t: the problem is + // made explicit by adding generics (see test3_failure.js introduced by + // D2747512). There is a race between writing b on the object literal + // type and adding b as an optional property to it, since in general we + // cannot guarantee that the flow from the object literal to the + // annotation will be processed before the flow involving the + // access. Here we lose the race and get an error on the write. + this.x = { a: 123 }; + this.x.b = \'hello\'; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +/* + object literals are sealed. this is simply a heuristic + decision: most of the time, the rule gives the \'right\' + errors. + + an exception is when a literal is used as an initializer + for an lvalue whose type specifies optional properties + missing from the literal, as below. + + the problem becomes visible when a property assignment + is then used to (legitimately) extend the object with an + optional property - the variable\'s specific (path- + dependent) type has become that of the literal which. + without adjustment, will reject the property addition. + + the solution in cases where a sealed object type (as from + an object literal) flows to an object type with optional + properties, is to have the sealed type acquire the optional + properties. + */ +// x has optional property b. +// (note that the initializer here does not play into +// the problem, it\'s just a placeholder. initializers +// do not narrow the types of annotated variables as do +// subsequent assignments.) +// +var x: { a: number, b?: number } = { a: 0 }; +// now assign an object literal lacking property b. +// the literal\'s type is sealed and has only a at creation. +// but it then flows, specific ~> general, to x\'s annotation +// type. at that point, it acquires b as an optional property. +// +x = { a: 0 }; +// ...which allows this assignment to take place. +x.b = 1; +// T7810506 +class A { + x: { a: number, b?: string }; + foo() { + // Something similar should happen here, but doesn\'t: the problem is + // made explicit by adding generics (see test3_failure.js introduced by + // D2747512). There is a race between writing b on the object literal + // type and adding b as an optional property to it, since in general we + // cannot guarantee that the flow from the object literal to the + // annotation will be processed before the flow involving the + // access. Here we lose the race and get an error on the write. + this.x = { a: 123 }; + this.x.b = \"hello\"; + } +} + +" +`; + +exports[`test test3_failure.js 1`] = ` +"// generalization of failure in test3.js + +class A { + o: O; + foo() { + this.o.x = { a: 123 }; + this.o.x.b = \'hello\'; // this is a spurious error (see test3.js for details) + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/optional_props/jsfmt.spec.js b/tests/optional_props/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/optional_props/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/optional_props/test.js b/tests/optional_props/test.js new file mode 100644 index 000000000000..ecb039485694 --- /dev/null +++ b/tests/optional_props/test.js @@ -0,0 +1,12 @@ +var x: { } = { foo: 0 }; +var y: { foo?: string } = x; // OK in TypeScript, not OK in Flow + +var z: string = y.foo || ""; + +var o = { }; +y = o; // OK; we know that narrowing could not have happened +o.foo = 0; // future widening is constrained + +function bar(config: { foo?: number }) {} +bar({}); +bar({foo: ""}); diff --git a/tests/optional_props/test2.js b/tests/optional_props/test2.js new file mode 100644 index 000000000000..827c6f3776ce --- /dev/null +++ b/tests/optional_props/test2.js @@ -0,0 +1,13 @@ +var a: { foo?: string } = {}; +a.foo = undefined; // This is not an error +a.foo = null; // But this is an error + +var b: { foo?: ?string } = {}; +b.foo = undefined; // This is fine +b.foo = null; // Also fine + +var c: { foo?: string } = { foo: undefined }; // This is not an error +var d: { foo?: string } = { foo: null }; // But this is an error + +var e: { foo?: ?string } = { foo: undefined }; // This is fine +var f: { foo?: ?string } = { foo: null }; // Also fine diff --git a/tests/optional_props/test3.js b/tests/optional_props/test3.js new file mode 100644 index 000000000000..2b737ace63fa --- /dev/null +++ b/tests/optional_props/test3.js @@ -0,0 +1,56 @@ +// @flow + +/* + object literals are sealed. this is simply a heuristic + decision: most of the time, the rule gives the 'right' + errors. + + an exception is when a literal is used as an initializer + for an lvalue whose type specifies optional properties + missing from the literal, as below. + + the problem becomes visible when a property assignment + is then used to (legitimately) extend the object with an + optional property - the variable's specific (path- + dependent) type has become that of the literal which. + without adjustment, will reject the property addition. + + the solution in cases where a sealed object type (as from + an object literal) flows to an object type with optional + properties, is to have the sealed type acquire the optional + properties. + */ + +// x has optional property b. +// (note that the initializer here does not play into +// the problem, it's just a placeholder. initializers +// do not narrow the types of annotated variables as do +// subsequent assignments.) +// +var x: { a: number, b?: number } = { a: 0 }; + +// now assign an object literal lacking property b. +// the literal's type is sealed and has only a at creation. +// but it then flows, specific ~> general, to x's annotation +// type. at that point, it acquires b as an optional property. +// +x = { a: 0 }; + +// ...which allows this assignment to take place. +x.b = 1; + +// T7810506 +class A { + x: { a: number, b?: string }; + foo() { + // Something similar should happen here, but doesn't: the problem is + // made explicit by adding generics (see test3_failure.js introduced by + // D2747512). There is a race between writing b on the object literal + // type and adding b as an optional property to it, since in general we + // cannot guarantee that the flow from the object literal to the + // annotation will be processed before the flow involving the + // access. Here we lose the race and get an error on the write. + this.x = { a: 123 }; + this.x.b = 'hello'; + } +} diff --git a/tests/optional_props/test3_failure.js b/tests/optional_props/test3_failure.js new file mode 100644 index 000000000000..f6478197da18 --- /dev/null +++ b/tests/optional_props/test3_failure.js @@ -0,0 +1,9 @@ +// generalization of failure in test3.js + +class A { + o: O; + foo() { + this.o.x = { a: 123 }; + this.o.x.b = 'hello'; // this is a spurious error (see test3.js for details) + } +} diff --git a/tests/overload/__snapshots__/jsfmt.spec.js.snap b/tests/overload/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4998e29a8cec --- /dev/null +++ b/tests/overload/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,176 @@ +exports[`test overload.js 1`] = ` +"/** + * tests of overload selection + * + * @flow + */ + +var x1: number = \"\".match(0)[0]; +var x2: number = \"\".match(/pattern/)[0]; +var x3: string = \"\".replace(/pattern/,\"...\"); +var x4: number = \"\".split(/pattern/)[0]; + +declare class C { + foo(x:number): number; + foo(x:string): string; + + bar(x: { a: number }): number; + bar(x: { a: string }): string; +} + +var a = new C(); + +a.foo(0); // ok +a.foo(\"hey\"); // ok +a.foo(true); // error, function cannot be called on intersection type + +a.bar({ a: 0 }); // ok +a.bar({ a: \"hey\" }); // ok +a.bar({ a: true }); // error, function cannot be called on intersection type + +declare var x: { a: boolean; } & { b: string }; + +a.bar(x); // error with nested intersection info (outer for bar, inner for x) + +/********** tests ************** +interface Dummy { + dumb(foo: (x:number) => number):number; + dumb(foo: (x:string) => string):string; + + dumber(bar: (x:T) => Array):U; + dumber(bar: (x:T) => U):Array; +} + +function foo(x:string):string { return x; } +var y:number = new Dummy().dumb(foo); + +function bar1(x:number):Array { return []; } +var z1:number = new Dummy().dumber(bar1); + +function bar2(x:number):string { return \"...\"; } +var z2:Array = new Dummy().dumber(bar2); +*/ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"function foo() { + var output = new FakeUint8Array(); + output.set(new FakeUint8Array(), 0); // matches one of the overloads of set +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo() { + var output = new FakeUint8Array(); + output.set(new FakeUint8Array(), 0);// matches one of the overloads of set +} + +" +`; + +exports[`test test2.js 1`] = ` +"declare class Foo { + bar(x: \'hmm\'): number; + bar(x: string): string; +} +var foo = new Foo; +(foo.bar(\'hmm\'): number); // OK +(foo.bar(\'hmmm\'): number); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test3.js 1`] = ` +"// passing a union-like thing into an overload is ok +// if overload handles each branch of union-like thing + +// unions +declare function f(x: string): void; +declare function f(x: number): void; +declare var x_f: string | number; +f(x_f); // ok + +// maybe +declare function g(x: null): void; +declare function g(x: void): void; +declare function g(x: string): void; +declare var x_g: ?string; +g(x_g); // ok + +// optional +declare function h(x: void): void; +declare function h(x: string): void; +declare var x_h: {p?: string}; +h(x_h.p); // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test union.js 1`] = ` +"function foo (x: $Either,U>): Array { return []; } + +var x1:number = foo(0)[0]; +var x2:string = foo([\"\"])[0]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/overload/jsfmt.spec.js b/tests/overload/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/overload/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/overload/lib/__snapshots__/jsfmt.spec.js.snap b/tests/overload/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b85798c12da2 --- /dev/null +++ b/tests/overload/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,23 @@ +exports[`test lib.js 1`] = ` +"declare class FakeUint8Array { + set(index: number, value: number): void; + set(array: FakeUint8Array | Array, offset?: number): void; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/overload/lib/jsfmt.spec.js b/tests/overload/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/overload/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/overload/lib/lib.js b/tests/overload/lib/lib.js new file mode 100644 index 000000000000..616d065acbe6 --- /dev/null +++ b/tests/overload/lib/lib.js @@ -0,0 +1,4 @@ +declare class FakeUint8Array { + set(index: number, value: number): void; + set(array: FakeUint8Array | Array, offset?: number): void; +} diff --git a/tests/overload/overload.js b/tests/overload/overload.js new file mode 100644 index 000000000000..ca2d8848bba4 --- /dev/null +++ b/tests/overload/overload.js @@ -0,0 +1,51 @@ +/** + * tests of overload selection + * + * @flow + */ + +var x1: number = "".match(0)[0]; +var x2: number = "".match(/pattern/)[0]; +var x3: string = "".replace(/pattern/,"..."); +var x4: number = "".split(/pattern/)[0]; + +declare class C { + foo(x:number): number; + foo(x:string): string; + + bar(x: { a: number }): number; + bar(x: { a: string }): string; +} + +var a = new C(); + +a.foo(0); // ok +a.foo("hey"); // ok +a.foo(true); // error, function cannot be called on intersection type + +a.bar({ a: 0 }); // ok +a.bar({ a: "hey" }); // ok +a.bar({ a: true }); // error, function cannot be called on intersection type + +declare var x: { a: boolean; } & { b: string }; + +a.bar(x); // error with nested intersection info (outer for bar, inner for x) + +/********** tests ************** +interface Dummy { + dumb(foo: (x:number) => number):number; + dumb(foo: (x:string) => string):string; + + dumber(bar: (x:T) => Array):U; + dumber(bar: (x:T) => U):Array; +} + +function foo(x:string):string { return x; } +var y:number = new Dummy().dumb(foo); + +function bar1(x:number):Array { return []; } +var z1:number = new Dummy().dumber(bar1); + +function bar2(x:number):string { return "..."; } +var z2:Array = new Dummy().dumber(bar2); +*/ diff --git a/tests/overload/test.js b/tests/overload/test.js new file mode 100644 index 000000000000..1dc44ef28277 --- /dev/null +++ b/tests/overload/test.js @@ -0,0 +1,4 @@ +function foo() { + var output = new FakeUint8Array(); + output.set(new FakeUint8Array(), 0); // matches one of the overloads of set +} diff --git a/tests/overload/test2.js b/tests/overload/test2.js new file mode 100644 index 000000000000..d3d1fb7f5ba6 --- /dev/null +++ b/tests/overload/test2.js @@ -0,0 +1,7 @@ +declare class Foo { + bar(x: 'hmm'): number; + bar(x: string): string; +} +var foo = new Foo; +(foo.bar('hmm'): number); // OK +(foo.bar('hmmm'): number); // error diff --git a/tests/overload/test3.js b/tests/overload/test3.js new file mode 100644 index 000000000000..4c4fefe6e609 --- /dev/null +++ b/tests/overload/test3.js @@ -0,0 +1,21 @@ +// passing a union-like thing into an overload is ok +// if overload handles each branch of union-like thing + +// unions +declare function f(x: string): void; +declare function f(x: number): void; +declare var x_f: string | number; +f(x_f); // ok + +// maybe +declare function g(x: null): void; +declare function g(x: void): void; +declare function g(x: string): void; +declare var x_g: ?string; +g(x_g); // ok + +// optional +declare function h(x: void): void; +declare function h(x: string): void; +declare var x_h: {p?: string}; +h(x_h.p); // ok diff --git a/tests/overload/union.js b/tests/overload/union.js new file mode 100644 index 000000000000..4e707c3feb53 --- /dev/null +++ b/tests/overload/union.js @@ -0,0 +1,4 @@ +function foo (x: $Either,U>): Array { return []; } + +var x1:number = foo(0)[0]; +var x2:string = foo([""])[0]; diff --git a/tests/parse/__snapshots__/jsfmt.spec.js.snap b/tests/parse/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9a0838ba525a --- /dev/null +++ b/tests/parse/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,90 @@ +exports[`test fail.js 1`] = ` +". +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (1:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3592:12) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test fail-flow.js 1`] = ` +"/* @flow */ + +. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (3:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3592:12) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test fail-flow-2.js 1`] = ` +"/** + * @flow */ + +. +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (4:0) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3592:12) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) + at Parser.parseMaybeAssign (/node_modules/babylon/lib/index.js:5700:20) +" +`; + +exports[`test no_parse_error.js 1`] = ` +"/* +@flow +*/ + +var x = \'Test\'; +var y = 5 / x; + +var z: { + type: number, + y: string +} = {type: 1, y: \'hey\'}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* +@flow +*/ +var x = \"Test\"; +var y = 5 / x; +var z: { type: number, y: string } = { type: 1, y: \"hey\" }; + +" +`; diff --git a/tests/parse/fail-flow-2.js b/tests/parse/fail-flow-2.js new file mode 100644 index 000000000000..97dfd87f73a3 --- /dev/null +++ b/tests/parse/fail-flow-2.js @@ -0,0 +1,4 @@ +/** + * @flow */ + +. diff --git a/tests/parse/fail-flow.js b/tests/parse/fail-flow.js new file mode 100644 index 000000000000..762b3652bbfe --- /dev/null +++ b/tests/parse/fail-flow.js @@ -0,0 +1,3 @@ +/* @flow */ + +. diff --git a/tests/parse/fail.js b/tests/parse/fail.js new file mode 100644 index 000000000000..9c558e357c41 --- /dev/null +++ b/tests/parse/fail.js @@ -0,0 +1 @@ +. diff --git a/tests/parse/jsfmt.spec.js b/tests/parse/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/parse/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/parse/no_parse_error.js b/tests/parse/no_parse_error.js new file mode 100644 index 000000000000..51fd29947373 --- /dev/null +++ b/tests/parse/no_parse_error.js @@ -0,0 +1,11 @@ +/* +@flow +*/ + +var x = 'Test'; +var y = 5 / x; + +var z: { + type: number, + y: string +} = {type: 1, y: 'hey'}; diff --git a/tests/parse_error_haste/Client.js b/tests/parse_error_haste/Client.js new file mode 100644 index 000000000000..b3827baaa074 --- /dev/null +++ b/tests/parse_error_haste/Client.js @@ -0,0 +1,11 @@ +/** + * Client imports some but not all modules, + * triggering/suppressing parse errors. + * @flow + */ + +// non-flow files should not show parse errors +var A = require("Foo"); // non-Flow file @providesModule Foo +var B = require("./NoProvides"); // non-Flow file + +var C = require("./ParseError"); // Flow file diff --git a/tests/parse_error_haste/NoProvides.js b/tests/parse_error_haste/NoProvides.js new file mode 100644 index 000000000000..16817984e83b --- /dev/null +++ b/tests/parse_error_haste/NoProvides.js @@ -0,0 +1,9 @@ +/** + * Parse errors, imported, not in flow, no provides module. + * No parse errors are raised because it is ignored by flow. + */ +function f(s) { ### // illegal token + return s; +} + +module.exports = { f: f } diff --git a/tests/parse_error_haste/ParseError.js b/tests/parse_error_haste/ParseError.js new file mode 100644 index 000000000000..6766fa50ec34 --- /dev/null +++ b/tests/parse_error_haste/ParseError.js @@ -0,0 +1,6 @@ +// @flow + +function foo() { ### // invalid token +} + +module.exports = foo; diff --git a/tests/parse_error_haste/Provides.js b/tests/parse_error_haste/Provides.js new file mode 100644 index 000000000000..da8e04dcaba6 --- /dev/null +++ b/tests/parse_error_haste/Provides.js @@ -0,0 +1,12 @@ +/** + * Parse errors, imported, not in flow, provides module. + * Should see a parse error in this file, and module + * not found in client. + * @providesModule Foo + * @noflow + */ +function f(s: string): string { ### // illegal token + return s; +} + +module.exports = { f: f } diff --git a/tests/parse_error_haste/Unimported.js b/tests/parse_error_haste/Unimported.js new file mode 100644 index 000000000000..177d59e6ab69 --- /dev/null +++ b/tests/parse_error_haste/Unimported.js @@ -0,0 +1,10 @@ +/** + * Parse errors but not in flow and not imported. + * Should see no parse errors for this file. + * @providesModule Bar + */ +function f(s:string):string { ### // illegal token + return s; +} + +module.exports = { f: f } diff --git a/tests/parse_error_haste/__snapshots__/jsfmt.spec.js.snap b/tests/parse_error_haste/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0fd5bcf9e3fe --- /dev/null +++ b/tests/parse_error_haste/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,142 @@ +exports[`test Client.js 1`] = ` +"/** + * Client imports some but not all modules, + * triggering/suppressing parse errors. + * @flow + */ + +// non-flow files should not show parse errors +var A = require(\"Foo\"); // non-Flow file @providesModule Foo +var B = require(\"./NoProvides\"); // non-Flow file + +var C = require(\"./ParseError\"); // Flow file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Client imports some but not all modules, + * triggering/suppressing parse errors. + * @flow + */ +// non-flow files should not show parse errors +var A = require(\"Foo\");// non-Flow file @providesModule Foo +var B = require(\"./NoProvides\");// non-Flow file +var C = require(\"./ParseError\");// Flow file + +" +`; + +exports[`test NoProvides.js 1`] = ` +"/** + * Parse errors, imported, not in flow, no provides module. + * No parse errors are raised because it is ignored by flow. + */ +function f(s) { ### // illegal token + return s; +} + +module.exports = { f: f } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (5:16) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; + +exports[`test ParseError.js 1`] = ` +"// @flow + +function foo() { ### // invalid token +} + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (3:17) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; + +exports[`test Provides.js 1`] = ` +"/** + * Parse errors, imported, not in flow, provides module. + * Should see a parse error in this file, and module + * not found in client. + * @providesModule Foo + * @noflow + */ +function f(s: string): string { ### // illegal token + return s; +} + +module.exports = { f: f } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (8:32) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; + +exports[`test Unimported.js 1`] = ` +"/** + * Parse errors but not in flow and not imported. + * Should see no parse errors for this file. + * @providesModule Bar + */ +function f(s:string):string { ### // illegal token + return s; +} + +module.exports = { f: f } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (6:30) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; diff --git a/tests/parse_error_haste/jsfmt.spec.js b/tests/parse_error_haste/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/parse_error_haste/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/parse_error_node/Client.js b/tests/parse_error_node/Client.js new file mode 100644 index 000000000000..45ea11195d28 --- /dev/null +++ b/tests/parse_error_node/Client.js @@ -0,0 +1,10 @@ +/** + * Client imports some but not all modules, + * triggering/suppressing parse errors. + * @flow + */ + +// non-flow files should not give parse errors +var A = require("./Imported"); // non-Flow file @providesModule Foo + +var B = require("./ParseError"); // Flow file diff --git a/tests/parse_error_node/Imported.js b/tests/parse_error_node/Imported.js new file mode 100644 index 000000000000..16817984e83b --- /dev/null +++ b/tests/parse_error_node/Imported.js @@ -0,0 +1,9 @@ +/** + * Parse errors, imported, not in flow, no provides module. + * No parse errors are raised because it is ignored by flow. + */ +function f(s) { ### // illegal token + return s; +} + +module.exports = { f: f } diff --git a/tests/parse_error_node/ParseError.js b/tests/parse_error_node/ParseError.js new file mode 100644 index 000000000000..6766fa50ec34 --- /dev/null +++ b/tests/parse_error_node/ParseError.js @@ -0,0 +1,6 @@ +// @flow + +function foo() { ### // invalid token +} + +module.exports = foo; diff --git a/tests/parse_error_node/Unimported.js b/tests/parse_error_node/Unimported.js new file mode 100644 index 000000000000..177d59e6ab69 --- /dev/null +++ b/tests/parse_error_node/Unimported.js @@ -0,0 +1,10 @@ +/** + * Parse errors but not in flow and not imported. + * Should see no parse errors for this file. + * @providesModule Bar + */ +function f(s:string):string { ### // illegal token + return s; +} + +module.exports = { f: f } diff --git a/tests/parse_error_node/__snapshots__/jsfmt.spec.js.snap b/tests/parse_error_node/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bb6c5eb1fac5 --- /dev/null +++ b/tests/parse_error_node/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,108 @@ +exports[`test Client.js 1`] = ` +"/** + * Client imports some but not all modules, + * triggering/suppressing parse errors. + * @flow + */ + +// non-flow files should not give parse errors +var A = require(\"./Imported\"); // non-Flow file @providesModule Foo + +var B = require(\"./ParseError\"); // Flow file +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Client imports some but not all modules, + * triggering/suppressing parse errors. + * @flow + */ +// non-flow files should not give parse errors +var A = require(\"./Imported\");// non-Flow file @providesModule Foo +var B = require(\"./ParseError\");// Flow file + +" +`; + +exports[`test Imported.js 1`] = ` +"/** + * Parse errors, imported, not in flow, no provides module. + * No parse errors are raised because it is ignored by flow. + */ +function f(s) { ### // illegal token + return s; +} + +module.exports = { f: f } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (5:16) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; + +exports[`test ParseError.js 1`] = ` +"// @flow + +function foo() { ### // invalid token +} + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (3:17) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; + +exports[`test Unimported.js 1`] = ` +"/** + * Parse errors but not in flow and not imported. + * Should see no parse errors for this file. + * @providesModule Bar + */ +function f(s:string):string { ### // illegal token + return s; +} + +module.exports = { f: f } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected character \'#\' (6:30) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.getTokenFromCode (/node_modules/babylon/lib/index.js:1065:10) + at Parser.readToken (/node_modules/babylon/lib/index.js:694:19) + at Parser. (/node_modules/babylon/lib/index.js:6441:20) + at Parser.readToken (/node_modules/babylon/lib/index.js:5376:22) + at Parser.nextToken (/node_modules/babylon/lib/index.js:684:19) + at Parser.next (/node_modules/babylon/lib/index.js:609:10) + at Parser.eat (/node_modules/babylon/lib/index.js:616:12) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:15) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) +" +`; diff --git a/tests/parse_error_node/jsfmt.spec.js b/tests/parse_error_node/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/parse_error_node/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/path/__snapshots__/jsfmt.spec.js.snap b/tests/path/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a2a3fe378afd --- /dev/null +++ b/tests/path/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test while.js 1`] = ` +"var x = 1; +while(typeof x == "number" || typeof x == "string") { + x = x + 1; + if (true) x = ""; +} +var z:number = x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x = 1; +while (typeof x == "number" || typeof x == "string") { + x = x + 1; + if (true) + x = ""; +} +var z: number = x; + +" +`; diff --git a/tests/path/jsfmt.spec.js b/tests/path/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/path/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/path/while.js b/tests/path/while.js new file mode 100644 index 000000000000..83c943b5faf5 --- /dev/null +++ b/tests/path/while.js @@ -0,0 +1,6 @@ +var x = 1; +while(typeof x == "number" || typeof x == "string") { + x = x + 1; + if (true) x = ""; +} +var z:number = x; diff --git a/tests/plsummit/__snapshots__/jsfmt.spec.js.snap b/tests/plsummit/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ffd3dd6c2c29 --- /dev/null +++ b/tests/plsummit/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,132 @@ +exports[`test arrays.js 1`] = ` +"function foo(x) { return [x, x > 0, \"number \" + x]; } + +var [n, b, s] = foo(42); +n * s.length; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function foo(x) { + return [ x, x > 0, \"number \" + x ]; +} +var [ n, b, s ] = foo(42); +n * s.length; + +" +`; + +exports[`test export_class.js 1`] = ` +"class C { + x: number; + constructor(x: number) { this.x = x; } +} + +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + x: number; + constructor(x: number) { + this.x = x; + } +} +module.exports = C; + +" +`; + +exports[`test generics.js 1`] = ` +"/* @flow */ + +var r: number = 0; +function foo(x: X): X { r = x; return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test import_class.js 1`] = ` +"var C = require(\'./export_class\'); + +var c = new C(\"\"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var C = require(\"./export_class\"); +var c = new C(\"\"); + +" +`; + +exports[`test locals.js 1`] = ` +"/* @flow */ + +function foo() { + var x = 0; + var y = x; +} + +function bar(x: ?string): number { + if (x == null) x = \"\"; + return x.length; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo() { + var x = 0; + var y = x; +} +function bar(x: ?string): number { + if (x == null) + x = \"\"; + return x.length; +} + +" +`; + +exports[`test objects.js 1`] = ` +"function C() { this.x = 0; } +C.prototype.foo = function() { return this.x; } + +var c = new C(); +var x: string = c.foo(); + +function foo() { return this.y; } +function bar() { return this.foo(); } +var o = { y: \"\", foo: foo, bar: bar }; +var o2 = { y: 0, foo: foo, bar: bar }; + +o.bar(); +var y: number = o2.bar(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function C() { + this.x = 0; +} +C.prototype.foo = function() { + return this.x; +}; +var c = new C(); +var x: string = c.foo(); +function foo() { + return this.y; +} +function bar() { + return this.foo(); +} +var o = { y: \"\", foo: foo, bar: bar }; +var o2 = { y: 0, foo: foo, bar: bar }; +o.bar(); +var y: number = o2.bar(); + +" +`; diff --git a/tests/plsummit/arrays.js b/tests/plsummit/arrays.js new file mode 100644 index 000000000000..9ed4c7b22f49 --- /dev/null +++ b/tests/plsummit/arrays.js @@ -0,0 +1,4 @@ +function foo(x) { return [x, x > 0, "number " + x]; } + +var [n, b, s] = foo(42); +n * s.length; diff --git a/tests/plsummit/export_class.js b/tests/plsummit/export_class.js new file mode 100644 index 000000000000..8f796fb05385 --- /dev/null +++ b/tests/plsummit/export_class.js @@ -0,0 +1,6 @@ +class C { + x: number; + constructor(x: number) { this.x = x; } +} + +module.exports = C; diff --git a/tests/plsummit/generics.js b/tests/plsummit/generics.js new file mode 100644 index 000000000000..ec4d476134da --- /dev/null +++ b/tests/plsummit/generics.js @@ -0,0 +1,4 @@ +/* @flow */ + +var r: number = 0; +function foo(x: X): X { r = x; return x; } diff --git a/tests/plsummit/import_class.js b/tests/plsummit/import_class.js new file mode 100644 index 000000000000..4a361b1515cd --- /dev/null +++ b/tests/plsummit/import_class.js @@ -0,0 +1,3 @@ +var C = require('./export_class'); + +var c = new C(""); diff --git a/tests/plsummit/jsfmt.spec.js b/tests/plsummit/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/plsummit/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/plsummit/locals.js b/tests/plsummit/locals.js new file mode 100644 index 000000000000..08f150b95c56 --- /dev/null +++ b/tests/plsummit/locals.js @@ -0,0 +1,11 @@ +/* @flow */ + +function foo() { + var x = 0; + var y = x; +} + +function bar(x: ?string): number { + if (x == null) x = ""; + return x.length; +} diff --git a/tests/plsummit/objects.js b/tests/plsummit/objects.js new file mode 100644 index 000000000000..29af3f72b10f --- /dev/null +++ b/tests/plsummit/objects.js @@ -0,0 +1,13 @@ +function C() { this.x = 0; } +C.prototype.foo = function() { return this.x; } + +var c = new C(); +var x: string = c.foo(); + +function foo() { return this.y; } +function bar() { return this.foo(); } +var o = { y: "", foo: foo, bar: bar }; +var o2 = { y: 0, foo: foo, bar: bar }; + +o.bar(); +var y: number = o2.bar(); diff --git a/tests/poly/__snapshots__/jsfmt.spec.js.snap b/tests/poly/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4a4d1b086938 --- /dev/null +++ b/tests/poly/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,192 @@ +exports[`test annot.js 1`] = ` +"class A { } +new A; // OK, implicitly inferred type args +class B extends A { } // OK, same as above + +function foo(b): A { // ok but unsafe, caller may assume any type arg + return b ? (new A: A): (new A: A); +} + +function bar(): A<*> { // error, * can\'t be {} and {x: string} at the same time + return (new A: A<{}>) || (new A: A<{x: string}>); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test implicit_bounded_instantiation.js 1`] = ` +"// @flow + +class Base {} +class Middle extends Base {} +class Child extends Middle {} + +class C { + meth(a: T): T { + return a; + } +} + +// T is implicitly (bounded by) Middle in constructor call if not provided. +// Explicit type arg is required in annotation - here a wildcard captures it. +var a: C<*> = new C(); + +a.meth(new Middle()); +a.meth(new Child()); +a.meth(42); // Error: number ~> Middle +a.meth(new Base()); // Error: Base ~> Middle +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1029.js 1`] = ` +"// @flow + +// naive unification causes combinatorial explosion here, +// effectively hangs + +declare type Box = { + map1(f: (x: T) => U): Box; + map2(f: (x: T) => U): Box; + map3(f: (x: T) => U): Box; + map4(f: (x: T) => U): Box; + map5(f: (x: T) => U): Box; +} + +declare var bool: Box; + +declare function unbox(box: Box): A + +unbox(bool); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test poly.js 1`] = ` +"class Foo { + x:T; + constructor(x:T) { this.x = x; } +} + +function bar(foo:Foo,y:S):Foo { return new Foo(y); } + +var P = { + bar: bar +} + +declare var Q: { + bar(foo:Foo,y:S):Foo; +} + +var foo = new Foo(0); +var x:string = foo.x; +var z:Foo = Q.bar(foo,\"\"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"class C { + foo(x: X): X { return x; } + foo_(x: X): number { return x; } + bar(x: X): X { return x; } + qux(x: number): number { return x; } +} +class D extends C { + foo(x: number): number { return x; } // error (specialization, see below) + foo_(x: number): number { return x; } // OK, but only because the overridden foo accepts no more than number and returns exactly number + bar(x: X): X { return x; } // OK + qux(x: X): X { return x; } // OK (generalization) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + foo(x: X): X { + return x; + } + foo_(x: X): number { + return x; + } + bar(x: X): X { + return x; + } + qux(x: number): number { + return x; + } +} +class D extends C { + foo(x: number): number { + return x; + }// error (specialization, see below) + foo_(x: number): number { + return x; + }// OK, but only because the overridden foo accepts no more than number and returns exactly number + bar(x: X): X { + return x; + }// OK + qux(x: X): X { + return x; + }// OK (generalization) +} + +" +`; diff --git a/tests/poly/annot.js b/tests/poly/annot.js new file mode 100644 index 000000000000..f5feef466989 --- /dev/null +++ b/tests/poly/annot.js @@ -0,0 +1,11 @@ +class A { } +new A; // OK, implicitly inferred type args +class B extends A { } // OK, same as above + +function foo(b): A { // ok but unsafe, caller may assume any type arg + return b ? (new A: A): (new A: A); +} + +function bar(): A<*> { // error, * can't be {} and {x: string} at the same time + return (new A: A<{}>) || (new A: A<{x: string}>); +} diff --git a/tests/poly/implicit_bounded_instantiation.js b/tests/poly/implicit_bounded_instantiation.js new file mode 100644 index 000000000000..e684afff4d6b --- /dev/null +++ b/tests/poly/implicit_bounded_instantiation.js @@ -0,0 +1,20 @@ +// @flow + +class Base {} +class Middle extends Base {} +class Child extends Middle {} + +class C { + meth(a: T): T { + return a; + } +} + +// T is implicitly (bounded by) Middle in constructor call if not provided. +// Explicit type arg is required in annotation - here a wildcard captures it. +var a: C<*> = new C(); + +a.meth(new Middle()); +a.meth(new Child()); +a.meth(42); // Error: number ~> Middle +a.meth(new Base()); // Error: Base ~> Middle diff --git a/tests/poly/issue-1029.js b/tests/poly/issue-1029.js new file mode 100644 index 000000000000..5b7ac33f3823 --- /dev/null +++ b/tests/poly/issue-1029.js @@ -0,0 +1,18 @@ +// @flow + +// naive unification causes combinatorial explosion here, +// effectively hangs + +declare type Box = { + map1(f: (x: T) => U): Box; + map2(f: (x: T) => U): Box; + map3(f: (x: T) => U): Box; + map4(f: (x: T) => U): Box; + map5(f: (x: T) => U): Box; +} + +declare var bool: Box; + +declare function unbox(box: Box): A + +unbox(bool); diff --git a/tests/poly/jsfmt.spec.js b/tests/poly/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/poly/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/poly/poly.js b/tests/poly/poly.js new file mode 100644 index 000000000000..be8b8014784e --- /dev/null +++ b/tests/poly/poly.js @@ -0,0 +1,18 @@ +class Foo { + x:T; + constructor(x:T) { this.x = x; } +} + +function bar(foo:Foo,y:S):Foo { return new Foo(y); } + +var P = { + bar: bar +} + +declare var Q: { + bar(foo:Foo,y:S):Foo; +} + +var foo = new Foo(0); +var x:string = foo.x; +var z:Foo = Q.bar(foo,""); diff --git a/tests/poly/test.js b/tests/poly/test.js new file mode 100644 index 000000000000..9e72bab6ada9 --- /dev/null +++ b/tests/poly/test.js @@ -0,0 +1,12 @@ +class C { + foo(x: X): X { return x; } + foo_(x: X): number { return x; } + bar(x: X): X { return x; } + qux(x: number): number { return x; } +} +class D extends C { + foo(x: number): number { return x; } // error (specialization, see below) + foo_(x: number): number { return x; } // OK, but only because the overridden foo accepts no more than number and returns exactly number + bar(x: X): X { return x; } // OK + qux(x: X): X { return x; } // OK (generalization) +} diff --git a/tests/poly_class_export/A.js b/tests/poly_class_export/A.js new file mode 100644 index 000000000000..3a6aecfd9ff5 --- /dev/null +++ b/tests/poly_class_export/A.js @@ -0,0 +1,7 @@ +// @flow + +class A { + x: T +} + +module.exports = A; diff --git a/tests/poly_class_export/B.js b/tests/poly_class_export/B.js new file mode 100644 index 000000000000..d4282e925827 --- /dev/null +++ b/tests/poly_class_export/B.js @@ -0,0 +1,11 @@ +// @flow + +let A = require('./A'); + +class B extends A { + constructor() { + super(); + } +} + +module.exports = new B(); diff --git a/tests/poly_class_export/C.js b/tests/poly_class_export/C.js new file mode 100644 index 000000000000..e017e2c83c91 --- /dev/null +++ b/tests/poly_class_export/C.js @@ -0,0 +1,14 @@ +// @flow + +// This test exports a function whose return type is the class's `this` type. +// It should be inferred (no annotation required). + +class Foo { + foo(): this { + return this; + } +} + +export function f(x: Foo) { + return x.foo(); +} diff --git a/tests/poly_class_export/__snapshots__/jsfmt.spec.js.snap b/tests/poly_class_export/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..038cb4d4f12d --- /dev/null +++ b/tests/poly_class_export/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,88 @@ +exports[`test A.js 1`] = ` +"// @flow + +class A { + x: T +} + +module.exports = A; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test B.js 1`] = ` +"// @flow + +let A = require(\'./A\'); + +class B extends A { + constructor() { + super(); + } +} + +module.exports = new B(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1180:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test C.js 1`] = ` +"// @flow + +// This test exports a function whose return type is the class\'s \`this\` type. +// It should be inferred (no annotation required). + +class Foo { + foo(): this { + return this; + } +} + +export function f(x: Foo) { + return x.foo(); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// This test exports a function whose return type is the class\'s \`this\` type. +// It should be inferred (no annotation required). +class Foo { + foo(): this { + return this; + } +} +export function f(x: Foo) { + return x.foo(); +} + +" +`; diff --git a/tests/poly_class_export/jsfmt.spec.js b/tests/poly_class_export/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/poly_class_export/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/poly_overload/decls/__snapshots__/jsfmt.spec.js.snap b/tests/poly_overload/decls/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ada571d251c5 --- /dev/null +++ b/tests/poly_overload/decls/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,35 @@ +exports[`test typescript-deferred.js 1`] = ` +"interface Some {} +interface Other { x: X; } +interface None {} +interface Nada { y: Y } +interface A { + foo(s: Some, e: None): A; + foo(s: Some, e: Nada): A; + foo(s: Other, e: None): A; + foo(s: Other, e: Nada): A; +} +interface B extends A { + foo(s: Some, e: None): B; + foo(s: Some, e: Nada): B; + foo(s: Other, e: None): B; + foo(s: Other, e: Nada): B; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1384:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/poly_overload/decls/jsfmt.spec.js b/tests/poly_overload/decls/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/poly_overload/decls/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/poly_overload/decls/typescript-deferred.js b/tests/poly_overload/decls/typescript-deferred.js new file mode 100644 index 000000000000..cf6fe780dc37 --- /dev/null +++ b/tests/poly_overload/decls/typescript-deferred.js @@ -0,0 +1,16 @@ +interface Some {} +interface Other { x: X; } +interface None {} +interface Nada { y: Y } +interface A { + foo(s: Some, e: None): A; + foo(s: Some, e: Nada): A; + foo(s: Other, e: None): A; + foo(s: Other, e: Nada): A; +} +interface B extends A { + foo(s: Some, e: None): B; + foo(s: Some, e: Nada): B; + foo(s: Other, e: None): B; + foo(s: Other, e: Nada): B; +} diff --git a/tests/predicates-abstract/__snapshots__/jsfmt.spec.js.snap b/tests/predicates-abstract/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9bb9fc127f51 --- /dev/null +++ b/tests/predicates-abstract/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,278 @@ +exports[`test filter.js 1`] = ` +"// @flow + +// Filter the contents of an array + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +declare var arr: Array; +const barr = my_filter(arr, is_string); +(barr: Array); + +function is_string(x): %checks { + return typeof x === \"string\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (11:23) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test filter-union.js 1`] = ` +"// @flow + +// Filter the contents of an array + + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +type A = { kind: \'A\', u: number } +type B = { kind: \'B\', v: string } +type C = { kind: \'C\', y: boolean } +type D = { kind: \'D\', x: boolean } +type E = { kind: \'E\', y: boolean } + +declare var ab: Array; + +(my_filter(ab, (x): %checks => x.kind === \'A\'): Array); // OK +(my_filter(ab, (x): %checks => x.kind !== \'A\'): Array); // OK +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (16:20) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test refine.js 1`] = ` +"// @flow + +/* + $Pred is an \"abstract predicate type\", i.e. denotes a (function) type that + refines N variables. So if \`cb\` is a function, then it should be refining + exactly N argument. It is abstract in that we do not need to specify: + (a) which variables are going to be refined (just the number), or (b) what + exactly the refinement (predicate) is going to be. + + $Refine is a refinement type, that refines type T with the k-th + argument that gets refined by an abstract preficate type P. +*/ +declare function refine>(v: T, cb: P): $Refine; +// function refine(v, cb) +// { if (cb(v)) { return v; } else { throw new Error(); } } + +/* + Use case +*/ +declare var a: mixed; +var b = refine(a, is_string); +(b: string); + +declare function refine_fst>(v: T, w: T, cb: P): $Refine; +// function refine_fst(v, w, cb) +// { if (cb(v, w)) { return v; } else { throw new Error(); } } + +declare var c: mixed; +declare var d: mixed; + +var e = refine2(c, d, is_string_and_number); +(e: string); + + +declare function refine2>(v: T, w: T, cb: P): $Refine; + +// function refine_fst(v, w, cb) +// { if (cb(v, w)) { return w; } else { throw new Error(); } } + +function is_string(x): boolean %checks { + return typeof x === \"string\"; +} + +function is_string_and_number(x, y): %checks { + return typeof x === \"string\" && typeof y === \"number\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected { (40:31) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:33) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) + at Parser.pp$3.parseFunctionBody (/node_modules/babylon/lib/index.js:4004:22) + at Parser.parseFunctionBody (/node_modules/babylon/lib/index.js:5211:20) + at Parser.pp$1.parseFunction (/node_modules/babylon/lib/index.js:2257:8) + at Parser.pp$1.parseFunctionStatement (/node_modules/babylon/lib/index.js:1926:15) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1712:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) +" +`; + +exports[`test sanity-filter.js 1`] = ` +"// @flow + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +// Sanity check A: filtering the wrong type +declare var a: Array; +const b = my_filter(a, is_string); +(b: Array); + + +// Sanity check B: Passing non-predicate function to filter +declare var c: Array; +const d = my_filter(c, is_string_regular); +(d: Array); + +function is_string(x): boolean %checks { + return typeof x === \"string\"; +} + +function is_string_regular(x): boolean { + return typeof x === \"string\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected { (16:31) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:33) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) + at Parser.pp$3.parseFunctionBody (/node_modules/babylon/lib/index.js:4004:22) + at Parser.parseFunctionBody (/node_modules/babylon/lib/index.js:5211:20) + at Parser.pp$1.parseFunction (/node_modules/babylon/lib/index.js:2257:8) + at Parser.pp$1.parseFunctionStatement (/node_modules/babylon/lib/index.js:1926:15) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1712:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) +" +`; + +exports[`test sanity-filter-union.js 1`] = ` +"// @flow + +// Filter the contents of an array + + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +type A = { kind: \'A\', u: number } +type B = { kind: \'B\', v: string } +type C = { kind: \'C\', y: boolean } +type D = { kind: \'D\', x: boolean } +type E = { kind: \'E\', y: boolean } + +declare var ab: Array; + +(my_filter(ab, (x): %checks => x.kind === \'A\'): Array); // ERROR +(my_filter(ab, (x): %checks => x.kind !== \'A\'): Array); // ERROR +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (16:20) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test sanity-refine.js 1`] = ` +"// @flow + +// Sanity check A: the refinment position index is outside of the allowed range +declare function refine>(v: T, cb: P): $Refine; + +declare var a: mixed; +var b = refine(a, is_string); // ERROR: index out of bounds +(b: string); + + +// Sanity check B: refine2 expects a function that accepts 3 arguments but +// it is called with a function that takes 2 +declare var c: mixed; +declare var d: mixed; +declare var e: mixed; + +declare function refine3>(u: T, v: T, w: T, cb: P): $Refine; + +var e = refine3(c, d, e, is_string_and_number); +(e: string); + +function is_string_and_number(x, y): %checks { + return typeof x === \"string\" && typeof y === \"number\"; +} + + +// Sanity check C: expecting a predicate function but passed a non-predicate one +var e = refine(a, is_string_regular); // ERROR: is_string_regular is not a + // predicate function +(e: number); + +//////////////////////////////////////////////////////////////////////////////// + +function is_string(x): %checks { + return typeof x === \"string\"; +} + +function is_string_regular(x) { + return typeof x === \"string\"; +} + +function is_string_and_number(x, y): %checks { + return typeof x === \"string\" && typeof y === \"number\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (22:37) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; diff --git a/tests/predicates-abstract/filter-union.js b/tests/predicates-abstract/filter-union.js new file mode 100644 index 000000000000..081cd6ebc161 --- /dev/null +++ b/tests/predicates-abstract/filter-union.js @@ -0,0 +1,17 @@ +// @flow + +// Filter the contents of an array + + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +type A = { kind: 'A', u: number } +type B = { kind: 'B', v: string } +type C = { kind: 'C', y: boolean } +type D = { kind: 'D', x: boolean } +type E = { kind: 'E', y: boolean } + +declare var ab: Array; + +(my_filter(ab, (x): %checks => x.kind === 'A'): Array); // OK +(my_filter(ab, (x): %checks => x.kind !== 'A'): Array); // OK diff --git a/tests/predicates-abstract/filter.js b/tests/predicates-abstract/filter.js new file mode 100644 index 000000000000..c14d10737b62 --- /dev/null +++ b/tests/predicates-abstract/filter.js @@ -0,0 +1,13 @@ +// @flow + +// Filter the contents of an array + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +declare var arr: Array; +const barr = my_filter(arr, is_string); +(barr: Array); + +function is_string(x): %checks { + return typeof x === "string"; +} diff --git a/tests/predicates-abstract/jsfmt.spec.js b/tests/predicates-abstract/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/predicates-abstract/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/predicates-abstract/refine.js b/tests/predicates-abstract/refine.js new file mode 100644 index 000000000000..bde9c92f3e60 --- /dev/null +++ b/tests/predicates-abstract/refine.js @@ -0,0 +1,46 @@ +// @flow + +/* + $Pred is an "abstract predicate type", i.e. denotes a (function) type that + refines N variables. So if `cb` is a function, then it should be refining + exactly N argument. It is abstract in that we do not need to specify: + (a) which variables are going to be refined (just the number), or (b) what + exactly the refinement (predicate) is going to be. + + $Refine is a refinement type, that refines type T with the k-th + argument that gets refined by an abstract preficate type P. +*/ +declare function refine>(v: T, cb: P): $Refine; +// function refine(v, cb) +// { if (cb(v)) { return v; } else { throw new Error(); } } + +/* + Use case +*/ +declare var a: mixed; +var b = refine(a, is_string); +(b: string); + +declare function refine_fst>(v: T, w: T, cb: P): $Refine; +// function refine_fst(v, w, cb) +// { if (cb(v, w)) { return v; } else { throw new Error(); } } + +declare var c: mixed; +declare var d: mixed; + +var e = refine2(c, d, is_string_and_number); +(e: string); + + +declare function refine2>(v: T, w: T, cb: P): $Refine; + +// function refine_fst(v, w, cb) +// { if (cb(v, w)) { return w; } else { throw new Error(); } } + +function is_string(x): boolean %checks { + return typeof x === "string"; +} + +function is_string_and_number(x, y): %checks { + return typeof x === "string" && typeof y === "number"; +} diff --git a/tests/predicates-abstract/sanity-filter-union.js b/tests/predicates-abstract/sanity-filter-union.js new file mode 100644 index 000000000000..a3eb6d03be69 --- /dev/null +++ b/tests/predicates-abstract/sanity-filter-union.js @@ -0,0 +1,17 @@ +// @flow + +// Filter the contents of an array + + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +type A = { kind: 'A', u: number } +type B = { kind: 'B', v: string } +type C = { kind: 'C', y: boolean } +type D = { kind: 'D', x: boolean } +type E = { kind: 'E', y: boolean } + +declare var ab: Array; + +(my_filter(ab, (x): %checks => x.kind === 'A'): Array); // ERROR +(my_filter(ab, (x): %checks => x.kind !== 'A'): Array); // ERROR diff --git a/tests/predicates-abstract/sanity-filter.js b/tests/predicates-abstract/sanity-filter.js new file mode 100644 index 000000000000..52ea0aaf6153 --- /dev/null +++ b/tests/predicates-abstract/sanity-filter.js @@ -0,0 +1,22 @@ +// @flow + +declare function my_filter>(v: Array, cb: P): Array<$Refine>; + +// Sanity check A: filtering the wrong type +declare var a: Array; +const b = my_filter(a, is_string); +(b: Array); + + +// Sanity check B: Passing non-predicate function to filter +declare var c: Array; +const d = my_filter(c, is_string_regular); +(d: Array); + +function is_string(x): boolean %checks { + return typeof x === "string"; +} + +function is_string_regular(x): boolean { + return typeof x === "string"; +} diff --git a/tests/predicates-abstract/sanity-refine.js b/tests/predicates-abstract/sanity-refine.js new file mode 100644 index 000000000000..2edc62b47c8d --- /dev/null +++ b/tests/predicates-abstract/sanity-refine.js @@ -0,0 +1,44 @@ +// @flow + +// Sanity check A: the refinment position index is outside of the allowed range +declare function refine>(v: T, cb: P): $Refine; + +declare var a: mixed; +var b = refine(a, is_string); // ERROR: index out of bounds +(b: string); + + +// Sanity check B: refine2 expects a function that accepts 3 arguments but +// it is called with a function that takes 2 +declare var c: mixed; +declare var d: mixed; +declare var e: mixed; + +declare function refine3>(u: T, v: T, w: T, cb: P): $Refine; + +var e = refine3(c, d, e, is_string_and_number); +(e: string); + +function is_string_and_number(x, y): %checks { + return typeof x === "string" && typeof y === "number"; +} + + +// Sanity check C: expecting a predicate function but passed a non-predicate one +var e = refine(a, is_string_regular); // ERROR: is_string_regular is not a + // predicate function +(e: number); + +//////////////////////////////////////////////////////////////////////////////// + +function is_string(x): %checks { + return typeof x === "string"; +} + +function is_string_regular(x) { + return typeof x === "string"; +} + +function is_string_and_number(x, y): %checks { + return typeof x === "string" && typeof y === "number"; +} diff --git a/tests/predicates-declared/__snapshots__/jsfmt.spec.js.snap b/tests/predicates-declared/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5b38e142c50a --- /dev/null +++ b/tests/predicates-declared/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,473 @@ +exports[`test function-bind.js 1`] = ` +"// @flow + +// Sanity checks: +// - use of bind in a position of a function predicate. +// (This case should fall through, as method calls +// are currently not supported.) The original behavior +// (including \`havoc\`) should be retained. + +class C { + m() { + return true; + } + a: 1; + + n() { + if(this.m.bind(this)) { + this.a; + } + } +} + +declare var m: Function; +const o = { a: 1 }; + +if (m.bind(o)) { + o.a; +} + + +class D { + m: Function; + + n() { + if(this.m({})) { } + } +} + +declare var m: Function; +const x = \"\"; +if (m.bind(this)(x)) { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 288, end: 289, loc: [object Object], value: 1, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; + +exports[`test function-union.js 1`] = ` +"// @flow + +declare function f1(x: mixed): boolean %checks(typeof x === \"string\"); +declare function f2(x: mixed): boolean %checks(Array.isArray(x)); + +declare var cond: boolean; + +// Feature check: +function foo(x: number | string | Array): number { + + var f = (cond) ? f1 : f2; + + if (f(x)) { + return x.length; + } else { + return 1; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:39) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test is-string-decl.js 1`] = ` +"// @flow + +declare function is_string(x: mixed): boolean %checks(typeof x === \"string\"); +declare function is_number(x: mixed): boolean %checks(typeof x === \"number\"); + +// Feature check: +function foo(x: string | Array): string { + if (is_string(x)) { + // The use of \`is_string\` as a conditional check + // should guarantee the narrowing of the type of \`x\` + // to string. + return x; + } else { + // Accordingly the negation of the above check + // guarantees that \`x\` here is an Array + return x.join(); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:46) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test logical-or.js 1`] = ` +"// @flow + +// Sanity check: +// - conditional functions do not affect behavior of conditional +// expressions (e.g. \`||\`) + +declare function r(x: string): number; +var s = \'a\'; +var n = r(s) || 1; +(n: number); + +var x = \"\"; +if (x = r(s) || 1) { + (x: number); +} + +declare var dollars: mixed; + +function foo(x: mixed) { return 1; } +(foo(dollars) || 0); + +(Number(dollars) || 0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test object-invariant.js 1`] = ` +"// @flow + +// Sanity check: +// - preserving \`havoc\` semantics + +type Meeting = { + organizer: ?Invitee, + es: Array +} + +type Invitee = { + fbid: number +} + +function f(_this: { m: ?Meeting }): string { + if (!_this.m) { + return \"0\"; + } + + if (_this.m.es.some((a) => a.fbid === 0)) { + + } + return \"3\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test orig-string-tag-check.js 1`] = ` +"// @flow + +// The original first-order case + +function foo(x: string | Array): string { + if (typeof x === \"string\") { + return x; // [ERROR] x: Array doesn\'t match return type + } + else { + return x.join(); // [ERROR] x: string doesn\'t have .join method + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test sanity-conditional.js 1`] = ` +"// @flow + +// ERROR: only allow conditional expressions in \`%checks\` + +declare function foo(x: string): mixed %checks(x = \"1\"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (5:39) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test sanity-fall-through.js 1`] = ` +"// @flow + +// Sanity check: +// - we should still be getting an error at the second return statement + +declare function pred(x: T): boolean; + +function foo(s: Array): string { + if (pred(s)) { + return \"1\"; + } + return 1; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test sanity-invalid-calls.js 1`] = ` +"// @flow + +// Sanity check: +// - invalid calls at predicate positions + +declare function pred(x: T): boolean; + +function foo(s: Array): string { + + if ((1)(s)) { + return \"1\"; + } + + if ((pred + 1)(\"s\")) { + return \"1\"; + } + + return \"1\" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test sanity-is-string-bug.js 1`] = ` +"// @flow + +declare function is_string(x: mixed): boolean %checks(typeof x === \"string\"); +declare function is_number(x: mixed): boolean %checks(typeof x === \"number\"); + +// Sanity check: +// - Erroneous logic + +function bar(x: string | Array): string { + if (is_number(x)) { + return x; + } else { + return x.join(); // error: both string and Array can flow to x + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:46) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test sanity-parameter-mismatch.js 1`] = ` +"// @flow + +// Sanity check: make sure the parameters are checked as usual + +declare function foo( + input: mixed, + types: string | Array +): boolean %checks(typeof input === \"string\" || Array.isArray(input)); + +foo(3, 3); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (8:11) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test sanity-pred-with-body.js 1`] = ` +"// @flow + +// Sanity check: +// - predicate functions cannot have bodies (can only be declarations) + +function pred(x: mixed): boolean %checks(typeof x === \"string\") { // error: cannot use pred type here + return typeof x === \"string\"; +} + +function foo(x: string | Array): string { + if (pred(x)) { + return x; + } + return \"1\" +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected { (6:33) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.expect (/node_modules/babylon/lib/index.js:1621:33) + at Parser.pp$1.parseBlock (/node_modules/babylon/lib/index.js:2119:8) + at Parser.pp$3.parseFunctionBody (/node_modules/babylon/lib/index.js:4004:22) + at Parser.parseFunctionBody (/node_modules/babylon/lib/index.js:5211:20) + at Parser.pp$1.parseFunction (/node_modules/babylon/lib/index.js:2257:8) + at Parser.pp$1.parseFunctionStatement (/node_modules/babylon/lib/index.js:1926:15) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1712:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) +" +`; + +exports[`test sanity-return-type.js 1`] = ` +"// @flow + +declare function f2(x: mixed): string %checks(Array.isArray(x)); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:38) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; diff --git a/tests/predicates-declared/function-bind.js b/tests/predicates-declared/function-bind.js new file mode 100644 index 000000000000..ac501bb17518 --- /dev/null +++ b/tests/predicates-declared/function-bind.js @@ -0,0 +1,40 @@ +// @flow + +// Sanity checks: +// - use of bind in a position of a function predicate. +// (This case should fall through, as method calls +// are currently not supported.) The original behavior +// (including `havoc`) should be retained. + +class C { + m() { + return true; + } + a: 1; + + n() { + if(this.m.bind(this)) { + this.a; + } + } +} + +declare var m: Function; +const o = { a: 1 }; + +if (m.bind(o)) { + o.a; +} + + +class D { + m: Function; + + n() { + if(this.m({})) { } + } +} + +declare var m: Function; +const x = ""; +if (m.bind(this)(x)) { } diff --git a/tests/predicates-declared/function-union.js b/tests/predicates-declared/function-union.js new file mode 100644 index 000000000000..561c9d1eb8ce --- /dev/null +++ b/tests/predicates-declared/function-union.js @@ -0,0 +1,18 @@ +// @flow + +declare function f1(x: mixed): boolean %checks(typeof x === "string"); +declare function f2(x: mixed): boolean %checks(Array.isArray(x)); + +declare var cond: boolean; + +// Feature check: +function foo(x: number | string | Array): number { + + var f = (cond) ? f1 : f2; + + if (f(x)) { + return x.length; + } else { + return 1; + } +} diff --git a/tests/predicates-declared/is-string-decl.js b/tests/predicates-declared/is-string-decl.js new file mode 100644 index 000000000000..11c94296c89f --- /dev/null +++ b/tests/predicates-declared/is-string-decl.js @@ -0,0 +1,18 @@ +// @flow + +declare function is_string(x: mixed): boolean %checks(typeof x === "string"); +declare function is_number(x: mixed): boolean %checks(typeof x === "number"); + +// Feature check: +function foo(x: string | Array): string { + if (is_string(x)) { + // The use of `is_string` as a conditional check + // should guarantee the narrowing of the type of `x` + // to string. + return x; + } else { + // Accordingly the negation of the above check + // guarantees that `x` here is an Array + return x.join(); + } +} diff --git a/tests/predicates-declared/jsfmt.spec.js b/tests/predicates-declared/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/predicates-declared/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/predicates-declared/logical-or.js b/tests/predicates-declared/logical-or.js new file mode 100644 index 000000000000..babe5b660fc1 --- /dev/null +++ b/tests/predicates-declared/logical-or.js @@ -0,0 +1,22 @@ +// @flow + +// Sanity check: +// - conditional functions do not affect behavior of conditional +// expressions (e.g. `||`) + +declare function r(x: string): number; +var s = 'a'; +var n = r(s) || 1; +(n: number); + +var x = ""; +if (x = r(s) || 1) { + (x: number); +} + +declare var dollars: mixed; + +function foo(x: mixed) { return 1; } +(foo(dollars) || 0); + +(Number(dollars) || 0); diff --git a/tests/predicates-declared/object-invariant.js b/tests/predicates-declared/object-invariant.js new file mode 100644 index 000000000000..916f7ead2fdc --- /dev/null +++ b/tests/predicates-declared/object-invariant.js @@ -0,0 +1,24 @@ +// @flow + +// Sanity check: +// - preserving `havoc` semantics + +type Meeting = { + organizer: ?Invitee, + es: Array +} + +type Invitee = { + fbid: number +} + +function f(_this: { m: ?Meeting }): string { + if (!_this.m) { + return "0"; + } + + if (_this.m.es.some((a) => a.fbid === 0)) { + + } + return "3"; +} diff --git a/tests/predicates-declared/orig-string-tag-check.js b/tests/predicates-declared/orig-string-tag-check.js new file mode 100644 index 000000000000..3930027f602f --- /dev/null +++ b/tests/predicates-declared/orig-string-tag-check.js @@ -0,0 +1,12 @@ +// @flow + +// The original first-order case + +function foo(x: string | Array): string { + if (typeof x === "string") { + return x; // [ERROR] x: Array doesn't match return type + } + else { + return x.join(); // [ERROR] x: string doesn't have .join method + } +} diff --git a/tests/predicates-declared/sanity-conditional.js b/tests/predicates-declared/sanity-conditional.js new file mode 100644 index 000000000000..d3d4ced873ad --- /dev/null +++ b/tests/predicates-declared/sanity-conditional.js @@ -0,0 +1,5 @@ +// @flow + +// ERROR: only allow conditional expressions in `%checks` + +declare function foo(x: string): mixed %checks(x = "1"); diff --git a/tests/predicates-declared/sanity-fall-through.js b/tests/predicates-declared/sanity-fall-through.js new file mode 100644 index 000000000000..2a4df3867533 --- /dev/null +++ b/tests/predicates-declared/sanity-fall-through.js @@ -0,0 +1,13 @@ +// @flow + +// Sanity check: +// - we should still be getting an error at the second return statement + +declare function pred(x: T): boolean; + +function foo(s: Array): string { + if (pred(s)) { + return "1"; + } + return 1; +} diff --git a/tests/predicates-declared/sanity-invalid-calls.js b/tests/predicates-declared/sanity-invalid-calls.js new file mode 100644 index 000000000000..1ccb68edb9af --- /dev/null +++ b/tests/predicates-declared/sanity-invalid-calls.js @@ -0,0 +1,19 @@ +// @flow + +// Sanity check: +// - invalid calls at predicate positions + +declare function pred(x: T): boolean; + +function foo(s: Array): string { + + if ((1)(s)) { + return "1"; + } + + if ((pred + 1)("s")) { + return "1"; + } + + return "1" +} diff --git a/tests/predicates-declared/sanity-is-string-bug.js b/tests/predicates-declared/sanity-is-string-bug.js new file mode 100644 index 000000000000..f96d550bb857 --- /dev/null +++ b/tests/predicates-declared/sanity-is-string-bug.js @@ -0,0 +1,15 @@ +// @flow + +declare function is_string(x: mixed): boolean %checks(typeof x === "string"); +declare function is_number(x: mixed): boolean %checks(typeof x === "number"); + +// Sanity check: +// - Erroneous logic + +function bar(x: string | Array): string { + if (is_number(x)) { + return x; + } else { + return x.join(); // error: both string and Array can flow to x + } +} diff --git a/tests/predicates-declared/sanity-parameter-mismatch.js b/tests/predicates-declared/sanity-parameter-mismatch.js new file mode 100644 index 000000000000..5432bc826ac8 --- /dev/null +++ b/tests/predicates-declared/sanity-parameter-mismatch.js @@ -0,0 +1,10 @@ +// @flow + +// Sanity check: make sure the parameters are checked as usual + +declare function foo( + input: mixed, + types: string | Array +): boolean %checks(typeof input === "string" || Array.isArray(input)); + +foo(3, 3); diff --git a/tests/predicates-declared/sanity-pred-with-body.js b/tests/predicates-declared/sanity-pred-with-body.js new file mode 100644 index 000000000000..1a60d83869d4 --- /dev/null +++ b/tests/predicates-declared/sanity-pred-with-body.js @@ -0,0 +1,15 @@ +// @flow + +// Sanity check: +// - predicate functions cannot have bodies (can only be declarations) + +function pred(x: mixed): boolean %checks(typeof x === "string") { // error: cannot use pred type here + return typeof x === "string"; +} + +function foo(x: string | Array): string { + if (pred(x)) { + return x; + } + return "1" +} diff --git a/tests/predicates-declared/sanity-return-type.js b/tests/predicates-declared/sanity-return-type.js new file mode 100644 index 000000000000..7ee0f6a11980 --- /dev/null +++ b/tests/predicates-declared/sanity-return-type.js @@ -0,0 +1,3 @@ +// @flow + +declare function f2(x: mixed): string %checks(Array.isArray(x)); diff --git a/tests/predicates-inferred/__snapshots__/jsfmt.spec.js.snap b/tests/predicates-inferred/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a19780c8be50 --- /dev/null +++ b/tests/predicates-inferred/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,289 @@ +exports[`test sanity.js 1`] = ` +"// @flow + +// Sanity check: shouldn\'t be allowed to declare a predicate AND use \`chekcs\` + +function check(y): %checks(typeof y === \"string\") { + return typeof y === \"number\"; +} + +declare var y: number | boolean; + +if (check(y)) { + (y: number); +} + +// Sanity: disallowed body +function indirect_is_number(y): %checks { + var y = 1; + return typeof y === \"number\"; +} + +function bak(z: string | number): number { + if (indirect_is_number(z)) { + return z; + } else { + return z.length; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:19) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test sanity-multi-params.js 1`] = ` +"// @flow + +// Feature: multi params +function multi_param(w,x,y,z): %checks { + return typeof z === \"string\"; +} + +function foo(x: string | Array): string { + if (multi_param(\"1\", \"2\", x, \"3\")) { + return x; + } else { + return x.join(); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (4:31) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test sanity-ordering.js 1`] = ` +"// @flow + +declare var key: string; +declare var obj: { page: ?Object; }; + +if (dotAccess(obj)) { + (obj.page: Object); +} + +function dotAccess(head, create) { + const path = \'path.location\'; + const stack = path.split(\'.\'); + do { + const key = stack.shift(); + head = head[key] || create && (head[key] = {}); + } while (stack.length && head); + return head; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:925 + if (endsWithBrace(doBody)) + ^ + +ReferenceError: endsWithBrace is not defined + at genericPrintNoParens (/src/printer.js:925:11) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:561:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test sanity-unbound-var.js 1`] = ` +"// @flow + +declare var y: mixed; + +// Sanity check: this should fail, because the preficate function +// checks \`y\` instead of \`x\`. +function err(x): %checks { + return typeof y === \"string\"; +} + +function foo(x: string | Array): string { + if (err(x)) { + return x; + } else { + return x.join(); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (7:17) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test simple-predicate-func.js 1`] = ` +"// @flow + +function is_string(y): %checks { + return typeof y === \"string\"; +} + +function is_bool(y): %checks { + return typeof y === \"boolean\"; +} + +function is_number(y): %checks { + return typeof y === \"number\"; +} + +// Feature check: +function foo(x: string | Array): string { + if (is_string(x)) { + // The use of \`is_string\` as a conditional check + // should guarantee the narrowing of the type of \`x\` + // to string. + return x; + } else { + // Accordingly the negation of the above check + // guarantees that \`x\` here is an Array + return x.join(); + } +} + +// Same as above but refining an offset +function bar(z: { f: string | Array}): string { + if (is_string(z.f)) { + return z.f; + } else { + return z.f.join(); + } +} + +function is_number_or_bool(y): %checks { + return is_number(y) || is_bool(y); +} + +function baz(z: string | number): number { + if (is_number_or_bool(z)) { + return z; + } else { + return z.length; + } +} + +// Feature: multi params +function multi_param(w,x,y,z): %checks { + return typeof z === \"string\"; +} + +function foo(x: string | Array): string { + if (multi_param(\"1\", \"2\", \"3\", x)) { + return x; + } else { + return x.join(); + } +} + +function foo(a, b) { + if (two_strings(a, b)) { + from_two_strings(a, b); + } +} + +function two_strings(x,y): %checks { + return is_string(x) && is_string(y) ; +} + +declare function from_two_strings(x: string, y: string): void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (3:23) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test simple-predicate-func-post.js 1`] = ` +"// @flow + +// Feature check: +// The predicate function is defined after the conditional check + +function foo(x: string | Array): string { + if (is_string(x)) { + // The use of \`is_string\` as a conditional check + // should guarantee the narrowing of the type of \`x\` + // to string. + return x; + } else { + // Accordingly the negation of the above check + // guarantees that \`x\` here is an Array + return x.join(); + } +} + +function is_string(x): %checks { + return typeof x === \"string\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (19:23) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; diff --git a/tests/predicates-inferred/jsfmt.spec.js b/tests/predicates-inferred/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/predicates-inferred/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/predicates-inferred/sanity-multi-params.js b/tests/predicates-inferred/sanity-multi-params.js new file mode 100644 index 000000000000..e08ae04e2c67 --- /dev/null +++ b/tests/predicates-inferred/sanity-multi-params.js @@ -0,0 +1,14 @@ +// @flow + +// Feature: multi params +function multi_param(w,x,y,z): %checks { + return typeof z === "string"; +} + +function foo(x: string | Array): string { + if (multi_param("1", "2", x, "3")) { + return x; + } else { + return x.join(); + } +} diff --git a/tests/predicates-inferred/sanity-ordering.js b/tests/predicates-inferred/sanity-ordering.js new file mode 100644 index 000000000000..741e65fd305f --- /dev/null +++ b/tests/predicates-inferred/sanity-ordering.js @@ -0,0 +1,18 @@ +// @flow + +declare var key: string; +declare var obj: { page: ?Object; }; + +if (dotAccess(obj)) { + (obj.page: Object); +} + +function dotAccess(head, create) { + const path = 'path.location'; + const stack = path.split('.'); + do { + const key = stack.shift(); + head = head[key] || create && (head[key] = {}); + } while (stack.length && head); + return head; +} diff --git a/tests/predicates-inferred/sanity-unbound-var.js b/tests/predicates-inferred/sanity-unbound-var.js new file mode 100644 index 000000000000..8ff02beb0e9c --- /dev/null +++ b/tests/predicates-inferred/sanity-unbound-var.js @@ -0,0 +1,17 @@ +// @flow + +declare var y: mixed; + +// Sanity check: this should fail, because the preficate function +// checks `y` instead of `x`. +function err(x): %checks { + return typeof y === "string"; +} + +function foo(x: string | Array): string { + if (err(x)) { + return x; + } else { + return x.join(); + } +} diff --git a/tests/predicates-inferred/sanity.js b/tests/predicates-inferred/sanity.js new file mode 100644 index 000000000000..5a2aa6d59ce6 --- /dev/null +++ b/tests/predicates-inferred/sanity.js @@ -0,0 +1,27 @@ +// @flow + +// Sanity check: shouldn't be allowed to declare a predicate AND use `chekcs` + +function check(y): %checks(typeof y === "string") { + return typeof y === "number"; +} + +declare var y: number | boolean; + +if (check(y)) { + (y: number); +} + +// Sanity: disallowed body +function indirect_is_number(y): %checks { + var y = 1; + return typeof y === "number"; +} + +function bak(z: string | number): number { + if (indirect_is_number(z)) { + return z; + } else { + return z.length; + } +} diff --git a/tests/predicates-inferred/simple-predicate-func-post.js b/tests/predicates-inferred/simple-predicate-func-post.js new file mode 100644 index 000000000000..ba5f390920dd --- /dev/null +++ b/tests/predicates-inferred/simple-predicate-func-post.js @@ -0,0 +1,21 @@ +// @flow + +// Feature check: +// The predicate function is defined after the conditional check + +function foo(x: string | Array): string { + if (is_string(x)) { + // The use of `is_string` as a conditional check + // should guarantee the narrowing of the type of `x` + // to string. + return x; + } else { + // Accordingly the negation of the above check + // guarantees that `x` here is an Array + return x.join(); + } +} + +function is_string(x): %checks { + return typeof x === "string"; +} diff --git a/tests/predicates-inferred/simple-predicate-func.js b/tests/predicates-inferred/simple-predicate-func.js new file mode 100644 index 000000000000..bb254dbe5c7c --- /dev/null +++ b/tests/predicates-inferred/simple-predicate-func.js @@ -0,0 +1,73 @@ +// @flow + +function is_string(y): %checks { + return typeof y === "string"; +} + +function is_bool(y): %checks { + return typeof y === "boolean"; +} + +function is_number(y): %checks { + return typeof y === "number"; +} + +// Feature check: +function foo(x: string | Array): string { + if (is_string(x)) { + // The use of `is_string` as a conditional check + // should guarantee the narrowing of the type of `x` + // to string. + return x; + } else { + // Accordingly the negation of the above check + // guarantees that `x` here is an Array + return x.join(); + } +} + +// Same as above but refining an offset +function bar(z: { f: string | Array}): string { + if (is_string(z.f)) { + return z.f; + } else { + return z.f.join(); + } +} + +function is_number_or_bool(y): %checks { + return is_number(y) || is_bool(y); +} + +function baz(z: string | number): number { + if (is_number_or_bool(z)) { + return z; + } else { + return z.length; + } +} + +// Feature: multi params +function multi_param(w,x,y,z): %checks { + return typeof z === "string"; +} + +function foo(x: string | Array): string { + if (multi_param("1", "2", "3", x)) { + return x; + } else { + return x.join(); + } +} + +function foo(a, b) { + if (two_strings(a, b)) { + from_two_strings(a, b); + } +} + +function two_strings(x,y): %checks { + return is_string(x) && is_string(y) ; +} + +declare function from_two_strings(x: string, y: string): void; diff --git a/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap b/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f2a3a00e626d --- /dev/null +++ b/tests/predicates-parsing/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,224 @@ +exports[`test fail-0.js 1`] = ` +"// @flow + +// Error: \'declare\', \'checks\' but missing predicate + +declare function f2(x: mixed): boolean %checks; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (5:39) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test fail-1.js 1`] = ` +"// @flow + +// Error: no return statement + +function f6(x: mixed): %checks (x !== null) { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:23) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test fail-2.js 1`] = ` +"// @flow + +var a2 = (x: mixed): %checks (x !== null) => { // Error: body form + var x = 1; return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (3:19) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2043:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) +" +`; + +exports[`test fail-3.js 1`] = ` +"// @flow + +// Cannot declare predicate with a function body is present. + +function f5(x: mixed): %checks (x !== null) { return x !== null } + +var a2 = (x: mixed): %checks (x !== null) => x !== null; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (5:23) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$7.flowParsePrimaryType (/node_modules/babylon/lib/index.js:5099:8) + at Parser.pp$7.flowParsePostfixType (/node_modules/babylon/lib/index.js:5105:19) + at Parser.pp$7.flowParsePrefixType (/node_modules/babylon/lib/index.js:5122:17) + at Parser.pp$7.flowParseAnonFunctionWithoutParens (/node_modules/babylon/lib/index.js:5127:20) + at Parser.pp$7.flowParseIntersectionType (/node_modules/babylon/lib/index.js:5141:19) + at Parser.pp$7.flowParseUnionType (/node_modules/babylon/lib/index.js:5151:19) + at Parser.pp$7.flowParseType (/node_modules/babylon/lib/index.js:5162:19) + at Parser.pp$7.flowParseTypeInitialiser (/node_modules/babylon/lib/index.js:4430:19) +" +`; + +exports[`test pass.js 1`] = ` +"// @flow + +declare function f1(x: mixed): boolean; + +declare function f3(x: mixed): boolean %checks (x !== null); + +declare function f4(x: mixed): boolean %checks (x !== null); + +function f7(x: mixed): %checks { return x !== null } + +var a0 = (x: mixed) => x !== null; + +var a1 = (x: mixed): %checks => x !== null; + +(x): %checks => x !== null; + +const insert_a_really_big_predicated_arrow_function_name_here = (x) + : %checks => x !== null; + +declare var x; +(x) +checks => 123; + +type checks = any; + +declare function f(x: mixed): checks +(typeof x === null); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (5:39) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$7.flowParseDeclareFunction (/node_modules/babylon/lib/index.js:4467:8) + at Parser.pp$7.flowParseDeclare (/node_modules/babylon/lib/index.js:4476:17) + at Parser.parseExpressionStatement (/node_modules/babylon/lib/index.js:5235:25) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1785:17) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) +" +`; + +exports[`test unsupported-0.js 1`] = ` +"// @flow + +// variables cannot be annotated with a predicate type + +var a3: (x: mixed) => boolean %checks (x !== null); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (5:30) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2043:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) +" +`; + +exports[`test unsupported-1.js 1`] = ` +"// @flow + +// (inited) variables cannot be annotated with a predicate type + +var a4: (x: mixed) => boolean %checks = (x: mixed) => x !== null; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (5:30) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2043:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) +" +`; + +exports[`test unsupported-2.js 1`] = ` +"// @flow + +// Error: no support for checked preds + +var a5: (x: mixed) => boolean %checks(x !== null) = + (y: mixed) => typeof y !== \"string\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token, expected ; (5:30) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp.semicolon (/node_modules/babylon/lib/index.js:1614:38) + at Parser.pp$1.parseVarStatement (/node_modules/babylon/lib/index.js:2043:8) + at Parser.pp$1.parseStatement (/node_modules/babylon/lib/index.js:1735:19) + at Parser.parseStatement (/node_modules/babylon/lib/index.js:5224:22) + at Parser.pp$1.parseBlockBody (/node_modules/babylon/lib/index.js:2139:21) + at Parser.pp$1.parseTopLevel (/node_modules/babylon/lib/index.js:1651:8) + at Parser.parse (/node_modules/babylon/lib/index.js:1543:17) + at Object.parse$1 [as parse] (/node_modules/babylon/lib/index.js:6472:37) +" +`; diff --git a/tests/predicates-parsing/fail-0.js b/tests/predicates-parsing/fail-0.js new file mode 100644 index 000000000000..93439645deb4 --- /dev/null +++ b/tests/predicates-parsing/fail-0.js @@ -0,0 +1,5 @@ +// @flow + +// Error: 'declare', 'checks' but missing predicate + +declare function f2(x: mixed): boolean %checks; diff --git a/tests/predicates-parsing/fail-1.js b/tests/predicates-parsing/fail-1.js new file mode 100644 index 000000000000..ceb1e926e073 --- /dev/null +++ b/tests/predicates-parsing/fail-1.js @@ -0,0 +1,5 @@ +// @flow + +// Error: no return statement + +function f6(x: mixed): %checks (x !== null) { } diff --git a/tests/predicates-parsing/fail-2.js b/tests/predicates-parsing/fail-2.js new file mode 100644 index 000000000000..68260c92aecc --- /dev/null +++ b/tests/predicates-parsing/fail-2.js @@ -0,0 +1,5 @@ +// @flow + +var a2 = (x: mixed): %checks (x !== null) => { // Error: body form + var x = 1; return x; +} diff --git a/tests/predicates-parsing/fail-3.js b/tests/predicates-parsing/fail-3.js new file mode 100644 index 000000000000..1cd15ba3f689 --- /dev/null +++ b/tests/predicates-parsing/fail-3.js @@ -0,0 +1,7 @@ +// @flow + +// Cannot declare predicate with a function body is present. + +function f5(x: mixed): %checks (x !== null) { return x !== null } + +var a2 = (x: mixed): %checks (x !== null) => x !== null; diff --git a/tests/predicates-parsing/jsfmt.spec.js b/tests/predicates-parsing/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/predicates-parsing/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/predicates-parsing/pass.js b/tests/predicates-parsing/pass.js new file mode 100644 index 000000000000..05e5c54ec9c6 --- /dev/null +++ b/tests/predicates-parsing/pass.js @@ -0,0 +1,27 @@ +// @flow + +declare function f1(x: mixed): boolean; + +declare function f3(x: mixed): boolean %checks (x !== null); + +declare function f4(x: mixed): boolean %checks (x !== null); + +function f7(x: mixed): %checks { return x !== null } + +var a0 = (x: mixed) => x !== null; + +var a1 = (x: mixed): %checks => x !== null; + +(x): %checks => x !== null; + +const insert_a_really_big_predicated_arrow_function_name_here = (x) + : %checks => x !== null; + +declare var x; +(x) +checks => 123; + +type checks = any; + +declare function f(x: mixed): checks +(typeof x === null); diff --git a/tests/predicates-parsing/unsupported-0.js b/tests/predicates-parsing/unsupported-0.js new file mode 100644 index 000000000000..84ed10e27e21 --- /dev/null +++ b/tests/predicates-parsing/unsupported-0.js @@ -0,0 +1,5 @@ +// @flow + +// variables cannot be annotated with a predicate type + +var a3: (x: mixed) => boolean %checks (x !== null); diff --git a/tests/predicates-parsing/unsupported-1.js b/tests/predicates-parsing/unsupported-1.js new file mode 100644 index 000000000000..c9a7af823fd2 --- /dev/null +++ b/tests/predicates-parsing/unsupported-1.js @@ -0,0 +1,5 @@ +// @flow + +// (inited) variables cannot be annotated with a predicate type + +var a4: (x: mixed) => boolean %checks = (x: mixed) => x !== null; diff --git a/tests/predicates-parsing/unsupported-2.js b/tests/predicates-parsing/unsupported-2.js new file mode 100644 index 000000000000..d4999b9c36b5 --- /dev/null +++ b/tests/predicates-parsing/unsupported-2.js @@ -0,0 +1,6 @@ +// @flow + +// Error: no support for checked preds + +var a5: (x: mixed) => boolean %checks(x !== null) = + (y: mixed) => typeof y !== "string"; diff --git a/tests/private/__snapshots__/jsfmt.spec.js.snap b/tests/private/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..69badd198c90 --- /dev/null +++ b/tests/private/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,36 @@ +exports[`test private.js 1`] = ` +"class A { + x: number; + _x: string; + __x: number; + constructor() { this.x = 0; this._x = ""; this.__x = 0; } +} + +class B extends A { + foo() { + var x: number = this.x; + var _x: string = this._x; + var __x: number = this.__x; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A { + x: number; + _x: string; + __x: number; + constructor() { + this.x = 0; + this._x = ""; + this.__x = 0; + } +} +class B extends A { + foo() { + var x: number = this.x; + var _x: string = this._x; + var __x: number = this.__x; + } +} + +" +`; diff --git a/tests/private/jsfmt.spec.js b/tests/private/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/private/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/private/private.js b/tests/private/private.js new file mode 100644 index 000000000000..60e209d079fc --- /dev/null +++ b/tests/private/private.js @@ -0,0 +1,14 @@ +class A { + x: number; + _x: string; + __x: number; + constructor() { this.x = 0; this._x = ""; this.__x = 0; } +} + +class B extends A { + foo() { + var x: number = this.x; + var _x: string = this._x; + var __x: number = this.__x; + } +} diff --git a/tests/promises/__snapshots__/jsfmt.spec.js.snap b/tests/promises/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7e3ce9ba9dbe --- /dev/null +++ b/tests/promises/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,428 @@ +exports[`test all.js 1`] = ` +"// @flow + +declare var pstr: Promise; +declare var pnum: Promise; + +Promise.all([ + pstr, + pnum, + true, // non-Promise values passed through +]).then((xs) => { + // tuple information is preserved + let [a,b,c] = xs; + (a: number); // Error: string ~> number + (b: boolean); // Error: number ~> boolean + (c: string); // Error: boolean ~> string + + // array element type is (string | number | boolean) + xs.forEach(x => { + (x: void); // Errors: string ~> void, number ~> void, boolean ~> void + }); +}); + +// First argument is required +Promise.all(); // Error: expected array instead of undefined (too few arguments) + +// Mis-typed arg +Promise.all(0); // Error: expected array instead of number + +// Promise.all is a function +(Promise.all : Function); + +// Promise.all supports iterables +function test(val: Iterable>) { + const r: Promise> = Promise.all(val); +} + +function tes2(val: Map>) { + const r: Promise> = Promise.all(val.values()); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test covariance.js 1`] = ` +"/* @flow */ + +async function testAll() { + /* This is a test case from https://github.com/facebook/flow/issues/1143 + * which was previously an error due to Array\'s invariance and an improper + * definition of Promise.all */ + const x: Array> = []; + const y: Promise> = Promise.all(x); + const z: Array = await y; +} + +async function testRace() { + const x: Array> = []; + const y: Promise = Promise.race(x); + const z: ?string = await y; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test promise.js 1`] = ` +"/** + * @flow + */ + +////////////////////////////////////////////////// +// == Promise constructor resolve() function == // +////////////////////////////////////////////////// + +// Promise constructor resolve(T) -> then(T) +new Promise(function(resolve, reject) { + resolve(0); +}).then(function(num) { + var a: number = num; + + // TODO: The error message that results from this is almost useless + var b: string = num; // Error: number ~> string +}); + +// Promise constructor with arrow function resolve(T) -> then(T) +new Promise((resolve, reject) => resolve(0)) + .then(function(num) { + var a: number = num; + + // TODO: The error message that results from this is almost useless + var b: string = num; // Error: number ~> string + }); + +// Promise constructor resolve(Promise) -> then(T) +new Promise(function(resolve, reject) { + resolve(new Promise(function(resolve, reject) { + resolve(0); + })); +}).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise constructor resolve(Promise>) -> then(T) +new Promise(function(resolve, reject) { + resolve(new Promise(function(resolve, reject) { + resolve(new Promise(function(resolve, reject) { + resolve(0); + })); + })); +}).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise constructor resolve(T); resolve(U); -> then(T|U) +new Promise(function(resolve, reject) { + if (Math.random()) { + resolve(42); + } else { + resolve(\'str\'); + } +}).then(function(numOrStr) { + if (typeof numOrStr === \'string\') { + var a: string = numOrStr; + } else { + var b: number = numOrStr; + } + var c: string = numOrStr; // Error: number|string -> string +}); + +///////////////////////////////////////////////// +// == Promise constructor reject() function == // +///////////////////////////////////////////////// + +// TODO: Promise constructor reject(T) -> catch(T) +new Promise(function(resolve, reject) { + reject(0); +}).catch(function(num) { + var a: number = num; + + // TODO + var b: string = num; // Error: number ~> string +}); + +// TODO: Promise constructor reject(Promise) ~> catch(Promise) +new Promise(function(resolve, reject) { + reject(new Promise(function(resolve, reject) { + reject(0); + })); +}).catch(function(num) { + var a: Promise = num; + + // TODO + var b: number = num; // Error: Promise ~> number +}); + +// TODO: Promise constructor reject(T); reject(U); -> then(T|U) +new Promise(function(resolve, reject) { + if (Math.random()) { + reject(42); + } else { + reject(\'str\'); + } +}).catch(function(numOrStr) { + if (typeof numOrStr === \'string\') { + var a: string = numOrStr; + } else { + var b: number = numOrStr; + } + + // TODO + var c: string = numOrStr; // Error: number|string -> string +}); + +///////////////////////////// +// == Promise.resolve() == // +///////////////////////////// + +// Promise.resolve(T) -> then(T) +Promise.resolve(0).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise.resolve(Promise) -> then(T) +Promise.resolve(Promise.resolve(0)).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise.resolve(Promise>) -> then(T) +Promise.resolve(Promise.resolve(Promise.resolve(0))).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +//////////////////////////// +// == Promise.reject() == // +//////////////////////////// + +// TODO: Promise.reject(T) -> catch(T) +Promise.reject(0).catch(function(num) { + var a: number = num; + + // TODO + var b: string = num; // Error: number ~> string +}); + +// TODO: Promise.reject(Promise) -> catch(Promise) +Promise.reject(Promise.resolve(0)).then(function(num) { + var a: Promise = num; + + // TODO + var b: number = num; // Error: Promise ~> number +}); + +////////////////////////////////// +// == Promise.prototype.then == // +////////////////////////////////// + +// resolvedPromise.then():T -> then(T) +Promise.resolve(0) + .then(function(num) { return \'asdf\'; }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// resolvedPromise.then():Promise -> then(T) +Promise.resolve(0) + .then(function(num) { return Promise.resolve(\'asdf\'); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// resolvedPromise.then():Promise> -> then(T) +Promise.resolve(0) + .then(function(num) { return Promise.resolve(Promise.resolve(\'asdf\')); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// TODO: resolvedPromise.then() -> catch(T) +Promise.resolve(0) + .then(function(num) { + throw \'str\'; + }) + .catch(function(str) { + var a: string = str; + + // TODO + var b: number = str; // Error: string ~> number + }); + +/////////////////////////////////// +// == Promise.prototype.catch == // +/////////////////////////////////// + +// rejectedPromise.catch():U -> then(U) +Promise.reject(0) + .catch(function(num) { return \'asdf\'; }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// rejectedPromise.catch():Promise -> then(U) +Promise.reject(0) + .catch(function(num) { return Promise.resolve(\'asdf\'); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// rejectedPromise.catch():Promise> -> then(U) +Promise.reject(0) + .catch(function(num) { return Promise.resolve(Promise.resolve(\'asdf\')); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// TODO: resolvedPromise -> catch() -> then():T +Promise.resolve(0) + .catch(function(err) {}) + .then(function(num) { + var a: number = num; + + // TODO + var b: string = num; // Error: string ~> number + }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test resolve_global.js 1`] = ` +"/** + * test Promise name resolution + * @flow + */ + +/** + * 1. introduce shadowing bindings for important names + */ +class Promise {} + +/** + * 2. implicit refs to Promise during desugaring should be unaffected + */ +async function foo(x: boolean) { + if (x) { + return {bar: \'baz\'}; + } else { + return null; + } +} + +async function run() { + console.log(await foo(true)); + console.log(await foo(false)); +} + +run(); + +/** + * 3. but explicit name refs from code and annos resolve + * using the usual rules + */ +// error: \`Promise\` in return expr is the local binding +async function bar() { + return Promise.resolve(0); +} + +// error: return type anno is a ref to the local binding +async function baz(): Promise { + return 0; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test resolve_void.js 1`] = ` +"// @flow + +(Promise.resolve(): Promise); // error + +(Promise.resolve(undefined): Promise); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/promises/all.js b/tests/promises/all.js new file mode 100644 index 000000000000..74d02a75eae0 --- /dev/null +++ b/tests/promises/all.js @@ -0,0 +1,39 @@ +// @flow + +declare var pstr: Promise; +declare var pnum: Promise; + +Promise.all([ + pstr, + pnum, + true, // non-Promise values passed through +]).then((xs) => { + // tuple information is preserved + let [a,b,c] = xs; + (a: number); // Error: string ~> number + (b: boolean); // Error: number ~> boolean + (c: string); // Error: boolean ~> string + + // array element type is (string | number | boolean) + xs.forEach(x => { + (x: void); // Errors: string ~> void, number ~> void, boolean ~> void + }); +}); + +// First argument is required +Promise.all(); // Error: expected array instead of undefined (too few arguments) + +// Mis-typed arg +Promise.all(0); // Error: expected array instead of number + +// Promise.all is a function +(Promise.all : Function); + +// Promise.all supports iterables +function test(val: Iterable>) { + const r: Promise> = Promise.all(val); +} + +function tes2(val: Map>) { + const r: Promise> = Promise.all(val.values()); +} diff --git a/tests/promises/covariance.js b/tests/promises/covariance.js new file mode 100644 index 000000000000..dbfdd6912d72 --- /dev/null +++ b/tests/promises/covariance.js @@ -0,0 +1,16 @@ +/* @flow */ + +async function testAll() { + /* This is a test case from https://github.com/facebook/flow/issues/1143 + * which was previously an error due to Array's invariance and an improper + * definition of Promise.all */ + const x: Array> = []; + const y: Promise> = Promise.all(x); + const z: Array = await y; +} + +async function testRace() { + const x: Array> = []; + const y: Promise = Promise.race(x); + const z: ?string = await y; +} diff --git a/tests/promises/jsfmt.spec.js b/tests/promises/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/promises/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/promises/promise.js b/tests/promises/promise.js new file mode 100644 index 000000000000..1266b018346d --- /dev/null +++ b/tests/promises/promise.js @@ -0,0 +1,228 @@ +/** + * @flow + */ + +////////////////////////////////////////////////// +// == Promise constructor resolve() function == // +////////////////////////////////////////////////// + +// Promise constructor resolve(T) -> then(T) +new Promise(function(resolve, reject) { + resolve(0); +}).then(function(num) { + var a: number = num; + + // TODO: The error message that results from this is almost useless + var b: string = num; // Error: number ~> string +}); + +// Promise constructor with arrow function resolve(T) -> then(T) +new Promise((resolve, reject) => resolve(0)) + .then(function(num) { + var a: number = num; + + // TODO: The error message that results from this is almost useless + var b: string = num; // Error: number ~> string + }); + +// Promise constructor resolve(Promise) -> then(T) +new Promise(function(resolve, reject) { + resolve(new Promise(function(resolve, reject) { + resolve(0); + })); +}).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise constructor resolve(Promise>) -> then(T) +new Promise(function(resolve, reject) { + resolve(new Promise(function(resolve, reject) { + resolve(new Promise(function(resolve, reject) { + resolve(0); + })); + })); +}).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise constructor resolve(T); resolve(U); -> then(T|U) +new Promise(function(resolve, reject) { + if (Math.random()) { + resolve(42); + } else { + resolve('str'); + } +}).then(function(numOrStr) { + if (typeof numOrStr === 'string') { + var a: string = numOrStr; + } else { + var b: number = numOrStr; + } + var c: string = numOrStr; // Error: number|string -> string +}); + +///////////////////////////////////////////////// +// == Promise constructor reject() function == // +///////////////////////////////////////////////// + +// TODO: Promise constructor reject(T) -> catch(T) +new Promise(function(resolve, reject) { + reject(0); +}).catch(function(num) { + var a: number = num; + + // TODO + var b: string = num; // Error: number ~> string +}); + +// TODO: Promise constructor reject(Promise) ~> catch(Promise) +new Promise(function(resolve, reject) { + reject(new Promise(function(resolve, reject) { + reject(0); + })); +}).catch(function(num) { + var a: Promise = num; + + // TODO + var b: number = num; // Error: Promise ~> number +}); + +// TODO: Promise constructor reject(T); reject(U); -> then(T|U) +new Promise(function(resolve, reject) { + if (Math.random()) { + reject(42); + } else { + reject('str'); + } +}).catch(function(numOrStr) { + if (typeof numOrStr === 'string') { + var a: string = numOrStr; + } else { + var b: number = numOrStr; + } + + // TODO + var c: string = numOrStr; // Error: number|string -> string +}); + +///////////////////////////// +// == Promise.resolve() == // +///////////////////////////// + +// Promise.resolve(T) -> then(T) +Promise.resolve(0).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise.resolve(Promise) -> then(T) +Promise.resolve(Promise.resolve(0)).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +// Promise.resolve(Promise>) -> then(T) +Promise.resolve(Promise.resolve(Promise.resolve(0))).then(function(num) { + var a: number = num; + var b: string = num; // Error: number ~> string +}); + +//////////////////////////// +// == Promise.reject() == // +//////////////////////////// + +// TODO: Promise.reject(T) -> catch(T) +Promise.reject(0).catch(function(num) { + var a: number = num; + + // TODO + var b: string = num; // Error: number ~> string +}); + +// TODO: Promise.reject(Promise) -> catch(Promise) +Promise.reject(Promise.resolve(0)).then(function(num) { + var a: Promise = num; + + // TODO + var b: number = num; // Error: Promise ~> number +}); + +////////////////////////////////// +// == Promise.prototype.then == // +////////////////////////////////// + +// resolvedPromise.then():T -> then(T) +Promise.resolve(0) + .then(function(num) { return 'asdf'; }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// resolvedPromise.then():Promise -> then(T) +Promise.resolve(0) + .then(function(num) { return Promise.resolve('asdf'); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// resolvedPromise.then():Promise> -> then(T) +Promise.resolve(0) + .then(function(num) { return Promise.resolve(Promise.resolve('asdf')); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// TODO: resolvedPromise.then() -> catch(T) +Promise.resolve(0) + .then(function(num) { + throw 'str'; + }) + .catch(function(str) { + var a: string = str; + + // TODO + var b: number = str; // Error: string ~> number + }); + +/////////////////////////////////// +// == Promise.prototype.catch == // +/////////////////////////////////// + +// rejectedPromise.catch():U -> then(U) +Promise.reject(0) + .catch(function(num) { return 'asdf'; }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// rejectedPromise.catch():Promise -> then(U) +Promise.reject(0) + .catch(function(num) { return Promise.resolve('asdf'); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// rejectedPromise.catch():Promise> -> then(U) +Promise.reject(0) + .catch(function(num) { return Promise.resolve(Promise.resolve('asdf')); }) + .then(function(str) { + var a: string = str; + var b: number = str; // Error: string ~> number + }); + +// TODO: resolvedPromise -> catch() -> then():T +Promise.resolve(0) + .catch(function(err) {}) + .then(function(num) { + var a: number = num; + + // TODO + var b: string = num; // Error: string ~> number + }); diff --git a/tests/promises/resolve_global.js b/tests/promises/resolve_global.js new file mode 100644 index 000000000000..d53873b74cca --- /dev/null +++ b/tests/promises/resolve_global.js @@ -0,0 +1,41 @@ +/** + * test Promise name resolution + * @flow + */ + +/** + * 1. introduce shadowing bindings for important names + */ +class Promise {} + +/** + * 2. implicit refs to Promise during desugaring should be unaffected + */ +async function foo(x: boolean) { + if (x) { + return {bar: 'baz'}; + } else { + return null; + } +} + +async function run() { + console.log(await foo(true)); + console.log(await foo(false)); +} + +run(); + +/** + * 3. but explicit name refs from code and annos resolve + * using the usual rules + */ +// error: `Promise` in return expr is the local binding +async function bar() { + return Promise.resolve(0); +} + +// error: return type anno is a ref to the local binding +async function baz(): Promise { + return 0; +} diff --git a/tests/promises/resolve_void.js b/tests/promises/resolve_void.js new file mode 100644 index 000000000000..c98ec554aa54 --- /dev/null +++ b/tests/promises/resolve_void.js @@ -0,0 +1,5 @@ +// @flow + +(Promise.resolve(): Promise); // error + +(Promise.resolve(undefined): Promise); // error diff --git a/tests/pure_component/__snapshots__/jsfmt.spec.js.snap b/tests/pure_component/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..80fcdf839ab9 --- /dev/null +++ b/tests/pure_component/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,16 @@ +exports[`test test.js 1`] = ` +"var React = require('react'); + +class C extends React.PureComponent { + props: { x: number }; +} +(); // error (\`x\` is a required prop) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var React = require("react"); +class C extends React.PureComponent { + props: { x: number }; +} +;// error (\`x\` is a required prop) + +" +`; diff --git a/tests/pure_component/jsfmt.spec.js b/tests/pure_component/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/pure_component/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/pure_component/test.js b/tests/pure_component/test.js new file mode 100644 index 000000000000..ec8e3daed8ed --- /dev/null +++ b/tests/pure_component/test.js @@ -0,0 +1,6 @@ +var React = require('react'); + +class C extends React.PureComponent { + props: { x: number }; +} +(); // error (`x` is a required prop) diff --git a/tests/qualified/__snapshots__/jsfmt.spec.js.snap b/tests/qualified/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..345f03a98111 --- /dev/null +++ b/tests/qualified/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test qualified.js 1`] = ` +"class C { } +var M = { C: C }; + +var x:M.C = 0; + +type foo = {bar: number}; + +declare var of_type_foo: foo; +type bar = typeof of_type_foo.bar; + +var a: bar = 42; +var b: bar = 'asdf'; // Error: string ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C {} +var M = { C: C }; +var x: M.C = 0; +type foo = { bar: number }; +declare var of_type_foo: foo; +type bar = typeof of_type_foo.bar; +var a: bar = 42; +var b: bar = "asdf";// Error: string ~> number + +" +`; diff --git a/tests/qualified/jsfmt.spec.js b/tests/qualified/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/qualified/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/qualified/qualified.js b/tests/qualified/qualified.js new file mode 100644 index 000000000000..f5fc7616799c --- /dev/null +++ b/tests/qualified/qualified.js @@ -0,0 +1,12 @@ +class C { } +var M = { C: C }; + +var x:M.C = 0; + +type foo = {bar: number}; + +declare var of_type_foo: foo; +type bar = typeof of_type_foo.bar; + +var a: bar = 42; +var b: bar = 'asdf'; // Error: string ~> number diff --git a/tests/react/ArityError.react.js b/tests/react/ArityError.react.js new file mode 100644 index 000000000000..531fdc1e980e --- /dev/null +++ b/tests/react/ArityError.react.js @@ -0,0 +1,11 @@ +/** + * @providesModule ArityError.react + */ +var React = require('react'); +var AudienceInsightsContainer = React.createClass({ + renderComponent(AudienceInsights: ReactClass<*>) { + return ; + }, +}); + +module.exports = AudienceInsightsContainer; diff --git a/tests/react/__snapshots__/jsfmt.spec.js.snap b/tests/react/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4f2dc3ec59f8 --- /dev/null +++ b/tests/react/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,395 @@ +exports[`test ArityError.react.js 1`] = ` +"/** + * @providesModule ArityError.react + */ +var React = require(\'react\'); +var AudienceInsightsContainer = React.createClass({ + renderComponent(AudienceInsights: ReactClass<*>) { + return ; + }, +}); + +module.exports = AudienceInsightsContainer; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test createElement_string.js 1`] = ` +"// @flow +import React from \'react\'; + +class Bar extends React.Component {} + +class Foo extends React.Component { + render() { + const Cmp = Math.random() < 0.5 ? \'div\' : Bar; + return (); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import React from \"react\"; +class Bar extends React.Component {} +class Foo extends React.Component { + render() { + const Cmp = (Math.random() < 0.5 ? \"div\" : Bar); + return ; + } +} + +" +`; + +exports[`test createElementRequiredProp_string.js 1`] = ` +"// @flow +import React from \'react\'; + +class Bar extends React.Component { + props: { + test: number, + }; + render() { + return ( +
+ {this.props.test} +
+ ) + } +} + +class Foo extends React.Component { + render() { + const Cmp = Math.random() < 0.5 ? \'div\' : Bar; + return (); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import React from \"react\"; +class Bar extends React.Component { + props: { test: number }; + render() { + return ( +
+ {this.props.test} +
+ ); + } +} +class Foo extends React.Component { + render() { + const Cmp = (Math.random() < 0.5 ? \"div\" : Bar); + return ; + } +} + +" +`; + +exports[`test import_react.js 1`] = ` +"/* @flow */ + +import react from \"react\"; +import {Component} from \"react\"; + +var a: Component<*,*,*> = new react.Component(); +var b: number = new react.Component(); // Error: ReactComponent ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test jsx_spread.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Foo = React.createClass({ + propTypes: { + bar: React.PropTypes.string.isRequired, + }, +}); + +var props = {bar: 42}; +var blah = ; // error bar, number given string expected +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Foo = React.createClass({ + propTypes: { bar: React.PropTypes.string.isRequired } +}); +var props = { bar: 42 }; +var blah = ;// error bar, number given string expected + +" +`; + +exports[`test proptype_arrayOf.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Example = React.createClass({ + propTypes: { + arr: React.PropTypes.arrayOf(React.PropTypes.number).isRequired + }, +}); + +var ok_empty = +var ok_numbers = + +var fail_not_array = +var fail_mistyped_elems = +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Example = React.createClass({ + propTypes: { arr: React.PropTypes.arrayOf(React.PropTypes.number).isRequired } +}); +var ok_empty = ; +var ok_numbers = ; +var fail_not_array = ; +var fail_mistyped_elems = ; + +" +`; + +exports[`test proptype_func.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Example = React.createClass({ + propTypes: { + func: React.PropTypes.func.isRequired + }, +}); + +var ok_void = {}} />; +var ok_args = {}} />; +var ok_retval = 1} /> + +var fail_mistyped = +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Example = React.createClass({ + propTypes: { func: React.PropTypes.func.isRequired } +}); +var ok_void = { + +}}/>; +var ok_args = { + +}}/>; +var ok_retval = 1}/>; +var fail_mistyped = ; + +" +`; + +exports[`test proptype_missing.js 1`] = ` +"/* @flow */ + +/* If you create a react component with createClass() but don\'t specify the + * propTypes, what should the type of props be? + * + * It used to be an empty object, but we didn\'t enforce that correctly, so + * people could do whatever they wanted with this.props. + * + * As of 0.21.0 it started to be an error when people used this.props in a + * strict equality situation. It was weird that this was only sometimes + * enforced, so glevi changed this.props to be Object by default. + * + * We may change this back to the empty object at some point and fix the + * situations where it didn\'t used to error + */ +var React = React.createClass({ + getID(): string { + // So this would have been an error in 0.21.0 if we didn\'t make this.props + // Object + switch (this.props.name) { + case \'a\': return \'Bob\'; + default: return \'Alice\'; + } + }, + + render() { + // But this never errored + return
; + } +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test proptype_object.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Example = React.createClass({ + propTypes: { + object: React.PropTypes.object.isRequired + }, +}); + +var ok_empty = ; +var ok_props = ; + +var fail_mistyped = +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Example = React.createClass({ + propTypes: { object: React.PropTypes.object.isRequired } +}); +var ok_empty = ; +var ok_props = ; +var fail_mistyped = ; + +" +`; + +exports[`test proptype_objectOf.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Example = React.createClass({ + propTypes: { + obj: React.PropTypes.objectOf(React.PropTypes.number).isRequired + }, +}); + +var ok_empty = +var ok_numbers = + +var fail_not_object = +var fail_mistyped_props = +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Example = React.createClass({ + propTypes: { + obj: React.PropTypes.objectOf(React.PropTypes.number).isRequired + } +}); +var ok_empty = ; +var ok_numbers = ; +var fail_not_object = ; +var fail_mistyped_props = ; + +" +`; + +exports[`test proptype_oneOf.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Example = React.createClass({ + propTypes: { + literal: React.PropTypes.oneOf([\"foo\"]).isRequired + }, +}); + +var ex1 = ; +var ex2 = ; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Example = React.createClass({ + propTypes: { literal: React.PropTypes.oneOf([ \"foo\" ]).isRequired } +}); +var ex1 = ; +var ex2 = ; + +" +`; + +exports[`test proptype_oneOfType.js 1`] = ` +"/* @flow */ + +var React = require(\'react\'); +var Example = React.createClass({ + propTypes: { + prop: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number + ]).isRequired + }, + render() { + if (typeof this.props.prop === \"string\") { + return
{this.props.prop}
+ } else { + return
{this.props.prop.toFixed(2)}
+ } + } +}); + +var ok_number = ; +var ok_string = ; + +var fail_bool = +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var React = require(\"react\"); +var Example = React.createClass({ + propTypes: { + prop: React.PropTypes.oneOfType( + [ React.PropTypes.string, React.PropTypes.number ] + ).isRequired + }, + render() { + if (typeof this.props.prop === \"string\") { + return
{this.props.prop}
; + } else { + return
{this.props.prop.toFixed(2)}
; + } + } +}); +var ok_number = ; +var ok_string = ; +var fail_bool = ; + +" +`; diff --git a/tests/react/createElementRequiredProp_string.js b/tests/react/createElementRequiredProp_string.js new file mode 100644 index 000000000000..5793a65c4799 --- /dev/null +++ b/tests/react/createElementRequiredProp_string.js @@ -0,0 +1,22 @@ +// @flow +import React from 'react'; + +class Bar extends React.Component { + props: { + test: number, + }; + render() { + return ( +
+ {this.props.test} +
+ ) + } +} + +class Foo extends React.Component { + render() { + const Cmp = Math.random() < 0.5 ? 'div' : Bar; + return (); + } +} diff --git a/tests/react/createElement_string.js b/tests/react/createElement_string.js new file mode 100644 index 000000000000..b6d548afec6a --- /dev/null +++ b/tests/react/createElement_string.js @@ -0,0 +1,11 @@ +// @flow +import React from 'react'; + +class Bar extends React.Component {} + +class Foo extends React.Component { + render() { + const Cmp = Math.random() < 0.5 ? 'div' : Bar; + return (); + } +} diff --git a/tests/react/import_react.js b/tests/react/import_react.js new file mode 100644 index 000000000000..d608b7c2f16c --- /dev/null +++ b/tests/react/import_react.js @@ -0,0 +1,7 @@ +/* @flow */ + +import react from "react"; +import {Component} from "react"; + +var a: Component<*,*,*> = new react.Component(); +var b: number = new react.Component(); // Error: ReactComponent ~> number diff --git a/tests/react/jsfmt.spec.js b/tests/react/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/react/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/react/jsx_spread.js b/tests/react/jsx_spread.js new file mode 100644 index 000000000000..d5214d7e40e6 --- /dev/null +++ b/tests/react/jsx_spread.js @@ -0,0 +1,11 @@ +/* @flow */ + +var React = require('react'); +var Foo = React.createClass({ + propTypes: { + bar: React.PropTypes.string.isRequired, + }, +}); + +var props = {bar: 42}; +var blah = ; // error bar, number given string expected diff --git a/tests/react/proptype_arrayOf.js b/tests/react/proptype_arrayOf.js new file mode 100644 index 000000000000..f6cd3822821b --- /dev/null +++ b/tests/react/proptype_arrayOf.js @@ -0,0 +1,14 @@ +/* @flow */ + +var React = require('react'); +var Example = React.createClass({ + propTypes: { + arr: React.PropTypes.arrayOf(React.PropTypes.number).isRequired + }, +}); + +var ok_empty = +var ok_numbers = + +var fail_not_array = +var fail_mistyped_elems = diff --git a/tests/react/proptype_func.js b/tests/react/proptype_func.js new file mode 100644 index 000000000000..52f452d63793 --- /dev/null +++ b/tests/react/proptype_func.js @@ -0,0 +1,14 @@ +/* @flow */ + +var React = require('react'); +var Example = React.createClass({ + propTypes: { + func: React.PropTypes.func.isRequired + }, +}); + +var ok_void = {}} />; +var ok_args = {}} />; +var ok_retval = 1} /> + +var fail_mistyped = diff --git a/tests/react/proptype_missing.js b/tests/react/proptype_missing.js new file mode 100644 index 000000000000..29fa980fab45 --- /dev/null +++ b/tests/react/proptype_missing.js @@ -0,0 +1,30 @@ +/* @flow */ + +/* If you create a react component with createClass() but don't specify the + * propTypes, what should the type of props be? + * + * It used to be an empty object, but we didn't enforce that correctly, so + * people could do whatever they wanted with this.props. + * + * As of 0.21.0 it started to be an error when people used this.props in a + * strict equality situation. It was weird that this was only sometimes + * enforced, so glevi changed this.props to be Object by default. + * + * We may change this back to the empty object at some point and fix the + * situations where it didn't used to error + */ +var React = React.createClass({ + getID(): string { + // So this would have been an error in 0.21.0 if we didn't make this.props + // Object + switch (this.props.name) { + case 'a': return 'Bob'; + default: return 'Alice'; + } + }, + + render() { + // But this never errored + return
; + } +}); diff --git a/tests/react/proptype_object.js b/tests/react/proptype_object.js new file mode 100644 index 000000000000..5a4754df6126 --- /dev/null +++ b/tests/react/proptype_object.js @@ -0,0 +1,13 @@ +/* @flow */ + +var React = require('react'); +var Example = React.createClass({ + propTypes: { + object: React.PropTypes.object.isRequired + }, +}); + +var ok_empty = ; +var ok_props = ; + +var fail_mistyped = diff --git a/tests/react/proptype_objectOf.js b/tests/react/proptype_objectOf.js new file mode 100644 index 000000000000..abead5617f30 --- /dev/null +++ b/tests/react/proptype_objectOf.js @@ -0,0 +1,14 @@ +/* @flow */ + +var React = require('react'); +var Example = React.createClass({ + propTypes: { + obj: React.PropTypes.objectOf(React.PropTypes.number).isRequired + }, +}); + +var ok_empty = +var ok_numbers = + +var fail_not_object = +var fail_mistyped_props = diff --git a/tests/react/proptype_oneOf.js b/tests/react/proptype_oneOf.js new file mode 100644 index 000000000000..f7486afb9a16 --- /dev/null +++ b/tests/react/proptype_oneOf.js @@ -0,0 +1,11 @@ +/* @flow */ + +var React = require('react'); +var Example = React.createClass({ + propTypes: { + literal: React.PropTypes.oneOf(["foo"]).isRequired + }, +}); + +var ex1 = ; +var ex2 = ; diff --git a/tests/react/proptype_oneOfType.js b/tests/react/proptype_oneOfType.js new file mode 100644 index 000000000000..3fa66d947cb6 --- /dev/null +++ b/tests/react/proptype_oneOfType.js @@ -0,0 +1,23 @@ +/* @flow */ + +var React = require('react'); +var Example = React.createClass({ + propTypes: { + prop: React.PropTypes.oneOfType([ + React.PropTypes.string, + React.PropTypes.number + ]).isRequired + }, + render() { + if (typeof this.props.prop === "string") { + return
{this.props.prop}
+ } else { + return
{this.props.prop.toFixed(2)}
+ } + } +}); + +var ok_number = ; +var ok_string = ; + +var fail_bool = diff --git a/tests/react_functional/__snapshots__/jsfmt.spec.js.snap b/tests/react_functional/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ff19495104e0 --- /dev/null +++ b/tests/react_functional/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,32 @@ +exports[`test test.js 1`] = ` +"import React from \"react\"; + +function F(props: { foo: string }) {} +; // error: missing \`foo\` +; // error: number ~> string +; // ok + +// props subtyping is property-wise covariant +function G(props: { foo: string|numner }) {} +; // ok + +var Z = 0; +; // error, expected React component +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/react_functional/jsfmt.spec.js b/tests/react_functional/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/react_functional/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/react_functional/test.js b/tests/react_functional/test.js new file mode 100644 index 000000000000..acdec6f9409e --- /dev/null +++ b/tests/react_functional/test.js @@ -0,0 +1,13 @@ +import React from "react"; + +function F(props: { foo: string }) {} +; // error: missing `foo` +; // error: number ~> string +; // ok + +// props subtyping is property-wise covariant +function G(props: { foo: string|numner }) {} +; // ok + +var Z = 0; +; // error, expected React component diff --git a/tests/react_modules/__snapshots__/jsfmt.spec.js.snap b/tests/react_modules/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2fedbc3a5ef0 --- /dev/null +++ b/tests/react_modules/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,241 @@ +exports[`test createclass-callsite.js 1`] = ` +"/* @flow */ +var React = require(\'react\'); +var Hello = require(\'./createclass-module\'); + +var HelloLocal = React.createClass({ + propTypes: { + name: React.PropTypes.string.isRequired, + }, + + render: function(): React.Element<*> { + return
{this.props.name}
; + } +}); + +var Callsite = React.createClass({ + render: function(): React.Element<*> { + return ( +
+ + +
+ ); + } +}); + +module.exports = Callsite; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test createclass-module.js 1`] = ` +"/* @flow */ +var React = require(\'react\'); + +var Hello = React.createClass({ + propTypes: { + name: React.PropTypes.string.isRequired, + }, + + render: function(): React.Element<*> { + return
{this.props.name}
; + } +}); + +module.exports = Hello; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test es6class-proptypes-callsite.js 1`] = ` +"/* @flow */ +import React from \'react\'; +import Hello from \'./es6class-proptypes-module\'; + +class HelloLocal extends React.Component { + defaultProps = {}; + propTypes = { + name: React.PropTypes.string.isRequired, + }; + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +class Callsite extends React.Component { + render(): React.Element<*> { + return ( +
+ + +
+ ); + } +} + +module.exports = Callsite; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1180:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test es6class-proptypes-module.js 1`] = ` +"/* @flow */ +import React from \'react\'; + +class Hello extends React.Component { + defaultProps = {}; + propTypes = { + name: React.PropTypes.string.isRequired, + }; + + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +module.exports = Hello; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1180:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test es6class-types-callsite.js 1`] = ` +"/* @flow */ +import React from \'react\'; +import Hello from \'./es6class-types-module\'; + +type Props = {name: string}; + +class HelloLocal extends React.Component { + props: Props; + + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +class Callsite extends React.Component { + render(): React.Element<*> { + return ( +
+ + +
+ ); + } +} + +module.exports = Callsite; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1180:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test es6class-types-module.js 1`] = ` +"/* @flow */ +import React from \'react\'; + +type Props = {name: string}; + +class Hello extends React.Component<{}, Props, void>{ + props: Props; + static defaultProps: {}; + + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +module.exports = Hello; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1180:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/react_modules/createclass-callsite.js b/tests/react_modules/createclass-callsite.js new file mode 100644 index 000000000000..5a5f3b175953 --- /dev/null +++ b/tests/react_modules/createclass-callsite.js @@ -0,0 +1,26 @@ +/* @flow */ +var React = require('react'); +var Hello = require('./createclass-module'); + +var HelloLocal = React.createClass({ + propTypes: { + name: React.PropTypes.string.isRequired, + }, + + render: function(): React.Element<*> { + return
{this.props.name}
; + } +}); + +var Callsite = React.createClass({ + render: function(): React.Element<*> { + return ( +
+ + +
+ ); + } +}); + +module.exports = Callsite; diff --git a/tests/react_modules/createclass-module.js b/tests/react_modules/createclass-module.js new file mode 100644 index 000000000000..3b7e25cdd5dc --- /dev/null +++ b/tests/react_modules/createclass-module.js @@ -0,0 +1,14 @@ +/* @flow */ +var React = require('react'); + +var Hello = React.createClass({ + propTypes: { + name: React.PropTypes.string.isRequired, + }, + + render: function(): React.Element<*> { + return
{this.props.name}
; + } +}); + +module.exports = Hello; diff --git a/tests/react_modules/es6class-proptypes-callsite.js b/tests/react_modules/es6class-proptypes-callsite.js new file mode 100644 index 000000000000..6a50aa90ee7a --- /dev/null +++ b/tests/react_modules/es6class-proptypes-callsite.js @@ -0,0 +1,26 @@ +/* @flow */ +import React from 'react'; +import Hello from './es6class-proptypes-module'; + +class HelloLocal extends React.Component { + defaultProps = {}; + propTypes = { + name: React.PropTypes.string.isRequired, + }; + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +class Callsite extends React.Component { + render(): React.Element<*> { + return ( +
+ + +
+ ); + } +} + +module.exports = Callsite; diff --git a/tests/react_modules/es6class-proptypes-module.js b/tests/react_modules/es6class-proptypes-module.js new file mode 100644 index 000000000000..86e55da1b28f --- /dev/null +++ b/tests/react_modules/es6class-proptypes-module.js @@ -0,0 +1,15 @@ +/* @flow */ +import React from 'react'; + +class Hello extends React.Component { + defaultProps = {}; + propTypes = { + name: React.PropTypes.string.isRequired, + }; + + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +module.exports = Hello; diff --git a/tests/react_modules/es6class-types-callsite.js b/tests/react_modules/es6class-types-callsite.js new file mode 100644 index 000000000000..c5586b682c17 --- /dev/null +++ b/tests/react_modules/es6class-types-callsite.js @@ -0,0 +1,26 @@ +/* @flow */ +import React from 'react'; +import Hello from './es6class-types-module'; + +type Props = {name: string}; + +class HelloLocal extends React.Component { + props: Props; + + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +class Callsite extends React.Component { + render(): React.Element<*> { + return ( +
+ + +
+ ); + } +} + +module.exports = Callsite; diff --git a/tests/react_modules/es6class-types-module.js b/tests/react_modules/es6class-types-module.js new file mode 100644 index 000000000000..d91eeab83f36 --- /dev/null +++ b/tests/react_modules/es6class-types-module.js @@ -0,0 +1,15 @@ +/* @flow */ +import React from 'react'; + +type Props = {name: string}; + +class Hello extends React.Component<{}, Props, void>{ + props: Props; + static defaultProps: {}; + + render(): React.Element<*> { + return
{this.props.name}
; + } +} + +module.exports = Hello; diff --git a/tests/react_modules/jsfmt.spec.js b/tests/react_modules/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/react_modules/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/rec/__snapshots__/jsfmt.spec.js.snap b/tests/rec/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e319f1c39127 --- /dev/null +++ b/tests/rec/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,226 @@ +exports[`test issue-598.js 1`] = ` +"/* @flow */ + +type F
= { foo(x: A): F } +declare function foo(x: any): F; +({ foo }: F); + +function bar(y: F): F { return y; } +function bar1(y: F): F { return y; } +function bar2(y: F): F { return y; } + +type Functor = { + map(f: (val: A) => B): Functor +} + +function identity(val: A): Functor { + return { + map(f: (_: typeof val) => B): Functor { return identity(f(val)) } + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1228.js 1`] = ` +"/* @flow */ + +type Task + = { chain(next:(input:value) => Task): + Task + } + +function id(x: Task): Task { return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"class P { x: X; } // this is like Promise + +type Pstar = X | Pstar>; // this is like Promise* + +var p: P = new P; +(p.x: string); // error + +var pstar: Pstar = 0; // OK +(pstar: number); // error, but limit potentially unbounded number of errors! + // e.g., P ~/~ number, P> ~/~ number, ... + +pstar = p; // OK +(pstar.x: string); // error + +pstar = (new P: P>); // OK +(pstar.x: string); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"var a = []; // Array ~> a +function bar() { + a = a.concat([]); // terminate despite expanding types: + // a ~> .concat(Array) + // Array ~> .concat(Array) + // Array ~> a + // Array ~> .concat(Array) + // Array ~> a +}; + +class A { + x: A>; +} +var a_ = new A; +function foo0() { + a_ = a_.x; // terminate despite expanding types +} + +type T = { y: S }; +type S = T>; +function foo1(b: S<*>) { + b = b.y; // terminate despite expanding types, OK + // S<*> = { y: S> } + // Both S> and S<*> expand to { y: { y: ... }}. +} + +class D { } +class B extends D { } +class C extends B { } +((new C: C): D) // error: number ~/~ string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test3.js 1`] = ` +"type I = () => I>; +type J = () => J>; + +function foo(x: I): J { + return x; // terminate despite expanding types, OK + // I and J both expand to () => () => ... +} + +type Q = { x: X; } +type P = () => Q>; + +function bar(x: P): () => P { + return x; // terminate despite expanding types, error + // P = () => { x: P } + // () => P = () => () => { x: P } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test4.js 1`] = ` +"type T = T // cycle in type alias should not cause non-termination +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +type T = T;// cycle in type alias should not cause non-termination + +" +`; + +exports[`test test5.js 1`] = ` +"/* @flow */ + +type NestedArray = Array>; + +function flatten(arrArg: NestedArray) { + let arr = arrArg; + while (true) { + arr = Array.prototype.concat.apply([], arr); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/rec/issue-1228.js b/tests/rec/issue-1228.js new file mode 100644 index 000000000000..6eae30ab211c --- /dev/null +++ b/tests/rec/issue-1228.js @@ -0,0 +1,8 @@ +/* @flow */ + +type Task + = { chain(next:(input:value) => Task): + Task + } + +function id(x: Task): Task { return x; } diff --git a/tests/rec/issue-598.js b/tests/rec/issue-598.js new file mode 100644 index 000000000000..b42d9ec635c8 --- /dev/null +++ b/tests/rec/issue-598.js @@ -0,0 +1,19 @@ +/* @flow */ + +type F = { foo(x: A): F } +declare function foo(x: any): F; +({ foo }: F); + +function bar(y: F): F { return y; } +function bar1(y: F): F { return y; } +function bar2(y: F): F { return y; } + +type Functor = { + map(f: (val: A) => B): Functor +} + +function identity(val: A): Functor { + return { + map(f: (_: typeof val) => B): Functor { return identity(f(val)) } + } +} diff --git a/tests/rec/jsfmt.spec.js b/tests/rec/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/rec/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/rec/test.js b/tests/rec/test.js new file mode 100644 index 000000000000..4b224d0ce984 --- /dev/null +++ b/tests/rec/test.js @@ -0,0 +1,16 @@ +class P { x: X; } // this is like Promise + +type Pstar = X | Pstar>; // this is like Promise* + +var p: P = new P; +(p.x: string); // error + +var pstar: Pstar = 0; // OK +(pstar: number); // error, but limit potentially unbounded number of errors! + // e.g., P ~/~ number, P> ~/~ number, ... + +pstar = p; // OK +(pstar.x: string); // error + +pstar = (new P: P>); // OK +(pstar.x: string); // error diff --git a/tests/rec/test2.js b/tests/rec/test2.js new file mode 100644 index 000000000000..f52df80b5415 --- /dev/null +++ b/tests/rec/test2.js @@ -0,0 +1,30 @@ +var a = []; // Array ~> a +function bar() { + a = a.concat([]); // terminate despite expanding types: + // a ~> .concat(Array) + // Array ~> .concat(Array) + // Array ~> a + // Array ~> .concat(Array) + // Array ~> a +}; + +class A { + x: A>; +} +var a_ = new A; +function foo0() { + a_ = a_.x; // terminate despite expanding types +} + +type T = { y: S }; +type S = T>; +function foo1(b: S<*>) { + b = b.y; // terminate despite expanding types, OK + // S<*> = { y: S> } + // Both S> and S<*> expand to { y: { y: ... }}. +} + +class D { } +class B extends D { } +class C extends B { } +((new C: C): D) // error: number ~/~ string diff --git a/tests/rec/test3.js b/tests/rec/test3.js new file mode 100644 index 000000000000..9c2baa21a3b5 --- /dev/null +++ b/tests/rec/test3.js @@ -0,0 +1,16 @@ +type I = () => I>; +type J = () => J>; + +function foo(x: I): J { + return x; // terminate despite expanding types, OK + // I and J both expand to () => () => ... +} + +type Q = { x: X; } +type P = () => Q>; + +function bar(x: P): () => P { + return x; // terminate despite expanding types, error + // P = () => { x: P } + // () => P = () => () => { x: P } +} diff --git a/tests/rec/test4.js b/tests/rec/test4.js new file mode 100644 index 000000000000..7116cd9dbfbc --- /dev/null +++ b/tests/rec/test4.js @@ -0,0 +1 @@ +type T = T // cycle in type alias should not cause non-termination diff --git a/tests/rec/test5.js b/tests/rec/test5.js new file mode 100644 index 000000000000..3052dcead8c2 --- /dev/null +++ b/tests/rec/test5.js @@ -0,0 +1,10 @@ +/* @flow */ + +type NestedArray = Array>; + +function flatten(arrArg: NestedArray) { + let arr = arrArg; + while (true) { + arr = Array.prototype.concat.apply([], arr); + } +} diff --git a/tests/recheck-haste/A1.js b/tests/recheck-haste/A1.js new file mode 100644 index 000000000000..638d95f80d1d --- /dev/null +++ b/tests/recheck-haste/A1.js @@ -0,0 +1,4 @@ +/** + * @providesModule A + * @flow + */ diff --git a/tests/recheck-haste/A3.js b/tests/recheck-haste/A3.js new file mode 100644 index 000000000000..62bd9a77de77 --- /dev/null +++ b/tests/recheck-haste/A3.js @@ -0,0 +1,3 @@ +// @flow + +require('A'); diff --git a/tests/recheck-haste/__snapshots__/jsfmt.spec.js.snap b/tests/recheck-haste/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9bc3b995516a --- /dev/null +++ b/tests/recheck-haste/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,21 @@ +exports[`test A1.js 1`] = ` +"/** + * @providesModule A + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test A3.js 1`] = ` +"// @flow + +require('A'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +require("A"); + +" +`; diff --git a/tests/recheck-haste/jsfmt.spec.js b/tests/recheck-haste/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck-haste/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck-haste/tmp1A/A2.js b/tests/recheck-haste/tmp1A/A2.js new file mode 100644 index 000000000000..cf331fe3deb2 --- /dev/null +++ b/tests/recheck-haste/tmp1A/A2.js @@ -0,0 +1,4 @@ +/** + * @providesModule B + * @flow + */ diff --git a/tests/recheck-haste/tmp1A/__snapshots__/jsfmt.spec.js.snap b/tests/recheck-haste/tmp1A/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b200fabe0f33 --- /dev/null +++ b/tests/recheck-haste/tmp1A/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test A2.js 1`] = ` +"/** + * @providesModule B + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; diff --git a/tests/recheck-haste/tmp1A/jsfmt.spec.js b/tests/recheck-haste/tmp1A/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck-haste/tmp1A/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck-haste/tmp2A/A3.js b/tests/recheck-haste/tmp2A/A3.js new file mode 100644 index 000000000000..c62d55de1472 --- /dev/null +++ b/tests/recheck-haste/tmp2A/A3.js @@ -0,0 +1,3 @@ +// @flow + +require('B'); diff --git a/tests/recheck-haste/tmp2A/__snapshots__/jsfmt.spec.js.snap b/tests/recheck-haste/tmp2A/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9b95ee207fcb --- /dev/null +++ b/tests/recheck-haste/tmp2A/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test A3.js 1`] = ` +"// @flow + +require('B'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +require("B"); + +" +`; diff --git a/tests/recheck-haste/tmp2A/jsfmt.spec.js b/tests/recheck-haste/tmp2A/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck-haste/tmp2A/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ef429d1fc181 --- /dev/null +++ b/tests/recheck/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,352 @@ +exports[`test a1.js 1`] = ` +"// @flow + +function foo(x: number): string { return 5; } + +foo(0); + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function foo(x: number): string { + return 5; +} +foo(0); +module.exports = foo; + +" +`; + +exports[`test a2.js 1`] = ` +"// @flow + +const foo = require(\'./a1\'); + +module.exports = foo(\"\"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +const foo = require(\"./a1\"); +module.exports = foo(\"\"); + +" +`; + +exports[`test a3.js 1`] = ` +"// @flow + +const five = require(\'./a2\'); + +(five + five: string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +const five = require(\"./a2\"); +(five + five: string); + +" +`; + +exports[`test b0.js 1`] = ` +"// @flow + +class C { x: C; } +class E { x: C; } + +module.exports = { C, E }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class C { + x: C; +} +class E { + x: C; +} +module.exports = { C, E }; + +" +`; + +exports[`test b1.js 1`] = ` +"// @flow + +import { C, E } from \"./b0\"; +function foo() { return C; } +function bar() { return E; } +let X = foo(); +class F extends X { } +class D extends F { } +module.exports = { C, D }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { C, E } from \"./b0\"; +function foo() { + return C; +} +function bar() { + return E; +} +let X = foo(); +class F extends X {} +class D extends F {} +module.exports = { C, D }; + +" +`; + +exports[`test b2.js 1`] = ` +"// @flow + +module.exports = require(\"./b1\"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +module.exports = require(\"./b1\"); + +" +`; + +exports[`test b3.js 1`] = ` +"// @flow + +import { C, D } from \"./b2\"; + +(new D: C); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { C, D } from \"./b2\"; +(new D(): C); + +" +`; + +exports[`test c1.js 1`] = ` +"// @flow + +export function foo(props: { x: number }) { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export function foo(props: { x: number }) { + +} + +" +`; + +exports[`test c2.js 1`] = ` +"// @flow + +import { foo } from \"./c1\"; + +export function bar(props: { x: number }) { + foo({ x: 0 }); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { foo } from \"./c1\"; +export function bar(props: { x: number }) { + foo({ x: 0 }); +} + +" +`; + +exports[`test c3.js 1`] = ` +"// @flow + +import { bar } from \"./c2\"; + +bar({ x: 0 }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { bar } from \"./c2\"; +bar({ x: 0 }); + +" +`; + +exports[`test d1.js 1`] = ` +"// @flow + +export class A {} +export class B {} +export var x = new A; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export class A {} +export class B {} +export var x = new A(); + +" +`; + +exports[`test d2.js 1`] = ` +"// @flow + +import {A, x} from \"./d1\"; +export var y: A = x; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { A, x } from \"./d1\"; +export var y: A = x; + +" +`; + +exports[`test e1.js 1`] = ` +"// @flow + +export type Action = + | { type: \'FOO\' } + | { type: \'BAR\' } +; + +export const LIFE = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test e2.js 1`] = ` +"// @flow + +import type { Action } from \'./e1\'; + +const f = (): Action => { + return { type: \'FOO\' }; +} + +import { LIFE } from \'./e1\'; + +(LIFE: 42); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 139, end: 141, loc: [object Object], value: 42, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; + +exports[`test f1.js 1`] = ` +"// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type T = { x: number }; +type S = { x: string }; +declare var a: T; +declare var b: S; +declare var c: T; +module.exports = { a, b, c }; + +" +`; + +exports[`test f2.js 1`] = ` +"// @flow + +var { a, b, c } = require(\'./f1\'); +(c: { x: number }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var { a, b, c } = require(\"./f1\"); +(c: { x: number }); + +" +`; + +exports[`test g1.js 1`] = ` +"// @flow + +export class C { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export class C {} + +" +`; + +exports[`test g2.js 1`] = ` +"// @flow + +import { C } from \'./g1\'; + +class D extends C { } + +module.exports = { D }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { C } from \"./g1\"; +class D extends C {} +module.exports = { D }; + +" +`; + +exports[`test g3.js 1`] = ` +"// @flow + +import { C } from \'./g1\'; +import { D } from \'./g2\'; + +(new D: C) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { C } from \"./g1\"; +import { D } from \"./g2\"; +(new D(): C); + +" +`; + +exports[`test h1.js 1`] = ` +"// @flow + +export type Foo = number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export type Foo = number; + +" +`; + +exports[`test h2.js 1`] = ` +"// @flow + +import type { Foo } from \'./h1\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import type { Foo } from \"./h1\"; + +" +`; diff --git a/tests/recheck/a1.js b/tests/recheck/a1.js new file mode 100644 index 000000000000..2a9c78c41807 --- /dev/null +++ b/tests/recheck/a1.js @@ -0,0 +1,7 @@ +// @flow + +function foo(x: number): string { return 5; } + +foo(0); + +module.exports = foo; diff --git a/tests/recheck/a2.js b/tests/recheck/a2.js new file mode 100644 index 000000000000..cfb5d1cd21db --- /dev/null +++ b/tests/recheck/a2.js @@ -0,0 +1,5 @@ +// @flow + +const foo = require('./a1'); + +module.exports = foo(""); diff --git a/tests/recheck/a3.js b/tests/recheck/a3.js new file mode 100644 index 000000000000..93135f1dfd8b --- /dev/null +++ b/tests/recheck/a3.js @@ -0,0 +1,5 @@ +// @flow + +const five = require('./a2'); + +(five + five: string); diff --git a/tests/recheck/b0.js b/tests/recheck/b0.js new file mode 100644 index 000000000000..a054df3838fb --- /dev/null +++ b/tests/recheck/b0.js @@ -0,0 +1,6 @@ +// @flow + +class C { x: C; } +class E { x: C; } + +module.exports = { C, E }; diff --git a/tests/recheck/b1.js b/tests/recheck/b1.js new file mode 100644 index 000000000000..02d08fc99ae4 --- /dev/null +++ b/tests/recheck/b1.js @@ -0,0 +1,9 @@ +// @flow + +import { C, E } from "./b0"; +function foo() { return C; } +function bar() { return E; } +let X = foo(); +class F extends X { } +class D extends F { } +module.exports = { C, D }; diff --git a/tests/recheck/b2.js b/tests/recheck/b2.js new file mode 100644 index 000000000000..89602457fce4 --- /dev/null +++ b/tests/recheck/b2.js @@ -0,0 +1,3 @@ +// @flow + +module.exports = require("./b1"); diff --git a/tests/recheck/b3.js b/tests/recheck/b3.js new file mode 100644 index 000000000000..948f528d624e --- /dev/null +++ b/tests/recheck/b3.js @@ -0,0 +1,5 @@ +// @flow + +import { C, D } from "./b2"; + +(new D: C); diff --git a/tests/recheck/c1.js b/tests/recheck/c1.js new file mode 100644 index 000000000000..34760f1969f4 --- /dev/null +++ b/tests/recheck/c1.js @@ -0,0 +1,3 @@ +// @flow + +export function foo(props: { x: number }) { } diff --git a/tests/recheck/c2.js b/tests/recheck/c2.js new file mode 100644 index 000000000000..5a7549516cf5 --- /dev/null +++ b/tests/recheck/c2.js @@ -0,0 +1,7 @@ +// @flow + +import { foo } from "./c1"; + +export function bar(props: { x: number }) { + foo({ x: 0 }); +} diff --git a/tests/recheck/c3.js b/tests/recheck/c3.js new file mode 100644 index 000000000000..cf0e94248644 --- /dev/null +++ b/tests/recheck/c3.js @@ -0,0 +1,5 @@ +// @flow + +import { bar } from "./c2"; + +bar({ x: 0 }); diff --git a/tests/recheck/d1.js b/tests/recheck/d1.js new file mode 100644 index 000000000000..b5dd060f3f0f --- /dev/null +++ b/tests/recheck/d1.js @@ -0,0 +1,5 @@ +// @flow + +export class A {} +export class B {} +export var x = new A; diff --git a/tests/recheck/d2.js b/tests/recheck/d2.js new file mode 100644 index 000000000000..7dd91ff07f40 --- /dev/null +++ b/tests/recheck/d2.js @@ -0,0 +1,4 @@ +// @flow + +import {A, x} from "./d1"; +export var y: A = x; diff --git a/tests/recheck/e1.js b/tests/recheck/e1.js new file mode 100644 index 000000000000..d0de69b553ef --- /dev/null +++ b/tests/recheck/e1.js @@ -0,0 +1,8 @@ +// @flow + +export type Action = + | { type: 'FOO' } + | { type: 'BAR' } +; + +export const LIFE = 42; diff --git a/tests/recheck/e2.js b/tests/recheck/e2.js new file mode 100644 index 000000000000..cb730cc55dc1 --- /dev/null +++ b/tests/recheck/e2.js @@ -0,0 +1,11 @@ +// @flow + +import type { Action } from './e1'; + +const f = (): Action => { + return { type: 'FOO' }; +} + +import { LIFE } from './e1'; + +(LIFE: 42); diff --git a/tests/recheck/f1.js b/tests/recheck/f1.js new file mode 100644 index 000000000000..f367b83232d6 --- /dev/null +++ b/tests/recheck/f1.js @@ -0,0 +1,10 @@ +// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c }; diff --git a/tests/recheck/f2.js b/tests/recheck/f2.js new file mode 100644 index 000000000000..33c925aefac5 --- /dev/null +++ b/tests/recheck/f2.js @@ -0,0 +1,4 @@ +// @flow + +var { a, b, c } = require('./f1'); +(c: { x: number }); diff --git a/tests/recheck/g1.js b/tests/recheck/g1.js new file mode 100644 index 000000000000..2db46640d122 --- /dev/null +++ b/tests/recheck/g1.js @@ -0,0 +1,3 @@ +// @flow + +export class C { } diff --git a/tests/recheck/g2.js b/tests/recheck/g2.js new file mode 100644 index 000000000000..5da8b17aff83 --- /dev/null +++ b/tests/recheck/g2.js @@ -0,0 +1,7 @@ +// @flow + +import { C } from './g1'; + +class D extends C { } + +module.exports = { D }; diff --git a/tests/recheck/g3.js b/tests/recheck/g3.js new file mode 100644 index 000000000000..a922c8b50bb3 --- /dev/null +++ b/tests/recheck/g3.js @@ -0,0 +1,6 @@ +// @flow + +import { C } from './g1'; +import { D } from './g2'; + +(new D: C) diff --git a/tests/recheck/h1.js b/tests/recheck/h1.js new file mode 100644 index 000000000000..658225cb3857 --- /dev/null +++ b/tests/recheck/h1.js @@ -0,0 +1,3 @@ +// @flow + +export type Foo = number; diff --git a/tests/recheck/h2.js b/tests/recheck/h2.js new file mode 100644 index 000000000000..27cc789c77ab --- /dev/null +++ b/tests/recheck/h2.js @@ -0,0 +1,3 @@ +// @flow + +import type { Foo } from './h1'; diff --git a/tests/recheck/jsfmt.spec.js b/tests/recheck/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1a/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1a/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..35a87e8c321c --- /dev/null +++ b/tests/recheck/tmp1a/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test a1.js 1`] = ` +"// @flow + +function foo(x: number): number { return 5; } + +foo(0); + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function foo(x: number): number { + return 5; +} +foo(0); +module.exports = foo; + +" +`; diff --git a/tests/recheck/tmp1a/a1.js b/tests/recheck/tmp1a/a1.js new file mode 100644 index 000000000000..6aea0d8312b9 --- /dev/null +++ b/tests/recheck/tmp1a/a1.js @@ -0,0 +1,7 @@ +// @flow + +function foo(x: number): number { return 5; } + +foo(0); + +module.exports = foo; diff --git a/tests/recheck/tmp1a/jsfmt.spec.js b/tests/recheck/tmp1a/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1a/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1b/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1b/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..cd873290ace9 --- /dev/null +++ b/tests/recheck/tmp1b/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test b1.js 1`] = ` +"// @flow + +import { C, E } from "./b0"; +function foo() { return C; } +function bar() { return E; } +let X = bar(); +class F extends X { } +class D extends F { } +module.exports = { C, D }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { C, E } from "./b0"; +function foo() { + return C; +} +function bar() { + return E; +} +let X = bar(); +class F extends X {} +class D extends F {} +module.exports = { C, D }; + +" +`; diff --git a/tests/recheck/tmp1b/b1.js b/tests/recheck/tmp1b/b1.js new file mode 100644 index 000000000000..468f26a53950 --- /dev/null +++ b/tests/recheck/tmp1b/b1.js @@ -0,0 +1,9 @@ +// @flow + +import { C, E } from "./b0"; +function foo() { return C; } +function bar() { return E; } +let X = bar(); +class F extends X { } +class D extends F { } +module.exports = { C, D }; diff --git a/tests/recheck/tmp1b/jsfmt.spec.js b/tests/recheck/tmp1b/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1b/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1c/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1c/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..812fec93444b --- /dev/null +++ b/tests/recheck/tmp1c/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,17 @@ +exports[`test c2.js 1`] = ` +"// @flow + +import { foo } from "./c1"; + +export function bar(props: { y: number }) { + foo({ y: 0 }); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +import { foo } from "./c1"; +export function bar(props: { y: number }) { + foo({ y: 0 }); +} + +" +`; diff --git a/tests/recheck/tmp1c/c2.js b/tests/recheck/tmp1c/c2.js new file mode 100644 index 000000000000..78f854440217 --- /dev/null +++ b/tests/recheck/tmp1c/c2.js @@ -0,0 +1,7 @@ +// @flow + +import { foo } from "./c1"; + +export function bar(props: { y: number }) { + foo({ y: 0 }); +} diff --git a/tests/recheck/tmp1c/jsfmt.spec.js b/tests/recheck/tmp1c/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1c/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1d/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1d/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0bff460b8b4e --- /dev/null +++ b/tests/recheck/tmp1d/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,14 @@ +exports[`test d1.js 1`] = ` +"// @flow + +export class A {} +export class B {} +export var x = new B; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export class A {} +export class B {} +export var x = new B(); + +" +`; diff --git a/tests/recheck/tmp1d/d1.js b/tests/recheck/tmp1d/d1.js new file mode 100644 index 000000000000..bfcfcbdf7f2c --- /dev/null +++ b/tests/recheck/tmp1d/d1.js @@ -0,0 +1,5 @@ +// @flow + +export class A {} +export class B {} +export var x = new B; diff --git a/tests/recheck/tmp1d/jsfmt.spec.js b/tests/recheck/tmp1d/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1d/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1e/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1e/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6aea92cc691b --- /dev/null +++ b/tests/recheck/tmp1e/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,30 @@ +exports[`test e2.js 1`] = ` +"// @flow + +import type { Action } from \'./e1\'; + +const f = (): Action => { + return { type: \'QUX\' }; +} + +import { LIFE } from \'./e1\'; + +(LIFE: 42); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 139, end: 141, loc: [object Object], value: 42, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; diff --git a/tests/recheck/tmp1e/e2.js b/tests/recheck/tmp1e/e2.js new file mode 100644 index 000000000000..337afa6cfe53 --- /dev/null +++ b/tests/recheck/tmp1e/e2.js @@ -0,0 +1,11 @@ +// @flow + +import type { Action } from './e1'; + +const f = (): Action => { + return { type: 'QUX' }; +} + +import { LIFE } from './e1'; + +(LIFE: 42); diff --git a/tests/recheck/tmp1e/jsfmt.spec.js b/tests/recheck/tmp1e/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1e/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1f/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1f/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e93239948127 --- /dev/null +++ b/tests/recheck/tmp1f/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test f1.js 1`] = ` +"// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: S; + +module.exports = { a, b, c }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type T = { x: number }; +type S = { x: string }; +declare var a: T; +declare var b: S; +declare var c: S; +module.exports = { a, b, c }; + +" +`; diff --git a/tests/recheck/tmp1f/f1.js b/tests/recheck/tmp1f/f1.js new file mode 100644 index 000000000000..4fa64d3756fc --- /dev/null +++ b/tests/recheck/tmp1f/f1.js @@ -0,0 +1,10 @@ +// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: S; + +module.exports = { a, b, c }; diff --git a/tests/recheck/tmp1f/jsfmt.spec.js b/tests/recheck/tmp1f/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1f/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1g/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1g/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..124e3714c8f1 --- /dev/null +++ b/tests/recheck/tmp1g/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,12 @@ +exports[`test g1.js 1`] = ` +"// @flow + +export class C { } +export var extra = null; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export class C {} +export var extra = null; + +" +`; diff --git a/tests/recheck/tmp1g/g1.js b/tests/recheck/tmp1g/g1.js new file mode 100644 index 000000000000..bef8fa52cafa --- /dev/null +++ b/tests/recheck/tmp1g/g1.js @@ -0,0 +1,4 @@ +// @flow + +export class C { } +export var extra = null; diff --git a/tests/recheck/tmp1g/jsfmt.spec.js b/tests/recheck/tmp1g/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1g/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp1h/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp1h/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..13d5fbb33b30 --- /dev/null +++ b/tests/recheck/tmp1h/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test h1.js 1`] = ` +"// @flow + +export type Bar = number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export type Bar = number; + +" +`; diff --git a/tests/recheck/tmp1h/h1.js b/tests/recheck/tmp1h/h1.js new file mode 100644 index 000000000000..ef374d6a5c5c --- /dev/null +++ b/tests/recheck/tmp1h/h1.js @@ -0,0 +1,3 @@ +// @flow + +export type Bar = number; diff --git a/tests/recheck/tmp1h/jsfmt.spec.js b/tests/recheck/tmp1h/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp1h/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp2a/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp2a/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..dd2074794bdf --- /dev/null +++ b/tests/recheck/tmp2a/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test a1.js 1`] = ` +"// @flow + +function foo(x: number): number { return 5; } + +foo(""); + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function foo(x: number): number { + return 5; +} +foo(""); +module.exports = foo; + +" +`; diff --git a/tests/recheck/tmp2a/a1.js b/tests/recheck/tmp2a/a1.js new file mode 100644 index 000000000000..16f0c5ce36ca --- /dev/null +++ b/tests/recheck/tmp2a/a1.js @@ -0,0 +1,7 @@ +// @flow + +function foo(x: number): number { return 5; } + +foo(""); + +module.exports = foo; diff --git a/tests/recheck/tmp2a/jsfmt.spec.js b/tests/recheck/tmp2a/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp2a/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp2b/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp2b/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..04d276feff6f --- /dev/null +++ b/tests/recheck/tmp2b/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,19 @@ +exports[`test b0.js 1`] = ` +"// @flow + +class C { x: C; } +class E extends C { x: C; } + +module.exports = { C, E }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +class C { + x: C; +} +class E extends C { + x: C; +} +module.exports = { C, E }; + +" +`; diff --git a/tests/recheck/tmp2b/b0.js b/tests/recheck/tmp2b/b0.js new file mode 100644 index 000000000000..e6b98e33120f --- /dev/null +++ b/tests/recheck/tmp2b/b0.js @@ -0,0 +1,6 @@ +// @flow + +class C { x: C; } +class E extends C { x: C; } + +module.exports = { C, E }; diff --git a/tests/recheck/tmp2b/jsfmt.spec.js b/tests/recheck/tmp2b/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp2b/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp2c/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp2c/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7b20457b536d --- /dev/null +++ b/tests/recheck/tmp2c/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,12 @@ +exports[`test c1.js 1`] = ` +"// @flow + +export function foo(props: { y: number }) { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +export function foo(props: { y: number }) { + +} + +" +`; diff --git a/tests/recheck/tmp2c/c1.js b/tests/recheck/tmp2c/c1.js new file mode 100644 index 000000000000..a2e88ae8f295 --- /dev/null +++ b/tests/recheck/tmp2c/c1.js @@ -0,0 +1,3 @@ +// @flow + +export function foo(props: { y: number }) { } diff --git a/tests/recheck/tmp2c/jsfmt.spec.js b/tests/recheck/tmp2c/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp2c/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp2e/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp2e/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6a9b521d85b6 --- /dev/null +++ b/tests/recheck/tmp2e/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,27 @@ +exports[`test e1.js 1`] = ` +"// @flow + +export type Action = + | { type: \'QUX\' } + | { type: \'BAR\' } +; + +export const LIFE = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/recheck/tmp2e/e1.js b/tests/recheck/tmp2e/e1.js new file mode 100644 index 000000000000..36a4c56b9b24 --- /dev/null +++ b/tests/recheck/tmp2e/e1.js @@ -0,0 +1,8 @@ +// @flow + +export type Action = + | { type: 'QUX' } + | { type: 'BAR' } +; + +export const LIFE = 42; diff --git a/tests/recheck/tmp2e/jsfmt.spec.js b/tests/recheck/tmp2e/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp2e/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp2f/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp2f/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4ae23f4c5660 --- /dev/null +++ b/tests/recheck/tmp2f/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test f1.js 1`] = ` +"// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type T = { x: number }; +type S = { x: string }; +declare var a: T; +declare var b: S; +declare var c: T; +module.exports = { a, b, c }; + +" +`; diff --git a/tests/recheck/tmp2f/f1.js b/tests/recheck/tmp2f/f1.js new file mode 100644 index 000000000000..f367b83232d6 --- /dev/null +++ b/tests/recheck/tmp2f/f1.js @@ -0,0 +1,10 @@ +// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c }; diff --git a/tests/recheck/tmp2f/jsfmt.spec.js b/tests/recheck/tmp2f/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp2f/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp3e/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp3e/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2f2da9b320b2 --- /dev/null +++ b/tests/recheck/tmp3e/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,58 @@ +exports[`test e1.js 1`] = ` +"// @flow + +export type Action = + | { type: \'QUX\' } + | { type: \'BAR\' } +; + +export const LIFE = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test e2.js 1`] = ` +"// @flow + +import type { Action } from \'./e1\'; + +const f = (): Action => { + return { type: \'QUX\' }; +} + +import { LIFE } from \'./e1\'; + +(LIFE: 0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 139, end: 140, loc: [object Object], value: 0, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; diff --git a/tests/recheck/tmp3e/e1.js b/tests/recheck/tmp3e/e1.js new file mode 100644 index 000000000000..244efab277dc --- /dev/null +++ b/tests/recheck/tmp3e/e1.js @@ -0,0 +1,8 @@ +// @flow + +export type Action = + | { type: 'QUX' } + | { type: 'BAR' } +; + +export const LIFE = 0; diff --git a/tests/recheck/tmp3e/e2.js b/tests/recheck/tmp3e/e2.js new file mode 100644 index 000000000000..6a7ca1b4fa5c --- /dev/null +++ b/tests/recheck/tmp3e/e2.js @@ -0,0 +1,11 @@ +// @flow + +import type { Action } from './e1'; + +const f = (): Action => { + return { type: 'QUX' }; +} + +import { LIFE } from './e1'; + +(LIFE: 0); diff --git a/tests/recheck/tmp3e/jsfmt.spec.js b/tests/recheck/tmp3e/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp3e/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp3f/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp3f/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f58b33b71daa --- /dev/null +++ b/tests/recheck/tmp3f/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test f1.js 1`] = ` +"// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c: a }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type T = { x: number }; +type S = { x: string }; +declare var a: T; +declare var b: S; +declare var c: T; +module.exports = { a, b, c: a }; + +" +`; diff --git a/tests/recheck/tmp3f/f1.js b/tests/recheck/tmp3f/f1.js new file mode 100644 index 000000000000..40a98b9b68b8 --- /dev/null +++ b/tests/recheck/tmp3f/f1.js @@ -0,0 +1,10 @@ +// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c: a }; diff --git a/tests/recheck/tmp3f/jsfmt.spec.js b/tests/recheck/tmp3f/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp3f/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/recheck/tmp4f/__snapshots__/jsfmt.spec.js.snap b/tests/recheck/tmp4f/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c9815810a0ee --- /dev/null +++ b/tests/recheck/tmp4f/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,22 @@ +exports[`test f1.js 1`] = ` +"// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c: b }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type T = { x: number }; +type S = { x: string }; +declare var a: T; +declare var b: S; +declare var c: T; +module.exports = { a, b, c: b }; + +" +`; diff --git a/tests/recheck/tmp4f/f1.js b/tests/recheck/tmp4f/f1.js new file mode 100644 index 000000000000..77954a93f28a --- /dev/null +++ b/tests/recheck/tmp4f/f1.js @@ -0,0 +1,10 @@ +// @flow + +type T = { x: number }; +type S = { x: string }; + +declare var a: T; +declare var b: S; +declare var c: T; + +module.exports = { a, b, c: b }; diff --git a/tests/recheck/tmp4f/jsfmt.spec.js b/tests/recheck/tmp4f/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/recheck/tmp4f/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/record/__snapshots__/jsfmt.spec.js.snap b/tests/record/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3e4a86f4d980 --- /dev/null +++ b/tests/record/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,43 @@ +exports[`test test.js 1`] = ` +"type Key1 = \'foo\' | \'bar\'; // make an enum type with known key set +var o1: {[key: Key1]: number} = { + foo: 0, + bar: \"\", // error: string ~/~ number +}; +o1.foo; // OK +o1.qux; // error: qux not found +o1.toString(); // ok + +type R = {foo: any, bar: any}; +type Key2 = $Keys; // another way to make an enum type, with unknown key set +var o2: {[key: Key2]: number} = { foo: 0 }; // OK to leave out bar +o2.bar; // OK to access bar +o2.qux; // error: qux not found + +class C { + x: $Subtype<{[key: $Keys]: any}>; // object with larger key set than X\'s +} +class D extends C<{foo: number, bar: string}> { + x: { foo: number, qux: boolean }; // error: qux not found +} + +type AnyKey = $Keys; +var o3: {[key: AnyKey]: number} = { foo: 0 }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/record/jsfmt.spec.js b/tests/record/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/record/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/record/test.js b/tests/record/test.js new file mode 100644 index 000000000000..b7b1357f13c4 --- /dev/null +++ b/tests/record/test.js @@ -0,0 +1,24 @@ +type Key1 = 'foo' | 'bar'; // make an enum type with known key set +var o1: {[key: Key1]: number} = { + foo: 0, + bar: "", // error: string ~/~ number +}; +o1.foo; // OK +o1.qux; // error: qux not found +o1.toString(); // ok + +type R = {foo: any, bar: any}; +type Key2 = $Keys; // another way to make an enum type, with unknown key set +var o2: {[key: Key2]: number} = { foo: 0 }; // OK to leave out bar +o2.bar; // OK to access bar +o2.qux; // error: qux not found + +class C { + x: $Subtype<{[key: $Keys]: any}>; // object with larger key set than X's +} +class D extends C<{foo: number, bar: string}> { + x: { foo: number, qux: boolean }; // error: qux not found +} + +type AnyKey = $Keys; +var o3: {[key: AnyKey]: number} = { foo: 0 }; diff --git a/tests/refi/__snapshots__/jsfmt.spec.js.snap b/tests/refi/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a9fd427a869d --- /dev/null +++ b/tests/refi/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,1196 @@ +exports[`test bound.js 1`] = ` +"// refinements of bound vars (closed-over locals) +// should have the same lifetimes as heap objects. + +var x : ?string = \"xxx\"; + +var tests = +[ + function() { + var y : string = x; // not ok + }, + + function() { + if (x != null) { + var y : string = x; // ok + } + }, + + function() { + if (x == null) {} else { + var y : string = x; // ok + } + }, + + function() { + if (x == null) + return; + var y : string = x; // ok + }, + + function() { + if (!(x != null)) {} else { + var y : string = x; // ok + } + }, + + /* TODO we actually allow this currently; fix + // requires further remedial work in Env + function() { + if (x != null) { + alert(\"\"); + var y : string = x; // not ok + } + }, + */ + function() { + if (x != null) {} + var y : string = x; // not ok + }, + + function() { + if (x != null) { + } else { + var y : string = x; // not ok + } + }, + + function() { + var y : string = x != null ? x : \"\"; // ok + }, + + function() { + var y : string = x || \"\"; // ok + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// refinements of bound vars (closed-over locals) +// should have the same lifetimes as heap objects. +var x: ?string = \"xxx\"; +var tests = [ + function() { + var y: string = x;// not ok + }, + function() { + if (x != null) { + var y: string = x;// ok + } + }, + function() { + if (x == null) { + + } else { + var y: string = x;// ok + } + }, + function() { + if (x == null) + return; + var y: string = x;// ok + }, + function() { + if (!(x != null)) { + + } else { + var y: string = x;// ok + } + }, + /* TODO we actually allow this currently; fix + // requires further remedial work in Env + function() { + if (x != null) { + alert(\"\"); + var y : string = x; // not ok + } + }, + */ + function() { + if (x != null) { + + } + var y: string = x;// not ok + }, + function() { + if (x != null) { + + } else { + var y: string = x;// not ok + } + }, + function() { + var y: string = (x != null ? x : \"\");// ok + }, + function() { + var y: string = x || \"\";// ok + } +]; + +" +`; + +exports[`test heap.js 1`] = ` +"var tests = +[ + function() { + var x : {p:?string} = {p:\"xxx\"}; + var y : string = x.p; // not ok + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p == null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p == null) + return; + var y : string = x.p; // ok + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (!(x.p != null)) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) { + alert(\"\"); + var y : string = x.p; // not ok + } + }, + + function () { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) { + x.p = null; + var y : string = x.p; // not ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) {} + var y : string = x.p; // not ok + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) { + } else { + var y : string = x.p; // not ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + var y : string = x.p != null ? x.p : \"\"; // ok + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + var y : string = x.p || \"\"; // ok + }, + + function() { + var x : {p:string | string[]} = {p:[\"xxx\"]}; + if (Array.isArray(x.p)) { + var y : string[] = x.p; // ok + } else { + var z : string = x.p; // ok + } + }, + + function() { + var x : {y: ?string} = {y: null}; + if (!x.y) { + x.y = \"foo\"; + } + (x.y: string); + }, + + function() { + var x : {y: ?string} = {y: null}; + if (x.y) { + } else { + x.y = \"foo\"; + } + (x.y: string); + }, + + function() { + var x : {y: ?string} = {y: null}; + if (!x.y) { + x.y = 123; // error + } + (x.y: string); // error, this got widened to a number + }, + + function() { + var x : {y: ?string} = {y: null}; + if (x.y) { + x.y = \"foo\"; + } else { + x.y = \"bar\"; + } + (x.y : string); + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == \"number\") { + x.y = \"foo\"; + } + (x.y : string); // error, could also be boolean + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == \"number\") { + x.y = \"foo\"; + } else if (typeof x.y == \"boolean\") { + x.y = \"bar\"; + } + (x.y : boolean); // error, string + }, + + function() { + var x : {y: ?string} = {y: null}; + if (!x.y) { + x.y = \"foo\"; + } + if (x.y) { + x.y = null; + } + (x.y : string); // error + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == \"number\") { + x.y = \"foo\"; + } + // now x.y can is string | boolean + if (typeof x.y == \"string\") { + x.y = false; + } + // now x.y is only boolean + (x.y : string); // error + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == \"number\") { + x.y = \"foo\"; + } + // now x.y can is string | boolean + if (typeof x.y == \"string\") { + x.y = 123; + } + // now x.y is number | boolean + (x.y : string); // error + }, + + function() { + var x : {y: ?string} = {y: null}; + var z : string = \"foo\"; + if (x.y) { + x.y = z; + } else { + x.y = z; + } + (x.y : string); + }, + + function(x: string) { + if (x === \'a\') {} + (x: \'b\'); // error (but only once, string !~> \'b\'; \'a\' is irrelevant) + }, + + function(x: mixed) { + if (typeof x.bar === \'string\') {} // error, so \`x.bar\` refinement is empty + (x: string & number); + }, + + // --- nested conditionals --- + // after a branch, the current scope may have changed. this causes the + // subsequent assignment to refine the new scope. these tests make sure that + // the scope that gets merged after the if statement is the correct + // post-condition scope, not the one that was saved at the beginning of the + // if statement. + + function() { + let x: { foo: ?string } = { foo: null }; + if (!x.foo) { + if (false) {} + x.foo = \"foo\"; + } + (x.foo: string); + }, + + function() { + let x: { foo: ?string } = { foo: null }; + if (!x.foo) { + while(false) {} + x.foo = \"foo\"; + } + (x.foo: string); + }, + + function() { + let x: { foo: ?string } = { foo: null }; + if (!x.foo) { + for (var i = 0; i < 0; i++) {} + x.foo = \"foo\"; + } + (x.foo: string); + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) { + var {p} = x; // TODO: annot checked against type of x + (p : string); // ok + } + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test lex.js 1`] = ` +"function block_scope(x: string | number) { + { + let x; + x = \"\"; // doesn\'t refine outer x + } + (x : string); // error: number ~> string +} + +function switch_scope(x: string | number) { + switch (x) { + default: + let x; + x = \"\"; // doesn\'t refine outer x + } + (x : string); // error: number ~> string +} + +function try_scope(x: string | number) { + try { + let x; + x = \"\"; // doesn\'t refine outer x + } catch (e) { + x = \"\"; // refinement would only escape if both sides refined + } + (x : string); // error: number ~> string +} + +function try_scope_catch(x: string | number) { + try { + x = \"\"; // refinement would only escape if both sides refined + } catch (e) { + let x; + x = \"\"; // doesn\'t refine outer x + } + (x : string); // error: number ~> string +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test local.js 1`] = ` +"var paths = +[ + function() { + var x : ?string = \"xxx\"; + var y : string = x; // not ok + }, + + function() { + var x : ?string = \"xxx\"; + if (x != null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (x == null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (x == null) + return; + var y : string = x; // ok + }, + + function() { + var x : ?string = \"xxx\"; + if (!(x != null)) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (x != null) { + alert(\"\"); + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (x != null) {} + var y : string = x; // not ok + }, + + function() { + var x : ?string = \"xxx\"; + if (x != null) { + } else { + var y : string = x; // not ok + } + }, + + function() { + var x : ?string = \"xxx\"; + var y : string = x != null ? x : \"\"; // ok + }, + + function() { + var x : ?string = \"xxx\"; + var y : string = x || \"\"; // ok + }, + + function() { + var x : string | string[] = [\"xxx\"]; + if (Array.isArray(x)) { + var y : string[] = x; // ok + } else { + var z : string = x; // ok + } + }, + + function() { + var x : ?string = null; + if (!x) { + x = \"xxx\"; + } + var y : string = x; + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test null_tests.js 1`] = ` +"var null_tests = +[ + // expr != null + function() { + var x : ?string = \"xxx\"; + if (x != null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (null != x) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p != null) { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q != null) { + var y : string = x.p.q; // ok + } + }, + + // expr == null + function() { + var x : ?string = \"xxx\"; + if (x == null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p == null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q == null) {} else { + var y : string = x.p.q; // ok + } + }, + + // expr !== null + function() { + var x : ?string = \"xxx\"; + if (x !== null) { + var y : string | void = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p !== null) { + var y : string | void = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q !== null) { + var y : string | void = x.p.q; // ok + } + }, + + // expr === null + function() { + var x : ?string = \"xxx\"; + if (x === null) {} else { + var y : string | void = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p === null) {} else { + var y : string | void = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q === null) {} else { + var y : string | void = x.p.q; // ok + } + }, +]; + +// this.p op null +class C { + p: ?string; + + ensure0(): string { + if (this.p != null) + return this.p; + else + return \"\"; + } + + ensure1(): string { + if (this.p == null) + return \"\"; + return this.p; + } + + ensure2(): string | void { + if (this.p !== null) + return this.p; + else + return \"\"; + } + + ensure3(): string | void { + if (this.p === null) + return \"\"; + return this.p; + } +} + +// super.p op null +class D extends C { + + ensure100(): string { + if (super.p != null) + return super.p; + else + return \"\"; + } + + ensure101(): string { + if (super.p == null) + return \"\"; + else + return super.p; + } + + ensure103(): string { + if (super.p != null) { + alert(\"\"); + return super.p; // not ok + } + return \"\"; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test switch.js 1`] = ` +"// @flow +function foo(a,b,c) { + switch (c) { + case a.x.y: // OK + case b.x.y: // OK + return; + default: + return; + } +} + +// test refis out of switches that are exhaustive without default case + +function exhaustion1(x): number { + var foo; + switch (x) { + case 0: // falls through + case 1: + foo = 3; + break; + default: + throw new Error(\'Invalid state\'); + } + return foo; // no error +} + +function exhaustion2(x, y): number { + var foo; + switch (x) { + case 0: + if (y) { + break; // leaks uninitialized foo out of switch + } + /** + * TODO this shouldn\'t cause an error, because the path that + * runs it will always go on to assign a number to foo. But + * we\'ll need true isolation in env snapshots to model this. + * Currently tvars are always shared between clones - we\'d + * have to rework envs pretty extensively to avoid it. + * + foo = \"\"; + */ + case 1: + foo = 3; + break; + default: + throw new Error(\'Invalid state\'); + } + return foo; // error, possibly uninitialized +} + +function exhaustion3(x): number { + let foo = null; + switch (x) { + case 0: // falls through + case 1: + foo = 3; + break; + default: + throw new Error(\'Invalid state\'); + } + return foo; // no error +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test typeof_tests.js 1`] = ` +"var null_tests = +[ + // typeof expr == typename + function() { + var x : ?string = \"xxx\"; + if (typeof x == \"string\") { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (\"string\" == typeof x) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (typeof x.p == \"string\") { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (typeof x.p.q == \"string\") { + var y : string = x.p.q; // ok + } + }, + + // typeof expr != typename + function() { + var x : ?string = \"xxx\"; + if (typeof x != \"string\") {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (typeof x.p != \"string\") {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (typeof x.p.q != \"string\") {} else { + var y : string = x.p.q; // ok + } + }, + + // typeof expr === typename + function() { + var x : ?string = \"xxx\"; + if (typeof x === \"string\") { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (typeof x.p === \"string\") { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (typeof x.p.q === \"string\") { + var y : string = x.p.q; // ok + } + }, + + // typeof expr !== typename + function() { + var x : ?string = \"xxx\"; + if (typeof x !== \"string\") {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (typeof x.p !== \"string\") {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (typeof x.p.q !== \"string\") {} else { + var y : string = x.p.q; // ok + } + }, +]; + +// typeof this.p op typename +class A { + p: ?string; + + ensure0(): string { + if (typeof this.p == \"string\") + return this.p; + else + return \"\"; + } + + ensure1(): string { + if (typeof this.p != \"string\") + return \"\"; + else + return this.p; + } + + ensure2(): string | void { + if (typeof this.p === \"string\") + return this.p; + else + return \"\"; + } + + ensure3(): string | void { + if (typeof this.p !== \"string\") + return \"\"; + else + return this.p; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test undef_tests.js 1`] = ` +"var undef_tests = +[ + // NOTE: not (yet?) supporting non-strict eq test for undefined + + // expr !== undefined + function() { + var x : ?string = \"xxx\"; + if (x !== undefined && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (undefined !== x && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p !== undefined && x.p !== null) { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q !== undefined && x.p.q !== null) { + var y : string = x.p.q; // ok + } + }, + + // expr === undefined + function() { + var x : ?string = \"xxx\"; + if (x === undefined || x === null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p === undefined || x.p === null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q === undefined || x.p.q === null) {} else { + var y : string = x.p.q; // ok + } + }, +]; + +// this.p op undefined +class A { + p: ?string; + + ensure0(): string { + if (this.p !== undefined && this.p !== null) + return this.p; + else + return \"\"; + } + + ensure1(): string { + if (this.p === undefined || this.p === null) + return \"\"; + else + return this.p; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var undef_tests = [ + // NOTE: not (yet?) supporting non-strict eq test for undefined + // expr !== undefined + function() { + var x: ?string = \"xxx\"; + if (x !== undefined && x !== null) { + var y: string = x;// ok + } + }, + function() { + var x: ?string = \"xxx\"; + if (undefined !== x && x !== null) { + var y: string = x;// ok + } + }, + function() { + var x: { p: ?string } = { p: \"xxx\" }; + if (x.p !== undefined && x.p !== null) { + var y: string = x.p;// ok + } + }, + function() { + var x: { p: { q: ?string } } = { p: { q: \"xxx\" } }; + if (x.p.q !== undefined && x.p.q !== null) { + var y: string = x.p.q;// ok + } + }, + // expr === undefined + function() { + var x: ?string = \"xxx\"; + if (x === undefined || x === null) { + + } else { + var y: string = x;// ok + } + }, + function() { + var x: { p: ?string } = { p: \"xxx\" }; + if (x.p === undefined || x.p === null) { + + } else { + var y: string = x.p;// ok + } + }, + function() { + var x: { p: { q: ?string } } = { p: { q: \"xxx\" } }; + if (x.p.q === undefined || x.p.q === null) { + + } else { + var y: string = x.p.q;// ok + } + } +]; +// this.p op undefined +class A { + p: ?string; + ensure0(): string { + if (this.p !== undefined && this.p !== null) + return this.p; +else + return \"\"; + } + ensure1(): string { + if (this.p === undefined || this.p === null) + return \"\"; +else + return this.p; + } +} + +" +`; + +exports[`test void_tests.js 1`] = ` +"var void_tests = +[ + // NOTE: not (yet?) supporting non-strict eq test for undefined + + // expr !== void(...) + function() { + var x : ?string = \"xxx\"; + if (x !== void(0) && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = \"xxx\"; + if (void(0) !== x && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p !== void(0) && x.p !== null) { + var y : string | void = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q !== void(0) && x.p.q !== null) { + var y : string = x.p.q; // ok + } + }, + + // expr === void(...) + function() { + var x : ?string = \"xxx\"; + if (x === void(0) || x === null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:\"xxx\"}; + if (x.p === void(0) || x.p === null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:\"xxx\"}}; + if (x.p.q === void(0) || x.p.q === null) {} else { + var y : string = x.p.q; // ok + } + }, +]; + +// this.p op void(...) +class A { + p: ?string; + + ensure0(): string { + if (this.p !== void(0) && this.p !== null) + return this.p; + else + return \"\"; + } + + ensure1(): string { + if (this.p === void(0) || this.p === null) + return \"\"; + else + return this.p; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/refi/bound.js b/tests/refi/bound.js new file mode 100644 index 000000000000..2c8381126568 --- /dev/null +++ b/tests/refi/bound.js @@ -0,0 +1,64 @@ +// refinements of bound vars (closed-over locals) +// should have the same lifetimes as heap objects. + +var x : ?string = "xxx"; + +var tests = +[ + function() { + var y : string = x; // not ok + }, + + function() { + if (x != null) { + var y : string = x; // ok + } + }, + + function() { + if (x == null) {} else { + var y : string = x; // ok + } + }, + + function() { + if (x == null) + return; + var y : string = x; // ok + }, + + function() { + if (!(x != null)) {} else { + var y : string = x; // ok + } + }, + + /* TODO we actually allow this currently; fix + // requires further remedial work in Env + function() { + if (x != null) { + alert(""); + var y : string = x; // not ok + } + }, + */ + function() { + if (x != null) {} + var y : string = x; // not ok + }, + + function() { + if (x != null) { + } else { + var y : string = x; // not ok + } + }, + + function() { + var y : string = x != null ? x : ""; // ok + }, + + function() { + var y : string = x || ""; // ok + }, +]; diff --git a/tests/refi/heap.js b/tests/refi/heap.js new file mode 100644 index 000000000000..16a4c2baaa5c --- /dev/null +++ b/tests/refi/heap.js @@ -0,0 +1,237 @@ +var tests = +[ + function() { + var x : {p:?string} = {p:"xxx"}; + var y : string = x.p; // not ok + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p == null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p == null) + return; + var y : string = x.p; // ok + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (!(x.p != null)) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) { + alert(""); + var y : string = x.p; // not ok + } + }, + + function () { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) { + x.p = null; + var y : string = x.p; // not ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) {} + var y : string = x.p; // not ok + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) { + } else { + var y : string = x.p; // not ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + var y : string = x.p != null ? x.p : ""; // ok + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + var y : string = x.p || ""; // ok + }, + + function() { + var x : {p:string | string[]} = {p:["xxx"]}; + if (Array.isArray(x.p)) { + var y : string[] = x.p; // ok + } else { + var z : string = x.p; // ok + } + }, + + function() { + var x : {y: ?string} = {y: null}; + if (!x.y) { + x.y = "foo"; + } + (x.y: string); + }, + + function() { + var x : {y: ?string} = {y: null}; + if (x.y) { + } else { + x.y = "foo"; + } + (x.y: string); + }, + + function() { + var x : {y: ?string} = {y: null}; + if (!x.y) { + x.y = 123; // error + } + (x.y: string); // error, this got widened to a number + }, + + function() { + var x : {y: ?string} = {y: null}; + if (x.y) { + x.y = "foo"; + } else { + x.y = "bar"; + } + (x.y : string); + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == "number") { + x.y = "foo"; + } + (x.y : string); // error, could also be boolean + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == "number") { + x.y = "foo"; + } else if (typeof x.y == "boolean") { + x.y = "bar"; + } + (x.y : boolean); // error, string + }, + + function() { + var x : {y: ?string} = {y: null}; + if (!x.y) { + x.y = "foo"; + } + if (x.y) { + x.y = null; + } + (x.y : string); // error + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == "number") { + x.y = "foo"; + } + // now x.y can is string | boolean + if (typeof x.y == "string") { + x.y = false; + } + // now x.y is only boolean + (x.y : string); // error + }, + + function() { + var x : {y: string | number | boolean} = {y: false}; + if (typeof x.y == "number") { + x.y = "foo"; + } + // now x.y can is string | boolean + if (typeof x.y == "string") { + x.y = 123; + } + // now x.y is number | boolean + (x.y : string); // error + }, + + function() { + var x : {y: ?string} = {y: null}; + var z : string = "foo"; + if (x.y) { + x.y = z; + } else { + x.y = z; + } + (x.y : string); + }, + + function(x: string) { + if (x === 'a') {} + (x: 'b'); // error (but only once, string !~> 'b'; 'a' is irrelevant) + }, + + function(x: mixed) { + if (typeof x.bar === 'string') {} // error, so `x.bar` refinement is empty + (x: string & number); + }, + + // --- nested conditionals --- + // after a branch, the current scope may have changed. this causes the + // subsequent assignment to refine the new scope. these tests make sure that + // the scope that gets merged after the if statement is the correct + // post-condition scope, not the one that was saved at the beginning of the + // if statement. + + function() { + let x: { foo: ?string } = { foo: null }; + if (!x.foo) { + if (false) {} + x.foo = "foo"; + } + (x.foo: string); + }, + + function() { + let x: { foo: ?string } = { foo: null }; + if (!x.foo) { + while(false) {} + x.foo = "foo"; + } + (x.foo: string); + }, + + function() { + let x: { foo: ?string } = { foo: null }; + if (!x.foo) { + for (var i = 0; i < 0; i++) {} + x.foo = "foo"; + } + (x.foo: string); + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) { + var {p} = x; // TODO: annot checked against type of x + (p : string); // ok + } + }, +]; diff --git a/tests/refi/jsfmt.spec.js b/tests/refi/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/refi/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/refi/lex.js b/tests/refi/lex.js new file mode 100644 index 000000000000..891931b5412f --- /dev/null +++ b/tests/refi/lex.js @@ -0,0 +1,36 @@ +function block_scope(x: string | number) { + { + let x; + x = ""; // doesn't refine outer x + } + (x : string); // error: number ~> string +} + +function switch_scope(x: string | number) { + switch (x) { + default: + let x; + x = ""; // doesn't refine outer x + } + (x : string); // error: number ~> string +} + +function try_scope(x: string | number) { + try { + let x; + x = ""; // doesn't refine outer x + } catch (e) { + x = ""; // refinement would only escape if both sides refined + } + (x : string); // error: number ~> string +} + +function try_scope_catch(x: string | number) { + try { + x = ""; // refinement would only escape if both sides refined + } catch (e) { + let x; + x = ""; // doesn't refine outer x + } + (x : string); // error: number ~> string +} diff --git a/tests/refi/local.js b/tests/refi/local.js new file mode 100644 index 000000000000..372cdfa0d657 --- /dev/null +++ b/tests/refi/local.js @@ -0,0 +1,84 @@ +var paths = +[ + function() { + var x : ?string = "xxx"; + var y : string = x; // not ok + }, + + function() { + var x : ?string = "xxx"; + if (x != null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (x == null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (x == null) + return; + var y : string = x; // ok + }, + + function() { + var x : ?string = "xxx"; + if (!(x != null)) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (x != null) { + alert(""); + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (x != null) {} + var y : string = x; // not ok + }, + + function() { + var x : ?string = "xxx"; + if (x != null) { + } else { + var y : string = x; // not ok + } + }, + + function() { + var x : ?string = "xxx"; + var y : string = x != null ? x : ""; // ok + }, + + function() { + var x : ?string = "xxx"; + var y : string = x || ""; // ok + }, + + function() { + var x : string | string[] = ["xxx"]; + if (Array.isArray(x)) { + var y : string[] = x; // ok + } else { + var z : string = x; // ok + } + }, + + function() { + var x : ?string = null; + if (!x) { + x = "xxx"; + } + var y : string = x; + }, +]; diff --git a/tests/refi/null_tests.js b/tests/refi/null_tests.js new file mode 100644 index 000000000000..f7c6ad7c111f --- /dev/null +++ b/tests/refi/null_tests.js @@ -0,0 +1,154 @@ +var null_tests = +[ + // expr != null + function() { + var x : ?string = "xxx"; + if (x != null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (null != x) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p != null) { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q != null) { + var y : string = x.p.q; // ok + } + }, + + // expr == null + function() { + var x : ?string = "xxx"; + if (x == null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p == null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q == null) {} else { + var y : string = x.p.q; // ok + } + }, + + // expr !== null + function() { + var x : ?string = "xxx"; + if (x !== null) { + var y : string | void = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p !== null) { + var y : string | void = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q !== null) { + var y : string | void = x.p.q; // ok + } + }, + + // expr === null + function() { + var x : ?string = "xxx"; + if (x === null) {} else { + var y : string | void = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p === null) {} else { + var y : string | void = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q === null) {} else { + var y : string | void = x.p.q; // ok + } + }, +]; + +// this.p op null +class C { + p: ?string; + + ensure0(): string { + if (this.p != null) + return this.p; + else + return ""; + } + + ensure1(): string { + if (this.p == null) + return ""; + return this.p; + } + + ensure2(): string | void { + if (this.p !== null) + return this.p; + else + return ""; + } + + ensure3(): string | void { + if (this.p === null) + return ""; + return this.p; + } +} + +// super.p op null +class D extends C { + + ensure100(): string { + if (super.p != null) + return super.p; + else + return ""; + } + + ensure101(): string { + if (super.p == null) + return ""; + else + return super.p; + } + + ensure103(): string { + if (super.p != null) { + alert(""); + return super.p; // not ok + } + return ""; + } +} diff --git a/tests/refi/switch.js b/tests/refi/switch.js new file mode 100644 index 000000000000..f1100fe2cfc8 --- /dev/null +++ b/tests/refi/switch.js @@ -0,0 +1,63 @@ +// @flow +function foo(a,b,c) { + switch (c) { + case a.x.y: // OK + case b.x.y: // OK + return; + default: + return; + } +} + +// test refis out of switches that are exhaustive without default case + +function exhaustion1(x): number { + var foo; + switch (x) { + case 0: // falls through + case 1: + foo = 3; + break; + default: + throw new Error('Invalid state'); + } + return foo; // no error +} + +function exhaustion2(x, y): number { + var foo; + switch (x) { + case 0: + if (y) { + break; // leaks uninitialized foo out of switch + } + /** + * TODO this shouldn't cause an error, because the path that + * runs it will always go on to assign a number to foo. But + * we'll need true isolation in env snapshots to model this. + * Currently tvars are always shared between clones - we'd + * have to rework envs pretty extensively to avoid it. + * + foo = ""; + */ + case 1: + foo = 3; + break; + default: + throw new Error('Invalid state'); + } + return foo; // error, possibly uninitialized +} + +function exhaustion3(x): number { + let foo = null; + switch (x) { + case 0: // falls through + case 1: + foo = 3; + break; + default: + throw new Error('Invalid state'); + } + return foo; // no error +} diff --git a/tests/refi/typeof_tests.js b/tests/refi/typeof_tests.js new file mode 100644 index 000000000000..7eefa8b5c274 --- /dev/null +++ b/tests/refi/typeof_tests.js @@ -0,0 +1,130 @@ +var null_tests = +[ + // typeof expr == typename + function() { + var x : ?string = "xxx"; + if (typeof x == "string") { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if ("string" == typeof x) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (typeof x.p == "string") { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (typeof x.p.q == "string") { + var y : string = x.p.q; // ok + } + }, + + // typeof expr != typename + function() { + var x : ?string = "xxx"; + if (typeof x != "string") {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (typeof x.p != "string") {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (typeof x.p.q != "string") {} else { + var y : string = x.p.q; // ok + } + }, + + // typeof expr === typename + function() { + var x : ?string = "xxx"; + if (typeof x === "string") { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (typeof x.p === "string") { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (typeof x.p.q === "string") { + var y : string = x.p.q; // ok + } + }, + + // typeof expr !== typename + function() { + var x : ?string = "xxx"; + if (typeof x !== "string") {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (typeof x.p !== "string") {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (typeof x.p.q !== "string") {} else { + var y : string = x.p.q; // ok + } + }, +]; + +// typeof this.p op typename +class A { + p: ?string; + + ensure0(): string { + if (typeof this.p == "string") + return this.p; + else + return ""; + } + + ensure1(): string { + if (typeof this.p != "string") + return ""; + else + return this.p; + } + + ensure2(): string | void { + if (typeof this.p === "string") + return this.p; + else + return ""; + } + + ensure3(): string | void { + if (typeof this.p !== "string") + return ""; + else + return this.p; + } +} diff --git a/tests/refi/undef_tests.js b/tests/refi/undef_tests.js new file mode 100644 index 000000000000..c23dfeaa101a --- /dev/null +++ b/tests/refi/undef_tests.js @@ -0,0 +1,74 @@ +var undef_tests = +[ + // NOTE: not (yet?) supporting non-strict eq test for undefined + + // expr !== undefined + function() { + var x : ?string = "xxx"; + if (x !== undefined && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (undefined !== x && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p !== undefined && x.p !== null) { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q !== undefined && x.p.q !== null) { + var y : string = x.p.q; // ok + } + }, + + // expr === undefined + function() { + var x : ?string = "xxx"; + if (x === undefined || x === null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p === undefined || x.p === null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q === undefined || x.p.q === null) {} else { + var y : string = x.p.q; // ok + } + }, +]; + +// this.p op undefined +class A { + p: ?string; + + ensure0(): string { + if (this.p !== undefined && this.p !== null) + return this.p; + else + return ""; + } + + ensure1(): string { + if (this.p === undefined || this.p === null) + return ""; + else + return this.p; + } +} diff --git a/tests/refi/void_tests.js b/tests/refi/void_tests.js new file mode 100644 index 000000000000..f74e7bcc8260 --- /dev/null +++ b/tests/refi/void_tests.js @@ -0,0 +1,74 @@ +var void_tests = +[ + // NOTE: not (yet?) supporting non-strict eq test for undefined + + // expr !== void(...) + function() { + var x : ?string = "xxx"; + if (x !== void(0) && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : ?string = "xxx"; + if (void(0) !== x && x !== null) { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p !== void(0) && x.p !== null) { + var y : string | void = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q !== void(0) && x.p.q !== null) { + var y : string = x.p.q; // ok + } + }, + + // expr === void(...) + function() { + var x : ?string = "xxx"; + if (x === void(0) || x === null) {} else { + var y : string = x; // ok + } + }, + + function() { + var x : {p:?string} = {p:"xxx"}; + if (x.p === void(0) || x.p === null) {} else { + var y : string = x.p; // ok + } + }, + + function() { + var x : {p:{q:?string}} = {p:{q:"xxx"}}; + if (x.p.q === void(0) || x.p.q === null) {} else { + var y : string = x.p.q; // ok + } + }, +]; + +// this.p op void(...) +class A { + p: ?string; + + ensure0(): string { + if (this.p !== void(0) && this.p !== null) + return this.p; + else + return ""; + } + + ensure1(): string { + if (this.p === void(0) || this.p === null) + return ""; + else + return this.p; + } +} diff --git a/tests/refinements/__snapshots__/jsfmt.spec.js.snap b/tests/refinements/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3cb42ac081d0 --- /dev/null +++ b/tests/refinements/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,2290 @@ +exports[`test assignment.js 1`] = ` +"/* @flow */ + +function foo(x : ?number) { + var y; + if (y = x) { + var z = y * 1000; + } +} + +type Bar = { + parent: ?Bar; + doStuff: () => void +} + +function bar0(x : Bar) { + while (x = x.parent) { // can\'t assign x to ?Bar + x.doStuff(); + } +} + +function bar1(x : ?Bar) { + while (x = x.parent) { // x.parent might be null + x.doStuff(); + } +} + +function bar2(x : Bar) { + var y = x; + while (y = y.parent) { + y.doStuff(); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test ast_node.js 1`] = ` +"type Node1 = { + kind: \'Node1\', + prop1?: string +}; + +type Node2 = { + kind: \'Node2\', + prop2?: string +} + +export type ASTNode = Node1 | Node2; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test bool.js 1`] = ` +"/* @flow */ + +function foo(x: ?bool) { + if (x === false) { + return; + } + + if (x === true) { + return; + } + + x[0]; // error on null and undefined +} + +function bar(x: ?bool) { + if (x !== true) { + if (x !== false) { + x[0]; // error on null and undefined + } + } +} + +function baz(x: ?bool) { + if (100 * false) { + return; + } + if (false * 100) { + return; + } +} + +let tests = [ + function(x: { done: true, result: string } | { done: false }) { + if (x.done === true) { + return x.result; + } + return x.result; // error + }, + + function(x: { done: true, result: string } | { done: false }) { + if (true === x.done) { + return x.result; + } + return x.result; // error + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test computed_string_literal.js 1`] = ` +"// @flow + +type A = { + \'b_c\': ?string +}; + +function stuff(str: string) {} + +function testProperty(a: A) { + if (a.b_c) { + stuff(a.b_c) + } +} + +function testLiteralProperty(a: A) { + if (a[\'b_c\']) { + stuff(a[\'b_c\']) + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type A = { \"b_c\": ?string }; +function stuff(str: string) { + +} +function testProperty(a: A) { + if (a.b_c) { + stuff(a.b_c); + } +} +function testLiteralProperty(a: A) { + if (a[\"b_c\"]) { + stuff(a[\"b_c\"]); + } +} + +" +`; + +exports[`test cond_prop.js 1`] = ` +"/* @flow */ + +type Type = Name | ListType | NonNullType; +type Name = {kind: \'Name\', value: string, type: void }; +type ListType = {kind: \'ListType\', type: Type}; +type NonNullType = {kind: \'NonNullType\', type: Name | ListType | BadType}; +type BadType = {}; + +function getTypeASTName(typeAST: Type): string { + if (!typeAST.type) throw new Error(\'Must be wrapping type\'); // OK + return getTypeASTName(typeAST.type); // error, BadType not a subtype of Type +} + +let tests = [ + function(x: { done: true, result: string } | { done: false }) { + if (x.done) { + return x.result; + } + return x.result; // error + }, + + function(x: { done: true, result: string } | { foo: string }) { + if (x.done) { + return x.result; // error, consider { foo: \"herp\", done: \"derp\" } + } + return x.result; // error + }, + + function() { + type T + = { foo: Object, bar: string } + | { baz: string, quux: string } + + function testAlwaysTruthyProp(t: T) { + if (t.foo) { + (t.bar: string); // error, consider { baz: \"x\", quux: \"y\", foo: \"boom\" } + } else { + (t.quux: string); // ok. since foo is an object (always truthy), the + // else case completely rules out the first branch of + // the union. + } + } + + function testSometimesTruthyProp(t: T) { + if (t.bar) { + (t.foo: Object); // error, consider { baz: \"x\", quux: \"y\", bar: \"boom\" } + } else { + (t.quux: string); // error, consider { foo: {}, bar: \"\" } + } + } + }, +] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test constants.js 1`] = ` +"/* @flow */ + +export const SUCCESS: \'SUCCESS\' = \'SUCCESS\'; +export const ERROR: \'ERROR\' = \'ERROR\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +export const SUCCESS: \"SUCCESS\" = \"SUCCESS\"; +export const ERROR: \"ERROR\" = \"ERROR\"; + +" +`; + +exports[`test eq.js 1`] = ` +"/* @flow */ + +let tests = [ + function(x: string, y: number) { + if (x == y) {} // error, string & number are not comparable (unsafe casting) + if (x === y) {} // no error, to match \`let z = (x === y)\` which is allowed + }, + + function(x: string) { + if (x == undefined) {} // ok + if (x == void 0) {} // ok + }, + + function(x: string) { + if (x == null) {} // ok + }, + + function(x: { y: \'foo\' } | { y: \'bar\' }) { + if (x.y == 123) {} // error + if (x.y === 123) {} // ok + }, +] +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test exists.js 1`] = ` +"declare class Foo { + foo: string; +} + +function foo0(x: ?string): string { + return x && x || \"\"; +} + +function foo1(x: ?Foo): string { + return x && x.foo || \"\"; +} + +function foo2(x: ?Class): string { + return x && new x().foo || \"\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test func_call.js 1`] = ` +"// @flow + +let tests = [ + function(x: { y?: string }, z: () => string) { + if (x.y) { + // make sure we visit the AST in the correct order. if we visit z() before + // x.y, then the function call will invalidate the refinement of x.y + // incorrectly. + x.y.indexOf(z()); // no error + } + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test hasOwnProperty.js 1`] = ` +"/* @flow */ + +function foo(x:{y?:() => void}) { + x.y(); // error: could be undefined + if (x.hasOwnProperty(\'y\')) { + x.y(); // error: still could be undefined + } + if (x.hasOwnProperty(\'z\')) { + x.z(); // error: unreachable, but we don\'t help you here + } +} + +function bar(x:Object) { + x.y(); // treated as \`any\`, so allowed + if (x.hasOwnProperty(\'y\')) { + x.y(); // still treated as \`any\`, so allowed + } + if (x.hasOwnProperty(\'z\')) { + x.z(); // also treated as \`any\`, so allowed + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test heap_defassign.js 1`] = ` +"// @flow + +type Obj = { p: number | string } + +function f () {} + +function def_assign_function_havoc(obj: Obj) { + obj.p = 10; // (obj.p : number) + f(); // clears refi + var x: number = obj.p; // error, obj.p : number | string +} + +function def_assign_setprop_havoc(obj: Obj, obj2: Obj) { + obj.p = 10; // (obj.p : number) + obj2.p = \'hey\'; // clears refi + var x: number = obj.p; // error, obj.p : number | string +} + +function def_assign_index_havoc(obj: Obj, obj2: Obj) { + obj.p = 10; // (obj.p : number) + obj2[\'p\'] = \'hey\'; // clears refi + var x: number = obj.p; // error, obj.p : number | string +} + +function def_assign_within_if(b: boolean, obj: Obj) { + if (b) { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } + var y: number = obj.p; // error, obj.p : number | string +} + +function def_assign_within_while(b: boolean, obj: Obj) { + while (b) { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } + var y: number = obj.p; // error, obj.p : number | string +} + +function def_assign_within_do(b: boolean, obj: Obj) { + do { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } while (b); + var y: number = obj.p; // no error, loop runs at least once +} + +function def_assign_within_try(b: boolean, obj: Obj) { + obj.p = 10; // (obj.p : number) + try { + f(); // clears refi and might throw + obj.p = \'hey\'; + } catch (e) { + f(); // clears refi and might throw + obj.p = \'hey\'; + } finally { + // NOTE: the values understood to flow to obj.p at this point + // include the number 42 written downstream; + // so if we did y:string, we would get at least a spurious error + // (among other reasonable errors caused by values written upstream) + var y: number = obj.p; // error, string ~/~ number + obj.p = 42; + } + var z:string = obj.p; // error, number ~/~ string +} + +function def_assign_within_for(b: boolean, obj: Obj) { + for (; b; ) { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } + var z: number = obj.p; // error, (number | string) ~/~ number +} + +// --- name-sensitive havoc --- + +type Obj2 = { q: number | string } + +function def_assign_setprop_nohavoc(obj: Obj, obj2: Obj2) { + obj.p = 10; // (obj.p : number) + obj2.q = \'hey\'; // doesn\'t clear refi of .p + var x: number = obj.p; // still ok +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test lib.js 1`] = ` +"/* @flow */ + +declare var BAZ: {stuff?: (x: number) => void} | void; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test missing-property-cond.js 1`] = ` +"// @flow + +function foo1(o: { x: number }) { + if (o.p1) { // OK, this is an idiomatic way of testing property existence + o.x; + } +} + +function foo2(o: { x: number }) { + if (o.p2) { // OK + o.p2.x; // error, since o.p2\'s type is unknown (e.g., could be \`number\`) + } +} + +function foo3(o: { x: number }) { + o.p3.x; // usual error outside conditional +} + +function foo4(o: $Exact<{ x: number }>) { + if (o.p4) { // OK + o.p4.x; // currently OK, should be unreachable + } else { + o.p4.x; // error + } +} + +function foo5() { + const o = { }; + _foo5(); + if (o.p) { o.p(); } + function _foo5() { + o.p = function() { } + } +} + +function foo6(o: mixed) { + if (o.bar) {} // error, any lookup on mixed is unsafe +} + +function foo7(o: mixed) { + if (typeof o.bar === \'string\') {} // error + if (o && typeof o.bar === \'string\') {} // ok + if (o != null && typeof o.bar === \'string\') {} // ok + if (o !== null && o !== undefined && typeof o.bar === \'string\') {} // ok +} + +function foo8(o: { p: mixed }) { + if (o.p && o.p.q) {} // this is ok because o.p is truthy, so o.p.q is safe + if (o.p && o.p.q && o.p.q.r) {} +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test mixed.js 1`] = ` +"/* @flow */ + +function takesNumber(x: number) {} +function takesString(x: string) {} + +function num(x: mixed) { + if (typeof x === \"number\") { + takesString(x); // error + (!x: false); // error: we don\'t know the truthiness of x + } + if (typeof x === \"number\" && x) { + (!x: false); // ok + } + if (x && typeof x === \"number\") { + (!x: false); // ok + } +} + +function str(x: mixed) { + if (typeof x === \"string\") { + takesNumber(x); // error + (!x: false); // error: we don\'t know the truthiness of x + } + if (typeof x === \"string\" && x) { + (!x: false); // ok + } + if (x && typeof x === \"string\") { + (!x: false); // ok + } +} + +function bool(x: mixed) { + if (typeof x === \"boolean\") { + takesString(x); // error + (x: true); // error: we don\'t know the truthiness of x + } + if (typeof x === \"boolean\" && x) { + (x: true); // ok + } + if (x && typeof x === \"boolean\") { + (x: true); // ok + } +} + +function fun(x: mixed) { + if (typeof x === \"function\") { + takesString(x); // error + } +} + +function obj0(x: mixed) { + if (typeof x === \"object\") { + takesString(x); // error + } +} + +function obj1(x: mixed) { + if (Array.isArray(x)) { + takesString(x); // error + } +} + +function undef(x: mixed) { + if (typeof x === \"undefined\") { + takesString(x); // error + } +} + +function null_(x: mixed) { + if (x === null) { + takesString(x); // error + } +} + +function maybe(x: mixed) { + if (x == null) { + takesString(x); // error + } +} + +function true_(x: mixed) { + if (x === true) { + takesString(x); // error + } +} + +function false_(x: mixed) { + if (x === false) { + takesString(x); // error + } +} + +function obj2(x: mixed) { + if (typeof x === \"object\") { + (x: { [key: string]: mixed } | null); + if (x !== null) { + (x[\'foo\']: string); // error, mixed + } + } +} + +function obj2(x: mixed) { + if (typeof x === \"object\" && x) { + (x: Object); + } + if (x && typeof x === \"object\") { + (x: Object); + } + if (x != null && typeof x === \"object\") { + (x: Object); + } + if (x !== null && typeof x === \"object\") { + (x: Object); + } +} + +function arr0(x: mixed) { + if (Array.isArray(x)) { + takesString(x[0]); // error + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test node1.js 1`] = ` +"module.exports = \'Node1\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +module.exports = \"Node1\"; + +" +`; + +exports[`test not.js 1`] = ` +"/* @flow */ + +function foo(x: ?bool) { + if (!x) { + x++; // should error for null, void and bool (false) + } +} + +function bar(x: ?number) { + if (!x) { + x[0]; // should error for null, void and number (0) + } +} + +function baz (x: ?number) { + if (x === null || x === undefined) { + return; + } + + if (!x) { + x[0]; // should error for number (0) + } +} + +class TestClass {} + +let tests = [ + function() { + var y = true; + while (y) { + y = !y; + } + }, + function(x: Function) { + (!x: false); // ok, functions are always truthy + }, + function(x: Object) { + (!x: false); // ok, objects are always truthy + }, + function(x: string) { + (!x: false); // error, strings are not always truthy + }, + function(x: number) { + (!x: false); // error, numbers are not always truthy + }, + function(x: boolean) { + (!x: false); // error, bools are not always truthy + }, + function(x: TestClass) { + (!x: false); // ok, classes are always truthy + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo(x: ?boolean) { + if (!x) { + x++;// should error for null, void and bool (false) + } +} +function bar(x: ?number) { + if (!x) { + x[0];// should error for null, void and number (0) + } +} +function baz(x: ?number) { + if (x === null || x === undefined) { + return; + } + if (!x) { + x[0];// should error for number (0) + } +} +class TestClass {} +let tests = [ + function() { + var y = true; + while (y) { + y = !y; + } + }, + function(x: Function) { + (!x: false);// ok, functions are always truthy + }, + function(x: Object) { + (!x: false);// ok, objects are always truthy + }, + function(x: string) { + (!x: false);// error, strings are not always truthy + }, + function(x: number) { + (!x: false);// error, numbers are not always truthy + }, + function(x: boolean) { + (!x: false);// error, bools are not always truthy + }, + function(x: TestClass) { + (!x: false);// ok, classes are always truthy + } +]; + +" +`; + +exports[`test null.js 1`] = ` +"/* @flow */ + +function null_bogus_comparison() { + if (100 * null) { + return; + } + if (null * 100) { + return; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function null_bogus_comparison() { + if (100 * null) { + return; + } + if (null * 100) { + return; + } +} + +" +`; + +exports[`test number.js 1`] = ` +"// @flow + +type Mode = 0 | 1 | 2; + +let tests = [ + function(x: number) { + if (x === 0) { + (x: void); // error + } + (x: 0); // error + }, + + function(x: number) { + if (x !== 0) { + (x: 0); // error + } + (x: void); // error + }, + + function(x: 1): 0 { + if (x === 0) { + return x; // unreachable, no error + } + return 0; + }, + + function(x: 0): number { + if (x === 1) { + return x; + } + return x; + }, + + function(x: 0) { + if (x !== 1) { + (x: 0); + } + (x: 0); + }, + + function(x: 0): number { + if (x === 0) { + return x; + } + return x; + }, + + function(x: 0 | 1) { + if (x === 0) { + (x: 0); + (x: void); // error + } + if (x === 1) { + (x: 1); + (x: void); // error + } + }, + + function(x: { foo: number }): 0 { + if (x.foo === 0) { + return x.foo; + } + return x.foo; // error + }, + + function( + x: { kind: 0, foo: number } | { kind: 1, bar: number } + ): number { + if (x.kind === 0) { + return x.foo; + } else { + return x.bar; + } + }, + + function(num: number, obj: { foo: number }) { + if (num === obj.bar) { // ok, typos allowed in conditionals + } + }, + + function(num: number, obj: {[key: string]: number}) { + if (num === obj.bar) { // ok + } + }, + + function(n: number): Mode { + if (n !== 0 && n !== 1 && n !== 2) { + throw new Error(\"Wrong number passed\"); + } + return n; + }, + + function(s: number): ?Mode { + if (s === 0) { + return s; + } else if (s === 3) { + return s; // error + } + }, + + function(mode: Mode) { + switch (mode) { + case 0: + (mode: 0); + break; + + case 1: + case 2: + (mode: 1 | 2); + break; + } + }, + + function(x: number): 0 { + if (x) { + return x; // error + } else { + return x; // no error, inferred to be 0 + } + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 22, end: 23, loc: [object Object], value: 0, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; + +exports[`test property.js 1`] = ` +"/* @flow */ + +function a(x: {[key: string]: ?string}, y: string): string { + if (x[y]) { + return x[y]; + } + return \"\"; +} + +function b(x: {y: {[key: string]: ?string}}, z: string): string { + if (x.y[z]) { + return x.y[z]; + } + return \"\"; +} + +function c(x: {[key: string]: ?string}, y: {z: string}): string { + if (x[y.z]) { + return x[y.z]; + } + return \"\"; +} + +function d(x: {y: {[key: string]: ?string}}, a: {b: string}): string { + if (x.y[a.b]) { + return x.y[a.b]; + } + return \"\"; +} + +function a_array(x: Array, y: number): string { + if (x[y]) { + return x[y]; + } + return \"\"; +} + +function b_array(x: {y: Array}, z: number): string { + if (x.y[z]) { + return x.y[z]; + } + return \"\"; +} + +function c_array(x: Array, y: {z: number}): string { + if (x[y.z]) { + return x[y.z]; + } + return \"\"; +} + +function d_array(x: {y: Array}, a: {b: number}): string { + if (x.y[a.b]) { + return x.y[a.b]; + } + return \"\"; +} + +function e_array(x: Array): string { + if (x[0]) { + return x[0]; + } + return \"\"; +} + +// --- name-sensitive havoc --- + +function c2(x: {[key: string]: ?string}, y: {z: string}): string { + if (x[y.z]) { + y.z = \"HEY\"; + return x[y.z]; // error + } + return \"\"; +} + +function c3(x: {[key: string]: ?string}, y: {z: string, a: string}): string { + if (x[y.z]) { + y.a = \"HEY\"; + return x[y.z]; // ok + } + return \"\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test refinements.js 1`] = ` +"function foo(b) { + var x = b? 0 : null; + while (typeof x == \"string\" || typeof x == \"number\") { + var y:string = x; + x = false; + } + var z:string = x; +} + +function bar(b) { + var x = b? 0 : null; + do { + var y:string = x; + x = false; + } while (x === null); + var z:string = x; +} + +function maybe_throw() { } +function qux() { + var x = 0; + try { + maybe_throw(); + x = \"hello\"; + } catch (e) { + maybe_throw(); + x = \"hello\"; + } finally { + // NOTE: the values understood to flow to x at this point + // include the number 42 written downstream; + // so if we did y:string, we would get at least a spurious error + // (among other reasonable errors caused by values written upstream) + var y:number = x; + x = 42; + } + var z:string = x; +} + +function corge(b) { + for (var x = b? 0 : null; + typeof x == \"string\" || typeof x == \"number\"; + x = false) { + var y:string = x; + } + var z:string = x; +} + +function waldo() { + var o = {}; + var x = false; + for (x in o) { + x = 0; // commenting this out would propagate x:string downstream + } + var z:number = x; +} + +// regression test: bring a global into scope by testing it. +// this has no refinement consequences and is error-free. +// the way we currently cache global lookups causes uneven +// distribution of the global\'s entries at path merge time, +// so we need to recognize that it\'s legit rather than an +// internal error. +// +function global_in_conditional0(x: number) { + // merge_env + if (x != 0) { + if (BAZ) { + } + } +} + +function global_in_conditional2(x: number) { + // copy_env + for (var i = 0; i < 100; i++) { + if (BAZ) { + } + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:925 + if (endsWithBrace(doBody)) + ^ + +ReferenceError: endsWithBrace is not defined + at genericPrintNoParens (/src/printer.js:925:11) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:561:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test string.js 1`] = ` +"// @flow + +type Mode = \"a\" | \"b\" | \"c\"; + +let tests = [ + function(x: string) { + if (x === \'foo\') { + (x: void); // error + } + (x: \'foo\'); // error + }, + + function(x: string) { + if (x !== \'foo\') { + (x: \'foo\'); // error + } + (x: void); // error + }, + + function(x: \'bar\'): \'foo\' { + if (x === \'foo\') { + return x; // unreachable, no error + } + return \'foo\'; + }, + + function(x: \'foo\'): string { + if (x === \'bar\') { + return x; + } + return x; + }, + + function(x: \'foo\') { + if (x !== \'bar\') { + (x: \'foo\'); + } + (x: \'foo\'); + }, + + function(x: \'foo\'): string { + if (x === \'foo\') { + return x; + } + return x; + }, + + function(x: \'foo\' | \'bar\') { + if (x === \'foo\') { + (x: \'foo\'); + (x: void); // error + } + if (x === \'bar\') { + (x: \'bar\'); + (x: void); // error + } + }, + + function(x: { foo: string }): \'foo\' { + if (x.foo === \'foo\') { + return x.foo; + } + return x.foo; // error + }, + + function( + x: { kind: \'foo\', foo: string } | { kind: \'bar\', bar: string } + ): string { + if (x.kind === \'foo\') { + return x.foo; + } else { + return x.bar; + } + }, + + function(str: string, obj: { foo: string }) { + if (str === obj.bar) { // ok, typos allowed in conditionals + } + }, + + function(str: string, obj: {[key: string]: string}) { + if (str === obj.bar) { // ok + } + }, + + function(str: string): Mode { + var ch = str[0]; + if (ch !== \"a\" && ch !== \"b\" && ch !== \"c\") { + throw new Error(\"Wrong string passed\"); + } + return ch; + }, + + function(s: string): ?Mode { + if (s === \"a\") { + return s; + } else if (s === \"d\") { + return s; // error + } + }, + + function(mode: Mode) { + switch (mode) { + case \"a\": + (mode: \"a\"); + break; + + case \"b\": + case \"c\": + (mode: \"b\" | \"c\"); + break; + } + }, + + function(x: string): \"\" { + if (x) { + return x; // error + } else { + return x; // no error, inferred to be \"\" + } + }, + + // Simple template literals are ok + function(x: string): \'foo\' { + if (x === \`foo\`) { + return x; + } + if (\`foo\` === x) { + return x; + } + return \'foo\'; + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test super_member.js 1`] = ` +"/* @flow */ + +class A { + prop: string; + method(): string { + return \"A\"; + } +} + +class B { + test(): string { + if (super.prop) { // super.prop doesn\'t exist + return super.prop; // error, unknown type passed to string expected + } + return \"B\"; + } +} + +class C extends A { + test(): string { + if (super.prop) { + return super.prop; // OK + } + return \"C\"; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class A { + prop: string; + method(): string { + return \"A\"; + } +} +class B { + test(): string { + if (super.prop) { + // super.prop doesn\'t exist + return super.prop;// error, unknown type passed to string expected + } + return \"B\"; + } +} +class C extends A { + test(): string { + if (super.prop) { + return super.prop;// OK + } + return \"C\"; + } +} + +" +`; + +exports[`test switch.js 1`] = ` +"/* @flow */ + +function foo(text: string | number): string { + switch (typeof text) { +  case \'string\': +   return text; + case \'number\': + return text; // error, should return string +  default: +   return \'wat\'; + } +} + +function bar(text: string | number): string { + switch (typeof text) { + case \'string\': + return text[0]; +  default: + return (text++) + \'\'; + } +} + +function baz1(text: string | number): string { + switch (typeof text) { + case \'number\': + case \'string\': + return text[0]; // error, [0] on number +  default: + return \'wat\'; + } +} + +function baz2(text: string | number): string { + switch (typeof text) { + case \'string\': + case \'number\': + return text[0]; // error, [0] on number +  default: + return \'wat\'; + } +} + +function corge(text: string | number | Array): string { + switch (typeof text) { + case \'object\': + return text[0]; + case \'string\': + case \'number\': + // using ++ since it isn\'t valid on arrays or strings. + // should only error for string since Array was filtered out. + return (text++) + \'\'; +  default: + return \'wat\'; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test tagged_union.js 1`] = ` +"// example 1 + +type Type = Name | ListType; +type Name = {kind: \'Name\', value: string}; +type ListType = {kind: \'ListType\', name: string}; + +function getTypeASTName(typeAST: Type): string { + if (typeAST.kind === \'Name\') { + return typeAST.value; // OK, since typeAST: Name + } else { + return typeAST.name; // OK, since typeAST: ListType + } +} + +// example 2 +import type {ASTNode} from \'./ast_node\'; +var Node = require(\'./node1\'); // Node = \"Node1\" +function foo(x: ASTNode) { + if (x.kind === Node) { + return x.prop1.charAt(0); // typeAST: Node1, but x.prop1 may be undefined + } + return null; +} + +// example 3 +type Apple = { kind: \'Fruit\', taste: \'Bad\' } +type Orange = { kind: \'Fruit\', taste: \'Good\' } +type Broccoli = { kind: \'Veg\', taste: \'Bad\', raw: \'No\' } +type Carrot = { kind: \'Veg\', taste: \'Good\', raw: \'Maybe\' } + +type Breakfast = Apple | Orange | Broccoli | Carrot + +function bar(x: Breakfast) { + if (x.kind === \'Fruit\') { (x.taste: \'Good\'); } // error, Apple.taste = Bad + else (x.raw: \'No\'); // error, Carrot.raw = Maybe +} + +function qux(x: Breakfast) { + if (x.taste === \'Good\') { + (x.raw: \'Yes\' | \'No\'); // 2 errors: + // Orange.raw doesn\'t exist + // Carrot.raw is neither Yes nor No + } +} + +// example 4 +function list(n) { + if (n > 0) return { kind: \"cons\", next: list(n-1) }; + return { kind: \"nil\" }; +} +function length(l) { + switch (l.kind) { + case \"cons\": return 1 + length(l.next); + default: return 0; + } +} +function check(n) { + if (n >= 0) return (n === (length(list(n)))); + return true; +} + + +// example 5 +var EnumKind = { A: 1, B: 2, C: 3}; +type A = { kind: 1, A: number }; +type B = { kind: 2, B: number }; +type C = { kind: 3, C: number }; +function kind(x: A | B | C): number { + switch (x.kind) { + case EnumKind.A: return x.A; + case EnumKind.B: return x.B; + default: return x.A; // error, x: C and property A not found in type C + } +} +kind({ kind: EnumKind.A, A: 1 }); + +// example 6 +type Citizen = { citizen: true }; +type NonCitizen = { citizen: false, nationality: string } +function nationality(x: Citizen | NonCitizen) { + if (x.citizen) return \"Shire\" + else return x.nationality; +} + +let tests = [ + // non-existent props + function test7(x: A) { + if (x.kindTypo === 1) { // typos are allowed to be tested + (x.kindTypo: string); // typos can\'t be used, though + } + }, + + // nested objects + function test8(x: {foo: {bar: 1}}) { + if (x.foo.bar === 1) {} + if (x.fooTypo.bar === 1) {} // error, fooTypo doesn\'t exist + }, + + // invalid RHS + function(x: A) { + if (x.kind === (null).toString()) {} // error, method on null + if ({kind: 1}.kind === (null).toString()) {} // error, method on null + }, + + // non-objects on LHS + function( + x: Array, y: string, z: number, q: boolean, + r: Object, s: Function, t: () => void + ) { + if (x.length === 0) {} + if (x.legnth === 0) { // typos are allowed to be tested + (x.legnth: number); // inside the block, it\'s a number + (x.legnth: string); // error: number literal 0 !~> string + } + if (y.length === 0) {} + if (y.legnth === 0) { // typos are allowed to be tested + (y.legnth: number); // inside the block, it\'s a number + (y.legnth: string); // error: number literal 0 !~> string + } + if (z.toString === 0) {} + if (z.toStirng === 0) { // typos are allowed to be tested + (z.toStirng: number); // inside the block, it\'s a number + (z.toStirng: string); // error: number literal 0 !~> string + } + if (q.valueOf === 0) {} + if (q.valeuOf === 0) { // typos are allowed to be tested + (q.valeuOf: number); // inside the block, it\'s a number + (q.valeuOf: string); // error: number literal 0 !~> string + } + if (r.toStirng === 0) { // typos are allowed to be tested + (r.toStirng: empty); // props on AnyObjT are \`any\` + } + if (s.call === 0) {} + if (s.calll === 0) { // typos are allowed to be tested + (t.calll: empty); // ok, props on functions are \`any\` :/ + } + if (t.call === 0) {} + if (t.calll === 0) { // typos are allowed to be tested + (t.calll: empty); // ok, props on functions are \`any\` :/ + } + }, + + // sentinel props become the RHS + function(x: { str: string, num: number, bool: boolean }) { + if (x.str === \'str\') { + (x.str: \'not str\'); // error: \'str\' !~> \'not str\' + } + if (x.num === 123) { + (x.num: 456); // error: 123 !~> 456 + } + if (x.bool === true) { + (x.bool: false); // error: true !~> false + } + // even if it doesn\'t exist... + if (x.badStr === \'bad\') { + (x.badStr: empty); // error: \'bad\' !~> empty + } + if (x.badNum === 123) { + (x.badNum: empty); // error: 123 !~> empty + } + if (x.badBool === true) { + (x.badBool: empty); // error: true !~> empty + } + }, + + // type mismatch + function(x: { foo: 123, y: string } | { foo: \'foo\', z: string }) { + if (x.foo === 123) { + (x.y: string); + x.z; // error + } else { + (x.z: string); + x.y; // error + } + if (x.foo === \'foo\') { + (x.z: string); + x.y; // error + } else { + (x.y: string); + x.z; // error + } + }, + + // type mismatch, but one is not a literal + function(x: { foo: number, y: string } | { foo: \'foo\', z: string }) { + if (x.foo === 123) { + (x.y: string); // ok, because 123 !== \'foo\' + x.z; // error + } else { + x.y; // error: x.foo could be a string + x.z; // error: could still be either case (if foo was a different number) + } + + if (x.foo === \'foo\') { + (x.z: string); + x.y; // error + } else { + (x.y: string); + x.z; // error + } + }, + + // type mismatch, neither is a literal + function(x: { foo: number, y: string } | { foo: string, z: string }) { + if (x.foo === 123) { + (x.y: string); // ok, because 123 !== string + x.z; // error + } else { + x.y; // error: x.foo could be a string + x.z; // error: could still be either case (if foo was a different number) + } + + if (x.foo === \'foo\') { + (x.z: string); + x.y; // error + } else { + x.y; // error: x.foo could be a different string + x.z; // error: x.foo could be a number + } + }, + + // type mismatch, neither is a literal, test is not a literal either + function( + x: { foo: number, y: string } | { foo: string, z: string }, + num: number + ) { + if (x.foo === num) { + x.y; // error: flow isn\'t smart enough to figure this out yet + x.z; // error + } + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test tagged_union_import.js 1`] = ` +"/* @flow */ + +import { SUCCESS, ERROR } from \'./constants\' + +type Success = { + type: typeof SUCCESS, + message: string +} + +type Error = { + type: typeof ERROR, + error: string +} + +function handleStatus(status: Success | Error) { + switch(status.type) { + case SUCCESS: + console.log(\`Successful: \${status.message}\`); + break; + default: + console.log(\`Errored: \${status.error}\`); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test typeof.js 1`] = ` +"/* @flow */ + +function foo(x: bool | number) { + if (typeof x === \"boolean\") { + x[0]; // error for boolean, not number + } +} + +function bar(): number { + var x = null; + if (typeof x === \"object\") { + return x; // error, null + } + return 0; +} + +/* refining globals */ +function fn0() { + if (typeof BAZ !== \'undefined\' && + typeof BAZ.stuff === \'function\') { + BAZ.stuff(123); + } + BAZ.stuff(123); // error, refinement is gone +} +function fn1() { + BAZ.stuff; // error, could be undefined + if (typeof BAZ !== \'undefined\' && + typeof BAZ.stuff === \'function\') { + BAZ.stuff(123); // ok + BAZ.stuff(123); // error, refinement is gone + } +} + +function anyfun(x: number | Function): number { + if (typeof x === \"function\") { + return 0; + } + return x; // OK, x refined to \`number\` +} + +function anyobj(x: number | Object): number { + if (typeof x === \"object\") { + return 0; + } + return x; // OK, x refined to \`number\` +} + +function testInvalidValue(x: mixed) { + if (typeof x === \"foo\") { // error + return 0; + } +} + +function testTemplateLiteral(x: string | number) { + if (typeof x === \`string\`) { + return x.length; + } +} + +function testInvalidTemplateLiteral(x: string | number) { + if (typeof x === \`foo\`) { // error + return 0; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test undef.js 1`] = ` +"/* @flow */ + +function undef_var(x: ?number) { + if (x !== null && x !== undefined) { + var y = x * 1000; + } +} + +function undef_var_rev(x: ?number) { + if (x === null || x === undefined) { + } else { + var y = x * 1000; + } +} + +function undef_prop(x: { x: ?number }) { + if (x.x !== null && x.x !== undefined) { + var y = x.x * 1000; + } +} + +function undef_prop_rev(x: { x: ?number }) { + if (x.x === null || x.x === undefined) { + } else { + var y = x.x * 1000; + } +} + +function undef_var_fail(x: ?number) { + if (x !== undefined) { + var y = x * 1000; + } +} + +function undef_var_fail_rev(x: ?number) { + if (x === undefined) { + } else { + var y = x * 1000; + } +} + +function undef_prop_fail(x: { x: ?number }) { + if (x.x !== undefined) { + var y = x.x * 1000; + } +} + +function undef_prop_fail_rev(x: { x: ?number }) { + if (x.x === undefined) { + } else { + var y = x.x * 1000; + } +} + +function undef_unreachable(x: number) { + if (x === undefined) { + var y = x * 1000; // unreachable + } + if (x == undefined) { + var z = x * 1000; // unreachable + } +} + +function undef_var_nonstrict(x: ?number, y: ?number) { + if (x != undefined) { + var a = x * 1000; + } + if (y == undefined){ + var b = y * 1000; // error + } +} + +function undef_bogus_comparison() { + if (100 * undefined) { + return; + } + if (undefined * 100) { + return; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function undef_var(x: ?number) { + if (x !== null && x !== undefined) { + var y = x * 1000; + } +} +function undef_var_rev(x: ?number) { + if (x === null || x === undefined) { + + } else { + var y = x * 1000; + } +} +function undef_prop(x: { x: ?number }) { + if (x.x !== null && x.x !== undefined) { + var y = x.x * 1000; + } +} +function undef_prop_rev(x: { x: ?number }) { + if (x.x === null || x.x === undefined) { + + } else { + var y = x.x * 1000; + } +} +function undef_var_fail(x: ?number) { + if (x !== undefined) { + var y = x * 1000; + } +} +function undef_var_fail_rev(x: ?number) { + if (x === undefined) { + + } else { + var y = x * 1000; + } +} +function undef_prop_fail(x: { x: ?number }) { + if (x.x !== undefined) { + var y = x.x * 1000; + } +} +function undef_prop_fail_rev(x: { x: ?number }) { + if (x.x === undefined) { + + } else { + var y = x.x * 1000; + } +} +function undef_unreachable(x: number) { + if (x === undefined) { + var y = x * 1000;// unreachable + } + if (x == undefined) { + var z = x * 1000;// unreachable + } +} +function undef_var_nonstrict(x: ?number, y: ?number) { + if (x != undefined) { + var a = x * 1000; + } + if (y == undefined) { + var b = y * 1000;// error + } +} +function undef_bogus_comparison() { + if (100 * undefined) { + return; + } + if (undefined * 100) { + return; + } +} + +" +`; + +exports[`test union.js 1`] = ` +"/* @flow */ + +type thing = number | bool + +function foo(x: thing) { + if (x === true) { + x[0]; // error on boolean + } +} + +function bar(x: thing) { + if (x !== true && x !== false) { + x[0]; // error on number + } +} + +function baz(x: ?thing) { + if (x && x !== true) { + x[0]; // error on number + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test void.js 1`] = ` +"/* @flow */ + +function void_var(x: ?number) { + if (x !== null && x !== void(0)) { + var y = x * 1000; + } +} + +function void_var_rev(x: ?number) { + if (x === null || x === void(0)) { + } else { + var y = x * 1000; + } +} + +function void_pro(x: { x: ?number }) { + if (x.x !== null && x.x !== void(0)) { + var y = x.x * 1000; + } +} + +function void_pro_rev(x: { x: ?number }) { + if (x.x === null || x.x === void(0)) { + } else { + var y = x.x * 1000; + } +} + +function void_var_fail(x: ?number) { + if (x !== void(0)) { + var y = x * 1000; + } +} + +function void_var_fail_rev(x: ?number) { + if (x === void(0)) { + } else { + var y = x * 1000; + } +} + +function void_pro_fail(x: { x: ?number }) { + if (x.x !== void(0)) { + var y = x.x * 1000; + } +} + +function void_pro_fail_rev(x: { x: ?number }) { + if (x.x === void(0)) { + } else { + var y = x.x * 1000; + } +} + +function void_var_side_effect(x: ?number) { + if (x !== null && x !== void(x * 1000)) { + var y = x * 1000; + } +} + +function void_var_side_effect_rev(x: ?number) { + if (x === null || x === void(x * 1000)) { + } else { + var y = x * 1000; + } +} + +function void_prop_side_effect(x: { x: ?number }) { + if (x.x !== null && x.x !== void(x.x * 1000)) { + var y = x.x * 1000; + } +} + +function void_prop_side_effect_rev(x: { x: ?number }) { + if (x.x === null || x.x === void(x.x * 1000)) { + } else { + var y = x.x * 1000; + } +} + +function void_bogus_comparison() { + if (100 * void(0)) { + return; + } + if (void(0) * 100) { + return; + } +} + +function void_redefined_undefined(x: ?number) { + var undefined = \"foo\"; + if (x !== null && x !== void(0)) { + var y = x * 1000; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function void_var(x: ?number) { + if (x !== null && x !== void 0) { + var y = x * 1000; + } +} +function void_var_rev(x: ?number) { + if (x === null || x === void 0) { + + } else { + var y = x * 1000; + } +} +function void_pro(x: { x: ?number }) { + if (x.x !== null && x.x !== void 0) { + var y = x.x * 1000; + } +} +function void_pro_rev(x: { x: ?number }) { + if (x.x === null || x.x === void 0) { + + } else { + var y = x.x * 1000; + } +} +function void_var_fail(x: ?number) { + if (x !== void 0) { + var y = x * 1000; + } +} +function void_var_fail_rev(x: ?number) { + if (x === void 0) { + + } else { + var y = x * 1000; + } +} +function void_pro_fail(x: { x: ?number }) { + if (x.x !== void 0) { + var y = x.x * 1000; + } +} +function void_pro_fail_rev(x: { x: ?number }) { + if (x.x === void 0) { + + } else { + var y = x.x * 1000; + } +} +function void_var_side_effect(x: ?number) { + if (x !== null && x !== void (x * 1000)) { + var y = x * 1000; + } +} +function void_var_side_effect_rev(x: ?number) { + if (x === null || x === void (x * 1000)) { + + } else { + var y = x * 1000; + } +} +function void_prop_side_effect(x: { x: ?number }) { + if (x.x !== null && x.x !== void (x.x * 1000)) { + var y = x.x * 1000; + } +} +function void_prop_side_effect_rev(x: { x: ?number }) { + if (x.x === null || x.x === void (x.x * 1000)) { + + } else { + var y = x.x * 1000; + } +} +function void_bogus_comparison() { + if (100 * void 0) { + return; + } + if (void 0 * 100) { + return; + } +} +function void_redefined_undefined(x: ?number) { + var undefined = \"foo\"; + if (x !== null && x !== void 0) { + var y = x * 1000; + } +} + +" +`; diff --git a/tests/refinements/assignment.js b/tests/refinements/assignment.js new file mode 100644 index 000000000000..a331d6d3e271 --- /dev/null +++ b/tests/refinements/assignment.js @@ -0,0 +1,32 @@ +/* @flow */ + +function foo(x : ?number) { + var y; + if (y = x) { + var z = y * 1000; + } +} + +type Bar = { + parent: ?Bar; + doStuff: () => void +} + +function bar0(x : Bar) { + while (x = x.parent) { // can't assign x to ?Bar + x.doStuff(); + } +} + +function bar1(x : ?Bar) { + while (x = x.parent) { // x.parent might be null + x.doStuff(); + } +} + +function bar2(x : Bar) { + var y = x; + while (y = y.parent) { + y.doStuff(); + } +} diff --git a/tests/refinements/ast_node.js b/tests/refinements/ast_node.js new file mode 100644 index 000000000000..396d466e1d94 --- /dev/null +++ b/tests/refinements/ast_node.js @@ -0,0 +1,11 @@ +type Node1 = { + kind: 'Node1', + prop1?: string +}; + +type Node2 = { + kind: 'Node2', + prop2?: string +} + +export type ASTNode = Node1 | Node2; diff --git a/tests/refinements/bool.js b/tests/refinements/bool.js new file mode 100644 index 000000000000..5730681c83a7 --- /dev/null +++ b/tests/refinements/bool.js @@ -0,0 +1,46 @@ +/* @flow */ + +function foo(x: ?bool) { + if (x === false) { + return; + } + + if (x === true) { + return; + } + + x[0]; // error on null and undefined +} + +function bar(x: ?bool) { + if (x !== true) { + if (x !== false) { + x[0]; // error on null and undefined + } + } +} + +function baz(x: ?bool) { + if (100 * false) { + return; + } + if (false * 100) { + return; + } +} + +let tests = [ + function(x: { done: true, result: string } | { done: false }) { + if (x.done === true) { + return x.result; + } + return x.result; // error + }, + + function(x: { done: true, result: string } | { done: false }) { + if (true === x.done) { + return x.result; + } + return x.result; // error + }, +]; diff --git a/tests/refinements/computed_string_literal.js b/tests/refinements/computed_string_literal.js new file mode 100644 index 000000000000..93fa0716cec4 --- /dev/null +++ b/tests/refinements/computed_string_literal.js @@ -0,0 +1,19 @@ +// @flow + +type A = { + 'b_c': ?string +}; + +function stuff(str: string) {} + +function testProperty(a: A) { + if (a.b_c) { + stuff(a.b_c) + } +} + +function testLiteralProperty(a: A) { + if (a['b_c']) { + stuff(a['b_c']) + } +} diff --git a/tests/refinements/cond_prop.js b/tests/refinements/cond_prop.js new file mode 100644 index 000000000000..7bab5dfef721 --- /dev/null +++ b/tests/refinements/cond_prop.js @@ -0,0 +1,52 @@ +/* @flow */ + +type Type = Name | ListType | NonNullType; +type Name = {kind: 'Name', value: string, type: void }; +type ListType = {kind: 'ListType', type: Type}; +type NonNullType = {kind: 'NonNullType', type: Name | ListType | BadType}; +type BadType = {}; + +function getTypeASTName(typeAST: Type): string { + if (!typeAST.type) throw new Error('Must be wrapping type'); // OK + return getTypeASTName(typeAST.type); // error, BadType not a subtype of Type +} + +let tests = [ + function(x: { done: true, result: string } | { done: false }) { + if (x.done) { + return x.result; + } + return x.result; // error + }, + + function(x: { done: true, result: string } | { foo: string }) { + if (x.done) { + return x.result; // error, consider { foo: "herp", done: "derp" } + } + return x.result; // error + }, + + function() { + type T + = { foo: Object, bar: string } + | { baz: string, quux: string } + + function testAlwaysTruthyProp(t: T) { + if (t.foo) { + (t.bar: string); // error, consider { baz: "x", quux: "y", foo: "boom" } + } else { + (t.quux: string); // ok. since foo is an object (always truthy), the + // else case completely rules out the first branch of + // the union. + } + } + + function testSometimesTruthyProp(t: T) { + if (t.bar) { + (t.foo: Object); // error, consider { baz: "x", quux: "y", bar: "boom" } + } else { + (t.quux: string); // error, consider { foo: {}, bar: "" } + } + } + }, +] diff --git a/tests/refinements/constants.js b/tests/refinements/constants.js new file mode 100644 index 000000000000..c845d58c24db --- /dev/null +++ b/tests/refinements/constants.js @@ -0,0 +1,4 @@ +/* @flow */ + +export const SUCCESS: 'SUCCESS' = 'SUCCESS'; +export const ERROR: 'ERROR' = 'ERROR'; diff --git a/tests/refinements/eq.js b/tests/refinements/eq.js new file mode 100644 index 000000000000..24fdaab5a448 --- /dev/null +++ b/tests/refinements/eq.js @@ -0,0 +1,22 @@ +/* @flow */ + +let tests = [ + function(x: string, y: number) { + if (x == y) {} // error, string & number are not comparable (unsafe casting) + if (x === y) {} // no error, to match `let z = (x === y)` which is allowed + }, + + function(x: string) { + if (x == undefined) {} // ok + if (x == void 0) {} // ok + }, + + function(x: string) { + if (x == null) {} // ok + }, + + function(x: { y: 'foo' } | { y: 'bar' }) { + if (x.y == 123) {} // error + if (x.y === 123) {} // ok + }, +] diff --git a/tests/refinements/exists.js b/tests/refinements/exists.js new file mode 100644 index 000000000000..b26e29a5b980 --- /dev/null +++ b/tests/refinements/exists.js @@ -0,0 +1,15 @@ +declare class Foo { + foo: string; +} + +function foo0(x: ?string): string { + return x && x || ""; +} + +function foo1(x: ?Foo): string { + return x && x.foo || ""; +} + +function foo2(x: ?Class): string { + return x && new x().foo || ""; +} diff --git a/tests/refinements/func_call.js b/tests/refinements/func_call.js new file mode 100644 index 000000000000..693c3c44e929 --- /dev/null +++ b/tests/refinements/func_call.js @@ -0,0 +1,12 @@ +// @flow + +let tests = [ + function(x: { y?: string }, z: () => string) { + if (x.y) { + // make sure we visit the AST in the correct order. if we visit z() before + // x.y, then the function call will invalidate the refinement of x.y + // incorrectly. + x.y.indexOf(z()); // no error + } + }, +]; diff --git a/tests/refinements/hasOwnProperty.js b/tests/refinements/hasOwnProperty.js new file mode 100644 index 000000000000..1545a554df94 --- /dev/null +++ b/tests/refinements/hasOwnProperty.js @@ -0,0 +1,21 @@ +/* @flow */ + +function foo(x:{y?:() => void}) { + x.y(); // error: could be undefined + if (x.hasOwnProperty('y')) { + x.y(); // error: still could be undefined + } + if (x.hasOwnProperty('z')) { + x.z(); // error: unreachable, but we don't help you here + } +} + +function bar(x:Object) { + x.y(); // treated as `any`, so allowed + if (x.hasOwnProperty('y')) { + x.y(); // still treated as `any`, so allowed + } + if (x.hasOwnProperty('z')) { + x.z(); // also treated as `any`, so allowed + } +} diff --git a/tests/refinements/heap_defassign.js b/tests/refinements/heap_defassign.js new file mode 100644 index 000000000000..09a760588469 --- /dev/null +++ b/tests/refinements/heap_defassign.js @@ -0,0 +1,84 @@ +// @flow + +type Obj = { p: number | string } + +function f () {} + +function def_assign_function_havoc(obj: Obj) { + obj.p = 10; // (obj.p : number) + f(); // clears refi + var x: number = obj.p; // error, obj.p : number | string +} + +function def_assign_setprop_havoc(obj: Obj, obj2: Obj) { + obj.p = 10; // (obj.p : number) + obj2.p = 'hey'; // clears refi + var x: number = obj.p; // error, obj.p : number | string +} + +function def_assign_index_havoc(obj: Obj, obj2: Obj) { + obj.p = 10; // (obj.p : number) + obj2['p'] = 'hey'; // clears refi + var x: number = obj.p; // error, obj.p : number | string +} + +function def_assign_within_if(b: boolean, obj: Obj) { + if (b) { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } + var y: number = obj.p; // error, obj.p : number | string +} + +function def_assign_within_while(b: boolean, obj: Obj) { + while (b) { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } + var y: number = obj.p; // error, obj.p : number | string +} + +function def_assign_within_do(b: boolean, obj: Obj) { + do { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } while (b); + var y: number = obj.p; // no error, loop runs at least once +} + +function def_assign_within_try(b: boolean, obj: Obj) { + obj.p = 10; // (obj.p : number) + try { + f(); // clears refi and might throw + obj.p = 'hey'; + } catch (e) { + f(); // clears refi and might throw + obj.p = 'hey'; + } finally { + // NOTE: the values understood to flow to obj.p at this point + // include the number 42 written downstream; + // so if we did y:string, we would get at least a spurious error + // (among other reasonable errors caused by values written upstream) + var y: number = obj.p; // error, string ~/~ number + obj.p = 42; + } + var z:string = obj.p; // error, number ~/~ string +} + +function def_assign_within_for(b: boolean, obj: Obj) { + for (; b; ) { + obj.p = 10; // (obj.p : number) + var x: number = obj.p // ok by def assign + } + var z: number = obj.p; // error, (number | string) ~/~ number +} + +// --- name-sensitive havoc --- + +type Obj2 = { q: number | string } + +function def_assign_setprop_nohavoc(obj: Obj, obj2: Obj2) { + obj.p = 10; // (obj.p : number) + obj2.q = 'hey'; // doesn't clear refi of .p + var x: number = obj.p; // still ok +} diff --git a/tests/refinements/jsfmt.spec.js b/tests/refinements/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/refinements/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/refinements/lib.js b/tests/refinements/lib.js new file mode 100644 index 000000000000..211648743a38 --- /dev/null +++ b/tests/refinements/lib.js @@ -0,0 +1,3 @@ +/* @flow */ + +declare var BAZ: {stuff?: (x: number) => void} | void; diff --git a/tests/refinements/missing-property-cond.js b/tests/refinements/missing-property-cond.js new file mode 100644 index 000000000000..944bd0f99d7d --- /dev/null +++ b/tests/refinements/missing-property-cond.js @@ -0,0 +1,50 @@ +// @flow + +function foo1(o: { x: number }) { + if (o.p1) { // OK, this is an idiomatic way of testing property existence + o.x; + } +} + +function foo2(o: { x: number }) { + if (o.p2) { // OK + o.p2.x; // error, since o.p2's type is unknown (e.g., could be `number`) + } +} + +function foo3(o: { x: number }) { + o.p3.x; // usual error outside conditional +} + +function foo4(o: $Exact<{ x: number }>) { + if (o.p4) { // OK + o.p4.x; // currently OK, should be unreachable + } else { + o.p4.x; // error + } +} + +function foo5() { + const o = { }; + _foo5(); + if (o.p) { o.p(); } + function _foo5() { + o.p = function() { } + } +} + +function foo6(o: mixed) { + if (o.bar) {} // error, any lookup on mixed is unsafe +} + +function foo7(o: mixed) { + if (typeof o.bar === 'string') {} // error + if (o && typeof o.bar === 'string') {} // ok + if (o != null && typeof o.bar === 'string') {} // ok + if (o !== null && o !== undefined && typeof o.bar === 'string') {} // ok +} + +function foo8(o: { p: mixed }) { + if (o.p && o.p.q) {} // this is ok because o.p is truthy, so o.p.q is safe + if (o.p && o.p.q && o.p.q.r) {} +} diff --git a/tests/refinements/mixed.js b/tests/refinements/mixed.js new file mode 100644 index 000000000000..5c12b32c541e --- /dev/null +++ b/tests/refinements/mixed.js @@ -0,0 +1,121 @@ +/* @flow */ + +function takesNumber(x: number) {} +function takesString(x: string) {} + +function num(x: mixed) { + if (typeof x === "number") { + takesString(x); // error + (!x: false); // error: we don't know the truthiness of x + } + if (typeof x === "number" && x) { + (!x: false); // ok + } + if (x && typeof x === "number") { + (!x: false); // ok + } +} + +function str(x: mixed) { + if (typeof x === "string") { + takesNumber(x); // error + (!x: false); // error: we don't know the truthiness of x + } + if (typeof x === "string" && x) { + (!x: false); // ok + } + if (x && typeof x === "string") { + (!x: false); // ok + } +} + +function bool(x: mixed) { + if (typeof x === "boolean") { + takesString(x); // error + (x: true); // error: we don't know the truthiness of x + } + if (typeof x === "boolean" && x) { + (x: true); // ok + } + if (x && typeof x === "boolean") { + (x: true); // ok + } +} + +function fun(x: mixed) { + if (typeof x === "function") { + takesString(x); // error + } +} + +function obj0(x: mixed) { + if (typeof x === "object") { + takesString(x); // error + } +} + +function obj1(x: mixed) { + if (Array.isArray(x)) { + takesString(x); // error + } +} + +function undef(x: mixed) { + if (typeof x === "undefined") { + takesString(x); // error + } +} + +function null_(x: mixed) { + if (x === null) { + takesString(x); // error + } +} + +function maybe(x: mixed) { + if (x == null) { + takesString(x); // error + } +} + +function true_(x: mixed) { + if (x === true) { + takesString(x); // error + } +} + +function false_(x: mixed) { + if (x === false) { + takesString(x); // error + } +} + +function obj2(x: mixed) { + if (typeof x === "object") { + (x: { [key: string]: mixed } | null); + if (x !== null) { + (x['foo']: string); // error, mixed + } + } +} + +function obj2(x: mixed) { + if (typeof x === "object" && x) { + (x: Object); + } + if (x && typeof x === "object") { + (x: Object); + } + if (x != null && typeof x === "object") { + (x: Object); + } + if (x !== null && typeof x === "object") { + (x: Object); + } +} + +function arr0(x: mixed) { + if (Array.isArray(x)) { + takesString(x[0]); // error + } +} diff --git a/tests/refinements/node1.js b/tests/refinements/node1.js new file mode 100644 index 000000000000..97afd3f36556 --- /dev/null +++ b/tests/refinements/node1.js @@ -0,0 +1 @@ +module.exports = 'Node1'; diff --git a/tests/refinements/not.js b/tests/refinements/not.js new file mode 100644 index 000000000000..dafd50927609 --- /dev/null +++ b/tests/refinements/not.js @@ -0,0 +1,52 @@ +/* @flow */ + +function foo(x: ?bool) { + if (!x) { + x++; // should error for null, void and bool (false) + } +} + +function bar(x: ?number) { + if (!x) { + x[0]; // should error for null, void and number (0) + } +} + +function baz (x: ?number) { + if (x === null || x === undefined) { + return; + } + + if (!x) { + x[0]; // should error for number (0) + } +} + +class TestClass {} + +let tests = [ + function() { + var y = true; + while (y) { + y = !y; + } + }, + function(x: Function) { + (!x: false); // ok, functions are always truthy + }, + function(x: Object) { + (!x: false); // ok, objects are always truthy + }, + function(x: string) { + (!x: false); // error, strings are not always truthy + }, + function(x: number) { + (!x: false); // error, numbers are not always truthy + }, + function(x: boolean) { + (!x: false); // error, bools are not always truthy + }, + function(x: TestClass) { + (!x: false); // ok, classes are always truthy + }, +]; diff --git a/tests/refinements/null.js b/tests/refinements/null.js new file mode 100644 index 000000000000..f21881abda93 --- /dev/null +++ b/tests/refinements/null.js @@ -0,0 +1,10 @@ +/* @flow */ + +function null_bogus_comparison() { + if (100 * null) { + return; + } + if (null * 100) { + return; + } +} diff --git a/tests/refinements/number.js b/tests/refinements/number.js new file mode 100644 index 000000000000..4c192b8e428e --- /dev/null +++ b/tests/refinements/number.js @@ -0,0 +1,121 @@ +// @flow + +type Mode = 0 | 1 | 2; + +let tests = [ + function(x: number) { + if (x === 0) { + (x: void); // error + } + (x: 0); // error + }, + + function(x: number) { + if (x !== 0) { + (x: 0); // error + } + (x: void); // error + }, + + function(x: 1): 0 { + if (x === 0) { + return x; // unreachable, no error + } + return 0; + }, + + function(x: 0): number { + if (x === 1) { + return x; + } + return x; + }, + + function(x: 0) { + if (x !== 1) { + (x: 0); + } + (x: 0); + }, + + function(x: 0): number { + if (x === 0) { + return x; + } + return x; + }, + + function(x: 0 | 1) { + if (x === 0) { + (x: 0); + (x: void); // error + } + if (x === 1) { + (x: 1); + (x: void); // error + } + }, + + function(x: { foo: number }): 0 { + if (x.foo === 0) { + return x.foo; + } + return x.foo; // error + }, + + function( + x: { kind: 0, foo: number } | { kind: 1, bar: number } + ): number { + if (x.kind === 0) { + return x.foo; + } else { + return x.bar; + } + }, + + function(num: number, obj: { foo: number }) { + if (num === obj.bar) { // ok, typos allowed in conditionals + } + }, + + function(num: number, obj: {[key: string]: number}) { + if (num === obj.bar) { // ok + } + }, + + function(n: number): Mode { + if (n !== 0 && n !== 1 && n !== 2) { + throw new Error("Wrong number passed"); + } + return n; + }, + + function(s: number): ?Mode { + if (s === 0) { + return s; + } else if (s === 3) { + return s; // error + } + }, + + function(mode: Mode) { + switch (mode) { + case 0: + (mode: 0); + break; + + case 1: + case 2: + (mode: 1 | 2); + break; + } + }, + + function(x: number): 0 { + if (x) { + return x; // error + } else { + return x; // no error, inferred to be 0 + } + }, +]; diff --git a/tests/refinements/property.js b/tests/refinements/property.js new file mode 100644 index 000000000000..6513e1deb340 --- /dev/null +++ b/tests/refinements/property.js @@ -0,0 +1,82 @@ +/* @flow */ + +function a(x: {[key: string]: ?string}, y: string): string { + if (x[y]) { + return x[y]; + } + return ""; +} + +function b(x: {y: {[key: string]: ?string}}, z: string): string { + if (x.y[z]) { + return x.y[z]; + } + return ""; +} + +function c(x: {[key: string]: ?string}, y: {z: string}): string { + if (x[y.z]) { + return x[y.z]; + } + return ""; +} + +function d(x: {y: {[key: string]: ?string}}, a: {b: string}): string { + if (x.y[a.b]) { + return x.y[a.b]; + } + return ""; +} + +function a_array(x: Array, y: number): string { + if (x[y]) { + return x[y]; + } + return ""; +} + +function b_array(x: {y: Array}, z: number): string { + if (x.y[z]) { + return x.y[z]; + } + return ""; +} + +function c_array(x: Array, y: {z: number}): string { + if (x[y.z]) { + return x[y.z]; + } + return ""; +} + +function d_array(x: {y: Array}, a: {b: number}): string { + if (x.y[a.b]) { + return x.y[a.b]; + } + return ""; +} + +function e_array(x: Array): string { + if (x[0]) { + return x[0]; + } + return ""; +} + +// --- name-sensitive havoc --- + +function c2(x: {[key: string]: ?string}, y: {z: string}): string { + if (x[y.z]) { + y.z = "HEY"; + return x[y.z]; // error + } + return ""; +} + +function c3(x: {[key: string]: ?string}, y: {z: string, a: string}): string { + if (x[y.z]) { + y.a = "HEY"; + return x[y.z]; // ok + } + return ""; +} diff --git a/tests/refinements/refinements.js b/tests/refinements/refinements.js new file mode 100644 index 000000000000..76da9e52058a --- /dev/null +++ b/tests/refinements/refinements.js @@ -0,0 +1,78 @@ +function foo(b) { + var x = b? 0 : null; + while (typeof x == "string" || typeof x == "number") { + var y:string = x; + x = false; + } + var z:string = x; +} + +function bar(b) { + var x = b? 0 : null; + do { + var y:string = x; + x = false; + } while (x === null); + var z:string = x; +} + +function maybe_throw() { } +function qux() { + var x = 0; + try { + maybe_throw(); + x = "hello"; + } catch (e) { + maybe_throw(); + x = "hello"; + } finally { + // NOTE: the values understood to flow to x at this point + // include the number 42 written downstream; + // so if we did y:string, we would get at least a spurious error + // (among other reasonable errors caused by values written upstream) + var y:number = x; + x = 42; + } + var z:string = x; +} + +function corge(b) { + for (var x = b? 0 : null; + typeof x == "string" || typeof x == "number"; + x = false) { + var y:string = x; + } + var z:string = x; +} + +function waldo() { + var o = {}; + var x = false; + for (x in o) { + x = 0; // commenting this out would propagate x:string downstream + } + var z:number = x; +} + +// regression test: bring a global into scope by testing it. +// this has no refinement consequences and is error-free. +// the way we currently cache global lookups causes uneven +// distribution of the global's entries at path merge time, +// so we need to recognize that it's legit rather than an +// internal error. +// +function global_in_conditional0(x: number) { + // merge_env + if (x != 0) { + if (BAZ) { + } + } +} + +function global_in_conditional2(x: number) { + // copy_env + for (var i = 0; i < 100; i++) { + if (BAZ) { + } + } +} diff --git a/tests/refinements/string.js b/tests/refinements/string.js new file mode 100644 index 000000000000..62873deda8e4 --- /dev/null +++ b/tests/refinements/string.js @@ -0,0 +1,133 @@ +// @flow + +type Mode = "a" | "b" | "c"; + +let tests = [ + function(x: string) { + if (x === 'foo') { + (x: void); // error + } + (x: 'foo'); // error + }, + + function(x: string) { + if (x !== 'foo') { + (x: 'foo'); // error + } + (x: void); // error + }, + + function(x: 'bar'): 'foo' { + if (x === 'foo') { + return x; // unreachable, no error + } + return 'foo'; + }, + + function(x: 'foo'): string { + if (x === 'bar') { + return x; + } + return x; + }, + + function(x: 'foo') { + if (x !== 'bar') { + (x: 'foo'); + } + (x: 'foo'); + }, + + function(x: 'foo'): string { + if (x === 'foo') { + return x; + } + return x; + }, + + function(x: 'foo' | 'bar') { + if (x === 'foo') { + (x: 'foo'); + (x: void); // error + } + if (x === 'bar') { + (x: 'bar'); + (x: void); // error + } + }, + + function(x: { foo: string }): 'foo' { + if (x.foo === 'foo') { + return x.foo; + } + return x.foo; // error + }, + + function( + x: { kind: 'foo', foo: string } | { kind: 'bar', bar: string } + ): string { + if (x.kind === 'foo') { + return x.foo; + } else { + return x.bar; + } + }, + + function(str: string, obj: { foo: string }) { + if (str === obj.bar) { // ok, typos allowed in conditionals + } + }, + + function(str: string, obj: {[key: string]: string}) { + if (str === obj.bar) { // ok + } + }, + + function(str: string): Mode { + var ch = str[0]; + if (ch !== "a" && ch !== "b" && ch !== "c") { + throw new Error("Wrong string passed"); + } + return ch; + }, + + function(s: string): ?Mode { + if (s === "a") { + return s; + } else if (s === "d") { + return s; // error + } + }, + + function(mode: Mode) { + switch (mode) { + case "a": + (mode: "a"); + break; + + case "b": + case "c": + (mode: "b" | "c"); + break; + } + }, + + function(x: string): "" { + if (x) { + return x; // error + } else { + return x; // no error, inferred to be "" + } + }, + + // Simple template literals are ok + function(x: string): 'foo' { + if (x === `foo`) { + return x; + } + if (`foo` === x) { + return x; + } + return 'foo'; + }, +]; diff --git a/tests/refinements/super_member.js b/tests/refinements/super_member.js new file mode 100644 index 000000000000..3aa941b12d8f --- /dev/null +++ b/tests/refinements/super_member.js @@ -0,0 +1,26 @@ +/* @flow */ + +class A { + prop: string; + method(): string { + return "A"; + } +} + +class B { + test(): string { + if (super.prop) { // super.prop doesn't exist + return super.prop; // error, unknown type passed to string expected + } + return "B"; + } +} + +class C extends A { + test(): string { + if (super.prop) { + return super.prop; // OK + } + return "C"; + } +} diff --git a/tests/refinements/switch.js b/tests/refinements/switch.js new file mode 100644 index 000000000000..f5e41cd22cac --- /dev/null +++ b/tests/refinements/switch.js @@ -0,0 +1,55 @@ +/* @flow */ + +function foo(text: string | number): string { + switch (typeof text) { +  case 'string': +   return text; + case 'number': + return text; // error, should return string +  default: +   return 'wat'; + } +} + +function bar(text: string | number): string { + switch (typeof text) { + case 'string': + return text[0]; +  default: + return (text++) + ''; + } +} + +function baz1(text: string | number): string { + switch (typeof text) { + case 'number': + case 'string': + return text[0]; // error, [0] on number +  default: + return 'wat'; + } +} + +function baz2(text: string | number): string { + switch (typeof text) { + case 'string': + case 'number': + return text[0]; // error, [0] on number +  default: + return 'wat'; + } +} + +function corge(text: string | number | Array): string { + switch (typeof text) { + case 'object': + return text[0]; + case 'string': + case 'number': + // using ++ since it isn't valid on arrays or strings. + // should only error for string since Array was filtered out. + return (text++) + ''; +  default: + return 'wat'; + } +} diff --git a/tests/refinements/tagged_union.js b/tests/refinements/tagged_union.js new file mode 100644 index 000000000000..19c5c185fb45 --- /dev/null +++ b/tests/refinements/tagged_union.js @@ -0,0 +1,232 @@ +// example 1 + +type Type = Name | ListType; +type Name = {kind: 'Name', value: string}; +type ListType = {kind: 'ListType', name: string}; + +function getTypeASTName(typeAST: Type): string { + if (typeAST.kind === 'Name') { + return typeAST.value; // OK, since typeAST: Name + } else { + return typeAST.name; // OK, since typeAST: ListType + } +} + +// example 2 +import type {ASTNode} from './ast_node'; +var Node = require('./node1'); // Node = "Node1" +function foo(x: ASTNode) { + if (x.kind === Node) { + return x.prop1.charAt(0); // typeAST: Node1, but x.prop1 may be undefined + } + return null; +} + +// example 3 +type Apple = { kind: 'Fruit', taste: 'Bad' } +type Orange = { kind: 'Fruit', taste: 'Good' } +type Broccoli = { kind: 'Veg', taste: 'Bad', raw: 'No' } +type Carrot = { kind: 'Veg', taste: 'Good', raw: 'Maybe' } + +type Breakfast = Apple | Orange | Broccoli | Carrot + +function bar(x: Breakfast) { + if (x.kind === 'Fruit') { (x.taste: 'Good'); } // error, Apple.taste = Bad + else (x.raw: 'No'); // error, Carrot.raw = Maybe +} + +function qux(x: Breakfast) { + if (x.taste === 'Good') { + (x.raw: 'Yes' | 'No'); // 2 errors: + // Orange.raw doesn't exist + // Carrot.raw is neither Yes nor No + } +} + +// example 4 +function list(n) { + if (n > 0) return { kind: "cons", next: list(n-1) }; + return { kind: "nil" }; +} +function length(l) { + switch (l.kind) { + case "cons": return 1 + length(l.next); + default: return 0; + } +} +function check(n) { + if (n >= 0) return (n === (length(list(n)))); + return true; +} + + +// example 5 +var EnumKind = { A: 1, B: 2, C: 3}; +type A = { kind: 1, A: number }; +type B = { kind: 2, B: number }; +type C = { kind: 3, C: number }; +function kind(x: A | B | C): number { + switch (x.kind) { + case EnumKind.A: return x.A; + case EnumKind.B: return x.B; + default: return x.A; // error, x: C and property A not found in type C + } +} +kind({ kind: EnumKind.A, A: 1 }); + +// example 6 +type Citizen = { citizen: true }; +type NonCitizen = { citizen: false, nationality: string } +function nationality(x: Citizen | NonCitizen) { + if (x.citizen) return "Shire" + else return x.nationality; +} + +let tests = [ + // non-existent props + function test7(x: A) { + if (x.kindTypo === 1) { // typos are allowed to be tested + (x.kindTypo: string); // typos can't be used, though + } + }, + + // nested objects + function test8(x: {foo: {bar: 1}}) { + if (x.foo.bar === 1) {} + if (x.fooTypo.bar === 1) {} // error, fooTypo doesn't exist + }, + + // invalid RHS + function(x: A) { + if (x.kind === (null).toString()) {} // error, method on null + if ({kind: 1}.kind === (null).toString()) {} // error, method on null + }, + + // non-objects on LHS + function( + x: Array, y: string, z: number, q: boolean, + r: Object, s: Function, t: () => void + ) { + if (x.length === 0) {} + if (x.legnth === 0) { // typos are allowed to be tested + (x.legnth: number); // inside the block, it's a number + (x.legnth: string); // error: number literal 0 !~> string + } + if (y.length === 0) {} + if (y.legnth === 0) { // typos are allowed to be tested + (y.legnth: number); // inside the block, it's a number + (y.legnth: string); // error: number literal 0 !~> string + } + if (z.toString === 0) {} + if (z.toStirng === 0) { // typos are allowed to be tested + (z.toStirng: number); // inside the block, it's a number + (z.toStirng: string); // error: number literal 0 !~> string + } + if (q.valueOf === 0) {} + if (q.valeuOf === 0) { // typos are allowed to be tested + (q.valeuOf: number); // inside the block, it's a number + (q.valeuOf: string); // error: number literal 0 !~> string + } + if (r.toStirng === 0) { // typos are allowed to be tested + (r.toStirng: empty); // props on AnyObjT are `any` + } + if (s.call === 0) {} + if (s.calll === 0) { // typos are allowed to be tested + (t.calll: empty); // ok, props on functions are `any` :/ + } + if (t.call === 0) {} + if (t.calll === 0) { // typos are allowed to be tested + (t.calll: empty); // ok, props on functions are `any` :/ + } + }, + + // sentinel props become the RHS + function(x: { str: string, num: number, bool: boolean }) { + if (x.str === 'str') { + (x.str: 'not str'); // error: 'str' !~> 'not str' + } + if (x.num === 123) { + (x.num: 456); // error: 123 !~> 456 + } + if (x.bool === true) { + (x.bool: false); // error: true !~> false + } + // even if it doesn't exist... + if (x.badStr === 'bad') { + (x.badStr: empty); // error: 'bad' !~> empty + } + if (x.badNum === 123) { + (x.badNum: empty); // error: 123 !~> empty + } + if (x.badBool === true) { + (x.badBool: empty); // error: true !~> empty + } + }, + + // type mismatch + function(x: { foo: 123, y: string } | { foo: 'foo', z: string }) { + if (x.foo === 123) { + (x.y: string); + x.z; // error + } else { + (x.z: string); + x.y; // error + } + if (x.foo === 'foo') { + (x.z: string); + x.y; // error + } else { + (x.y: string); + x.z; // error + } + }, + + // type mismatch, but one is not a literal + function(x: { foo: number, y: string } | { foo: 'foo', z: string }) { + if (x.foo === 123) { + (x.y: string); // ok, because 123 !== 'foo' + x.z; // error + } else { + x.y; // error: x.foo could be a string + x.z; // error: could still be either case (if foo was a different number) + } + + if (x.foo === 'foo') { + (x.z: string); + x.y; // error + } else { + (x.y: string); + x.z; // error + } + }, + + // type mismatch, neither is a literal + function(x: { foo: number, y: string } | { foo: string, z: string }) { + if (x.foo === 123) { + (x.y: string); // ok, because 123 !== string + x.z; // error + } else { + x.y; // error: x.foo could be a string + x.z; // error: could still be either case (if foo was a different number) + } + + if (x.foo === 'foo') { + (x.z: string); + x.y; // error + } else { + x.y; // error: x.foo could be a different string + x.z; // error: x.foo could be a number + } + }, + + // type mismatch, neither is a literal, test is not a literal either + function( + x: { foo: number, y: string } | { foo: string, z: string }, + num: number + ) { + if (x.foo === num) { + x.y; // error: flow isn't smart enough to figure this out yet + x.z; // error + } + } +]; diff --git a/tests/refinements/tagged_union_import.js b/tests/refinements/tagged_union_import.js new file mode 100644 index 000000000000..e6c39c83ade0 --- /dev/null +++ b/tests/refinements/tagged_union_import.js @@ -0,0 +1,23 @@ +/* @flow */ + +import { SUCCESS, ERROR } from './constants' + +type Success = { + type: typeof SUCCESS, + message: string +} + +type Error = { + type: typeof ERROR, + error: string +} + +function handleStatus(status: Success | Error) { + switch(status.type) { + case SUCCESS: + console.log(`Successful: ${status.message}`); + break; + default: + console.log(`Errored: ${status.error}`); + } +} diff --git a/tests/refinements/typeof.js b/tests/refinements/typeof.js new file mode 100644 index 000000000000..0b1f0da2f72c --- /dev/null +++ b/tests/refinements/typeof.js @@ -0,0 +1,64 @@ +/* @flow */ + +function foo(x: bool | number) { + if (typeof x === "boolean") { + x[0]; // error for boolean, not number + } +} + +function bar(): number { + var x = null; + if (typeof x === "object") { + return x; // error, null + } + return 0; +} + +/* refining globals */ +function fn0() { + if (typeof BAZ !== 'undefined' && + typeof BAZ.stuff === 'function') { + BAZ.stuff(123); + } + BAZ.stuff(123); // error, refinement is gone +} +function fn1() { + BAZ.stuff; // error, could be undefined + if (typeof BAZ !== 'undefined' && + typeof BAZ.stuff === 'function') { + BAZ.stuff(123); // ok + BAZ.stuff(123); // error, refinement is gone + } +} + +function anyfun(x: number | Function): number { + if (typeof x === "function") { + return 0; + } + return x; // OK, x refined to `number` +} + +function anyobj(x: number | Object): number { + if (typeof x === "object") { + return 0; + } + return x; // OK, x refined to `number` +} + +function testInvalidValue(x: mixed) { + if (typeof x === "foo") { // error + return 0; + } +} + +function testTemplateLiteral(x: string | number) { + if (typeof x === `string`) { + return x.length; + } +} + +function testInvalidTemplateLiteral(x: string | number) { + if (typeof x === `foo`) { // error + return 0; + } +} diff --git a/tests/refinements/undef.js b/tests/refinements/undef.js new file mode 100644 index 000000000000..14d1b92309ff --- /dev/null +++ b/tests/refinements/undef.js @@ -0,0 +1,80 @@ +/* @flow */ + +function undef_var(x: ?number) { + if (x !== null && x !== undefined) { + var y = x * 1000; + } +} + +function undef_var_rev(x: ?number) { + if (x === null || x === undefined) { + } else { + var y = x * 1000; + } +} + +function undef_prop(x: { x: ?number }) { + if (x.x !== null && x.x !== undefined) { + var y = x.x * 1000; + } +} + +function undef_prop_rev(x: { x: ?number }) { + if (x.x === null || x.x === undefined) { + } else { + var y = x.x * 1000; + } +} + +function undef_var_fail(x: ?number) { + if (x !== undefined) { + var y = x * 1000; + } +} + +function undef_var_fail_rev(x: ?number) { + if (x === undefined) { + } else { + var y = x * 1000; + } +} + +function undef_prop_fail(x: { x: ?number }) { + if (x.x !== undefined) { + var y = x.x * 1000; + } +} + +function undef_prop_fail_rev(x: { x: ?number }) { + if (x.x === undefined) { + } else { + var y = x.x * 1000; + } +} + +function undef_unreachable(x: number) { + if (x === undefined) { + var y = x * 1000; // unreachable + } + if (x == undefined) { + var z = x * 1000; // unreachable + } +} + +function undef_var_nonstrict(x: ?number, y: ?number) { + if (x != undefined) { + var a = x * 1000; + } + if (y == undefined){ + var b = y * 1000; // error + } +} + +function undef_bogus_comparison() { + if (100 * undefined) { + return; + } + if (undefined * 100) { + return; + } +} diff --git a/tests/refinements/union.js b/tests/refinements/union.js new file mode 100644 index 000000000000..145df02c3bfd --- /dev/null +++ b/tests/refinements/union.js @@ -0,0 +1,21 @@ +/* @flow */ + +type thing = number | bool + +function foo(x: thing) { + if (x === true) { + x[0]; // error on boolean + } +} + +function bar(x: thing) { + if (x !== true && x !== false) { + x[0]; // error on number + } +} + +function baz(x: ?thing) { + if (x && x !== true) { + x[0]; // error on number + } +} diff --git a/tests/refinements/void.js b/tests/refinements/void.js new file mode 100644 index 000000000000..87d3a8af8644 --- /dev/null +++ b/tests/refinements/void.js @@ -0,0 +1,95 @@ +/* @flow */ + +function void_var(x: ?number) { + if (x !== null && x !== void(0)) { + var y = x * 1000; + } +} + +function void_var_rev(x: ?number) { + if (x === null || x === void(0)) { + } else { + var y = x * 1000; + } +} + +function void_pro(x: { x: ?number }) { + if (x.x !== null && x.x !== void(0)) { + var y = x.x * 1000; + } +} + +function void_pro_rev(x: { x: ?number }) { + if (x.x === null || x.x === void(0)) { + } else { + var y = x.x * 1000; + } +} + +function void_var_fail(x: ?number) { + if (x !== void(0)) { + var y = x * 1000; + } +} + +function void_var_fail_rev(x: ?number) { + if (x === void(0)) { + } else { + var y = x * 1000; + } +} + +function void_pro_fail(x: { x: ?number }) { + if (x.x !== void(0)) { + var y = x.x * 1000; + } +} + +function void_pro_fail_rev(x: { x: ?number }) { + if (x.x === void(0)) { + } else { + var y = x.x * 1000; + } +} + +function void_var_side_effect(x: ?number) { + if (x !== null && x !== void(x * 1000)) { + var y = x * 1000; + } +} + +function void_var_side_effect_rev(x: ?number) { + if (x === null || x === void(x * 1000)) { + } else { + var y = x * 1000; + } +} + +function void_prop_side_effect(x: { x: ?number }) { + if (x.x !== null && x.x !== void(x.x * 1000)) { + var y = x.x * 1000; + } +} + +function void_prop_side_effect_rev(x: { x: ?number }) { + if (x.x === null || x.x === void(x.x * 1000)) { + } else { + var y = x.x * 1000; + } +} + +function void_bogus_comparison() { + if (100 * void(0)) { + return; + } + if (void(0) * 100) { + return; + } +} + +function void_redefined_undefined(x: ?number) { + var undefined = "foo"; + if (x !== null && x !== void(0)) { + var y = x * 1000; + } +} diff --git a/tests/reflection/__snapshots__/jsfmt.spec.js.snap b/tests/reflection/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..370bc1f8b9fb --- /dev/null +++ b/tests/reflection/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,18 @@ +exports[`test type.js 1`] = ` +"declare var a: number; +var b: typeof a = "..."; +var c: typeof a = "..."; + +type T = number; +var x:T = "..."; + +// what about recursive unions? +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare var a: number; +var b: typeof a = "..."; +var c: typeof a = "..."; +type T = number; +var x: T = "...";// what about recursive unions? + +" +`; diff --git a/tests/reflection/jsfmt.spec.js b/tests/reflection/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/reflection/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/reflection/type.js b/tests/reflection/type.js new file mode 100644 index 000000000000..de8cd6ed4804 --- /dev/null +++ b/tests/reflection/type.js @@ -0,0 +1,8 @@ +declare var a: number; +var b: typeof a = "..."; +var c: typeof a = "..."; + +type T = number; +var x:T = "..."; + +// what about recursive unions? diff --git a/tests/regexp/__snapshots__/jsfmt.spec.js.snap b/tests/regexp/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..d61d4407d641 --- /dev/null +++ b/tests/regexp/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,9 @@ +exports[`test regexp.js 1`] = ` +"var patt=/Hello/g +var match:number = patt.test("Hello world!"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var patt = /Hello/g; +var match: number = patt.test("Hello world!"); + +" +`; diff --git a/tests/regexp/jsfmt.spec.js b/tests/regexp/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/regexp/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/regexp/regexp.js b/tests/regexp/regexp.js new file mode 100644 index 000000000000..c8b2340ac812 --- /dev/null +++ b/tests/regexp/regexp.js @@ -0,0 +1,2 @@ +var patt=/Hello/g +var match:number = patt.test("Hello world!"); diff --git a/tests/replace/__snapshots__/jsfmt.spec.js.snap b/tests/replace/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..62ba462c75d7 --- /dev/null +++ b/tests/replace/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,15 @@ +exports[`test test.js 1`] = ` +"var a = 0; + +function foo(x) { } + +foo(""); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var a = 0; +function foo(x) { + +} +foo(""); + +" +`; diff --git a/tests/replace/jsfmt.spec.js b/tests/replace/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/replace/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/replace/test.js b/tests/replace/test.js new file mode 100644 index 000000000000..8a4904c12fa7 --- /dev/null +++ b/tests/replace/test.js @@ -0,0 +1,5 @@ +var a = 0; + +function foo(x) { } + +foo(""); diff --git a/tests/require/B.js b/tests/require/B.js new file mode 100644 index 000000000000..e4d0f1b41f44 --- /dev/null +++ b/tests/require/B.js @@ -0,0 +1,3 @@ +/* @flow */ + +exports.numberValue = 42; diff --git a/tests/require/C.js b/tests/require/C.js new file mode 100644 index 000000000000..e667c4717b69 --- /dev/null +++ b/tests/require/C.js @@ -0,0 +1 @@ +/* @flow */ diff --git a/tests/require/E.js b/tests/require/E.js new file mode 100644 index 000000000000..7d408be6436e --- /dev/null +++ b/tests/require/E.js @@ -0,0 +1,10 @@ +/* @flow */ + +// Local `exports` var is just a ref to module.exports, so mutating the original +// value will affect the exports object but re-binding it makes it useless and +// does not affect the exports value. +module.exports = { + numberValue: 42 +}; + +exports = {stringValue: ''}; diff --git a/tests/require/ProvidesModuleA.js b/tests/require/ProvidesModuleA.js new file mode 100644 index 000000000000..3c651145d2f5 --- /dev/null +++ b/tests/require/ProvidesModuleA.js @@ -0,0 +1,6 @@ +/** + * @providesModule A + * @flow + */ + +exports.numberValue = 42; diff --git a/tests/require/ProvidesModuleD.js b/tests/require/ProvidesModuleD.js new file mode 100644 index 000000000000..a4d5ee842062 --- /dev/null +++ b/tests/require/ProvidesModuleD.js @@ -0,0 +1,4 @@ +/** + * @providesModule D + * @flow + */ diff --git a/tests/require/__snapshots__/jsfmt.spec.js.snap b/tests/require/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..0ce3d84b8ecb --- /dev/null +++ b/tests/require/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,168 @@ +exports[`test B.js 1`] = ` +"/* @flow */ + +exports.numberValue = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +exports.numberValue = 42; + +" +`; + +exports[`test C.js 1`] = ` +"/* @flow */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test E.js 1`] = ` +"/* @flow */ + +// Local \`exports\` var is just a ref to module.exports, so mutating the original +// value will affect the exports object but re-binding it makes it useless and +// does not affect the exports value. +module.exports = { + numberValue: 42 +}; + +exports = {stringValue: ''}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// Local \`exports\` var is just a ref to module.exports, so mutating the original +// value will affect the exports object but re-binding it makes it useless and +// does not affect the exports value. +module.exports = { numberValue: 42 }; +exports = { stringValue: "" }; + +" +`; + +exports[`test ProvidesModuleA.js 1`] = ` +"/** + * @providesModule A + * @flow + */ + +exports.numberValue = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule A + * @flow + */ +exports.numberValue = 42; + +" +`; + +exports[`test ProvidesModuleD.js 1`] = ` +"/** + * @providesModule D + * @flow + */ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +" +`; + +exports[`test not_builtin_require.js 1`] = ` +"// @flow + +function require() {} +require("not a module name"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function require() { + +} +require("not a module name"); + +" +`; + +exports[`test not_builtin_require2.js 1`] = ` +"// @flow + +type require = number; +var a: require = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +type require = number; +var a: require = 42; + +" +`; + +exports[`test require.js 1`] = ` +"/* @flow */ + +function takesANumber(num: number): void {} +function takesAString(str: string): void {} + +// @providesModule +var A = require("A"); +takesANumber(A.numberValue); +takesAString(A.numberValue); + +// File path +var B = require("./B"); +takesANumber(B.numberValue); +takesAString(B.numberValue); + +// C.js exists, but not as a providesModule +require("C"); + +// @providesModule D exists, but not as a filename +require("./D"); + +// E exports an object with a numVal property +var E = require('./E'); +var e_1: number = E.numberValue; +E.stringValue; // Error: The E exports obj has no 'stringValue' property + +// We require that the param passed to require() be a string literal to support +// guaranteed static extraction +var a = './E'; +require(a); // Error: Param must be string literal +require(\`./E\`); // template literals are ok... +require(\`\${'./E'}\`); // error: but only if they have no expressions + +// require.call is allowed but circumverts Flow's static analysis +require.call(null, "DoesNotExist"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function takesANumber(num: number): void { + +} +function takesAString(str: string): void { + +} +// @providesModule +var A = require("A"); +takesANumber(A.numberValue); +takesAString(A.numberValue); +// File path +var B = require("./B"); +takesANumber(B.numberValue); +takesAString(B.numberValue); +// C.js exists, but not as a providesModule +require("C"); +// @providesModule D exists, but not as a filename +require("./D"); +// E exports an object with a numVal property +var E = require("./E"); +var e_1: number = E.numberValue; +E.stringValue;// Error: The E exports obj has no 'stringValue' property +// We require that the param passed to require() be a string literal to support +// guaranteed static extraction +var a = "./E"; +require(a);// Error: Param must be string literal +require(\`./E\`);// template literals are ok... +require(\`\${"./E"}\`);// error: but only if they have no expressions +// require.call is allowed but circumverts Flow's static analysis +require.call(null, "DoesNotExist"); + +" +`; diff --git a/tests/require/jsfmt.spec.js b/tests/require/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/require/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/require/not_builtin_require.js b/tests/require/not_builtin_require.js new file mode 100644 index 000000000000..3671905918bb --- /dev/null +++ b/tests/require/not_builtin_require.js @@ -0,0 +1,4 @@ +// @flow + +function require() {} +require("not a module name"); diff --git a/tests/require/not_builtin_require2.js b/tests/require/not_builtin_require2.js new file mode 100644 index 000000000000..682bd304ecb4 --- /dev/null +++ b/tests/require/not_builtin_require2.js @@ -0,0 +1,4 @@ +// @flow + +type require = number; +var a: require = 42; diff --git a/tests/require/require.js b/tests/require/require.js new file mode 100644 index 000000000000..1628df536d39 --- /dev/null +++ b/tests/require/require.js @@ -0,0 +1,35 @@ +/* @flow */ + +function takesANumber(num: number): void {} +function takesAString(str: string): void {} + +// @providesModule +var A = require("A"); +takesANumber(A.numberValue); +takesAString(A.numberValue); + +// File path +var B = require("./B"); +takesANumber(B.numberValue); +takesAString(B.numberValue); + +// C.js exists, but not as a providesModule +require("C"); + +// @providesModule D exists, but not as a filename +require("./D"); + +// E exports an object with a numVal property +var E = require('./E'); +var e_1: number = E.numberValue; +E.stringValue; // Error: The E exports obj has no 'stringValue' property + +// We require that the param passed to require() be a string literal to support +// guaranteed static extraction +var a = './E'; +require(a); // Error: Param must be string literal +require(`./E`); // template literals are ok... +require(`${'./E'}`); // error: but only if they have no expressions + +// require.call is allowed but circumverts Flow's static analysis +require.call(null, "DoesNotExist"); diff --git a/tests/requireLazy/A.js b/tests/requireLazy/A.js new file mode 100644 index 000000000000..37d71689d456 --- /dev/null +++ b/tests/requireLazy/A.js @@ -0,0 +1,9 @@ +/** + * @providesModule A + * @flow + */ + +module.exports = { + numberValueA: 1, + stringValueA: "someString" +}; diff --git a/tests/requireLazy/B.js b/tests/requireLazy/B.js new file mode 100644 index 000000000000..d125081a8a9b --- /dev/null +++ b/tests/requireLazy/B.js @@ -0,0 +1,9 @@ +/** + * @providesModule B + * @flow + */ + +module.exports = { + numberValueB: 1, + stringValueB: "someString" +}; diff --git a/tests/requireLazy/__snapshots__/jsfmt.spec.js.snap b/tests/requireLazy/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..c3f58bdfdcc6 --- /dev/null +++ b/tests/requireLazy/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,93 @@ +exports[`test A.js 1`] = ` +"/** + * @providesModule A + * @flow + */ + +module.exports = { + numberValueA: 1, + stringValueA: "someString" +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule A + * @flow + */ +module.exports = { numberValueA: 1, stringValueA: "someString" }; + +" +`; + +exports[`test B.js 1`] = ` +"/** + * @providesModule B + * @flow + */ + +module.exports = { + numberValueB: 1, + stringValueB: "someString" +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule B + * @flow + */ +module.exports = { numberValueB: 1, stringValueB: "someString" }; + +" +`; + +exports[`test requireLazy.js 1`] = ` +"/** + * @flow + */ + +requireLazy(['A', 'B'], function(A, B) { + var num1: number = A.numberValueA; + var str1: string = A.stringValueA; + var num2: number = A.stringValueA; // Error: string ~> number + var str2: string = A.numberValueA; // Error: number ~> string + + var num3: number = B.numberValueB; + var str3: string = B.stringValueB; + var num4: number = B.stringValueB; // Error: string ~> number + var str4: string = B.numberValueB; // Error: number ~> string +}); + +var notA: Object = A; +var notB: Object = B; + +requireLazy(); // Error: No args +requireLazy([nope], function() {}); // Error: Non-stringliteral args +requireLazy(['A']); // Error: No calback expression +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +requireLazy( + [ "A", "B" ], + function(A, B) { + var num1: number = A.numberValueA; + var str1: string = A.stringValueA; + var num2: number = A.stringValueA;// Error: string ~> number + var str2: string = A.numberValueA;// Error: number ~> string + var num3: number = B.numberValueB; + var str3: string = B.stringValueB; + var num4: number = B.stringValueB;// Error: string ~> number + var str4: string = B.numberValueB;// Error: number ~> string + } +); +var notA: Object = A; +var notB: Object = B; +requireLazy();// Error: No args +requireLazy( + [ nope ], + function() { + + } +);// Error: Non-stringliteral args +requireLazy([ "A" ]);// Error: No calback expression + +" +`; diff --git a/tests/requireLazy/jsfmt.spec.js b/tests/requireLazy/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/requireLazy/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/requireLazy/requireLazy.js b/tests/requireLazy/requireLazy.js new file mode 100644 index 000000000000..4bc44c3a87df --- /dev/null +++ b/tests/requireLazy/requireLazy.js @@ -0,0 +1,22 @@ +/** + * @flow + */ + +requireLazy(['A', 'B'], function(A, B) { + var num1: number = A.numberValueA; + var str1: string = A.stringValueA; + var num2: number = A.stringValueA; // Error: string ~> number + var str2: string = A.numberValueA; // Error: number ~> string + + var num3: number = B.numberValueB; + var str3: string = B.stringValueB; + var num4: number = B.stringValueB; // Error: string ~> number + var str4: string = B.numberValueB; // Error: number ~> string +}); + +var notA: Object = A; +var notB: Object = B; + +requireLazy(); // Error: No args +requireLazy([nope], function() {}); // Error: Non-stringliteral args +requireLazy(['A']); // Error: No calback expression diff --git a/tests/return/__snapshots__/jsfmt.spec.js.snap b/tests/return/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a71e2ce54cd6 --- /dev/null +++ b/tests/return/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,104 @@ +exports[`test function_return.js 1`] = ` +"class C { + foo() { } + bar() { return; } + fn(x:number) { return x; } +} + +function f(x): number { + if (x > 1) { + return 42; + } +} + +function g(x): ?number { + if (x > 1) { + return 42; + } +} + +function h(x): number { + if (x > 1) { + return 42; + } + return; +} + +function i(x): ?number { + if (x > 1) { + return 42; + } + return; +} + +module.exports = C; + +//function fn(x:number) { return x; } +//module.exports = fn; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + foo() { + + } + bar() { + return; + } + fn(x: number) { + return x; + } +} +function f(x): number { + if (x > 1) { + return 42; + } +} +function g(x): ?number { + if (x > 1) { + return 42; + } +} +function h(x): number { + if (x > 1) { + return 42; + } + return; +} +function i(x): ?number { + if (x > 1) { + return 42; + } + return; +} +module.exports = C;//function fn(x:number) { return x; }//module.exports = fn; + +" +`; + +exports[`test void.js 1`] = ` +"/* This is a regression test. At one point we incorrectly inferred the return + type of functions that have an explicit \`undefined\` to be only \`undefined\` -- + ignoring other possible exits. */ +function f(b) { + if (b) { + return undefined; + } else { + return "nope"; + } +} + +(f(true): void); // error: string ~> void +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* This is a regression test. At one point we incorrectly inferred the return + type of functions that have an explicit \`undefined\` to be only \`undefined\` -- + ignoring other possible exits. */ +function f(b) { + if (b) { + return undefined; + } else { + return "nope"; + } +} +(f(true): void);// error: string ~> void + +" +`; diff --git a/tests/return/function_return.js b/tests/return/function_return.js new file mode 100644 index 000000000000..3667ad5d982e --- /dev/null +++ b/tests/return/function_return.js @@ -0,0 +1,36 @@ +class C { + foo() { } + bar() { return; } + fn(x:number) { return x; } +} + +function f(x): number { + if (x > 1) { + return 42; + } +} + +function g(x): ?number { + if (x > 1) { + return 42; + } +} + +function h(x): number { + if (x > 1) { + return 42; + } + return; +} + +function i(x): ?number { + if (x > 1) { + return 42; + } + return; +} + +module.exports = C; + +//function fn(x:number) { return x; } +//module.exports = fn; diff --git a/tests/return/jsfmt.spec.js b/tests/return/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/return/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/return/void.js b/tests/return/void.js new file mode 100644 index 000000000000..6bfe74a3f6ce --- /dev/null +++ b/tests/return/void.js @@ -0,0 +1,12 @@ +/* This is a regression test. At one point we incorrectly inferred the return + type of functions that have an explicit `undefined` to be only `undefined` -- + ignoring other possible exits. */ +function f(b) { + if (b) { + return undefined; + } else { + return "nope"; + } +} + +(f(true): void); // error: string ~> void diff --git a/tests/return_new/__snapshots__/jsfmt.spec.js.snap b/tests/return_new/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f4fda93a6822 --- /dev/null +++ b/tests/return_new/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,65 @@ +exports[`test test.js 1`] = ` +"function Foo() { return {}; } +var foo: number = new Foo(); // error (returns object literal above) + +function Bar() { return 0; } +var bar: number = new Bar(); // error (returns new object) + +function Qux() { } +var qux: number = new Qux(); // error (returns new object) + +class A { } +function B() { return new A(); } +var a: A = new B(); // OK (returns new A) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function Foo() { + return {}; +} +var foo: number = new Foo();// error (returns object literal above) +function Bar() { + return 0; +} +var bar: number = new Bar();// error (returns new object) +function Qux() { + +} +var qux: number = new Qux();// error (returns new object) +class A {} +function B() { + return new A(); +} +var a: A = new B();// OK (returns new A) + +" +`; + +exports[`test test2.js 1`] = ` +"declare class D { + constructor(): { x: number }; // OK + y: any; +} + +var d = new D(); +d.x = \"\"; // error, string ~/~ number (but property x is found) + +(new D: D); // error, new D is an object, D not in proto chain + +module.exports = D; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/return_new/jsfmt.spec.js b/tests/return_new/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/return_new/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/return_new/test.js b/tests/return_new/test.js new file mode 100644 index 000000000000..ba0f36f87353 --- /dev/null +++ b/tests/return_new/test.js @@ -0,0 +1,12 @@ +function Foo() { return {}; } +var foo: number = new Foo(); // error (returns object literal above) + +function Bar() { return 0; } +var bar: number = new Bar(); // error (returns new object) + +function Qux() { } +var qux: number = new Qux(); // error (returns new object) + +class A { } +function B() { return new A(); } +var a: A = new B(); // OK (returns new A) diff --git a/tests/return_new/test2.js b/tests/return_new/test2.js new file mode 100644 index 000000000000..8e961a2addd5 --- /dev/null +++ b/tests/return_new/test2.js @@ -0,0 +1,11 @@ +declare class D { + constructor(): { x: number }; // OK + y: any; +} + +var d = new D(); +d.x = ""; // error, string ~/~ number (but property x is found) + +(new D: D); // error, new D is an object, D not in proto chain + +module.exports = D; diff --git a/tests/seal/__snapshots__/jsfmt.spec.js.snap b/tests/seal/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8a555f736668 --- /dev/null +++ b/tests/seal/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,33 @@ +exports[`test imp.js 1`] = ` +"/* @flow */ + +var imp = require('./obj_annot'); +imp({ name: "imp" }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var imp = require("./obj_annot"); +imp({ name: "imp" }); + +" +`; + +exports[`test obj_annot.js 1`] = ` +"/* @flow */ + +function foo(param: { name: string; }): number { + return param.id; +} + +foo({ name: "test" }); + +module.exports = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo(param: { name: string }): number { + return param.id; +} +foo({ name: "test" }); +module.exports = foo; + +" +`; diff --git a/tests/seal/imp.js b/tests/seal/imp.js new file mode 100644 index 000000000000..caae6a1bc613 --- /dev/null +++ b/tests/seal/imp.js @@ -0,0 +1,4 @@ +/* @flow */ + +var imp = require('./obj_annot'); +imp({ name: "imp" }); diff --git a/tests/seal/jsfmt.spec.js b/tests/seal/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/seal/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/seal/obj_annot.js b/tests/seal/obj_annot.js new file mode 100644 index 000000000000..7df3e9ee6615 --- /dev/null +++ b/tests/seal/obj_annot.js @@ -0,0 +1,9 @@ +/* @flow */ + +function foo(param: { name: string; }): number { + return param.id; +} + +foo({ name: "test" }); + +module.exports = foo; diff --git a/tests/sealed/__snapshots__/jsfmt.spec.js.snap b/tests/sealed/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9583e539e32b --- /dev/null +++ b/tests/sealed/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,88 @@ +exports[`test function.js 1`] = ` +"/* @flow */ + +function Bar(x: number) { + this.x = x; +} +Bar.prototype.getX = function() { return this.x; } +Bar.prototype.getY = function(): string { return this.y; } + +module.exports = Bar; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function Bar(x: number) { + this.x = x; +} +Bar.prototype.getX = function() { + return this.x; +}; +Bar.prototype.getY = function(): string { + return this.y; +}; +module.exports = Bar; + +" +`; + +exports[`test proto.js 1`] = ` +"function Foo() { } +var o = new Foo(); +var x:number = o.x; + +Foo.prototype.m = function() { return this.x; } + +var y:number = o.m(); +o.x = "..."; + +Foo.prototype = { m: function() { return false; } } + +var export_o: { x:any; } = o; // awkward type cast + +module.exports = export_o; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function Foo() { + +} +var o = new Foo(); +var x: number = o.x; +Foo.prototype.m = function() { + return this.x; +}; +var y: number = o.m(); +o.x = "..."; +Foo.prototype = { + m: function() { + return false; + } +}; +var export_o: { x: any } = o;// awkward type cast +module.exports = export_o; + +" +`; + +exports[`test sealed.js 1`] = ` +"var o = require('./proto'); + +o.z = 0; +var x:string = o.x; + +var Bar = require('./function'); +var a = new Bar(234); +a.x = 123; +a.y = 'abc'; // error, needs to be declared in Bar's constructor +(a.getX(): number); +(a.getY(): string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = require("./proto"); +o.z = 0; +var x: string = o.x; +var Bar = require("./function"); +var a = new Bar(234); +a.x = 123; +a.y = "abc";// error, needs to be declared in Bar's constructor +(a.getX(): number); +(a.getY(): string); + +" +`; diff --git a/tests/sealed/function.js b/tests/sealed/function.js new file mode 100644 index 000000000000..ebfacc5c5e0c --- /dev/null +++ b/tests/sealed/function.js @@ -0,0 +1,9 @@ +/* @flow */ + +function Bar(x: number) { + this.x = x; +} +Bar.prototype.getX = function() { return this.x; } +Bar.prototype.getY = function(): string { return this.y; } + +module.exports = Bar; diff --git a/tests/sealed/jsfmt.spec.js b/tests/sealed/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/sealed/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/sealed/proto.js b/tests/sealed/proto.js new file mode 100644 index 000000000000..c14fa9e28891 --- /dev/null +++ b/tests/sealed/proto.js @@ -0,0 +1,14 @@ +function Foo() { } +var o = new Foo(); +var x:number = o.x; + +Foo.prototype.m = function() { return this.x; } + +var y:number = o.m(); +o.x = "..."; + +Foo.prototype = { m: function() { return false; } } + +var export_o: { x:any; } = o; // awkward type cast + +module.exports = export_o; diff --git a/tests/sealed/sealed.js b/tests/sealed/sealed.js new file mode 100644 index 000000000000..82c955333c94 --- /dev/null +++ b/tests/sealed/sealed.js @@ -0,0 +1,11 @@ +var o = require('./proto'); + +o.z = 0; +var x:string = o.x; + +var Bar = require('./function'); +var a = new Bar(234); +a.x = 123; +a.y = 'abc'; // error, needs to be declared in Bar's constructor +(a.getX(): number); +(a.getY(): string); diff --git a/tests/sealed_objects/__snapshots__/jsfmt.spec.js.snap b/tests/sealed_objects/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..bba2a19de525 --- /dev/null +++ b/tests/sealed_objects/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,40 @@ +exports[`test test.js 1`] = ` +"var o1 = { x: 0 }; +var s1: string = o1.y; // error + +var o2: { x: number; y?: string; } = { x: 0 }; +var s2: string = o2.y || ""; // ok + +var o3: { x: number; y?: string; } = ({ x: 0, y: 0 }: { x: number; }); +var s3: string = o3.y || ""; // error + +var o4: { x: number; y?: string; } = ({ x: 0 }: { x: number; [_:any]:any}); +var s4: string = o4.y || ""; // ok + +var o5 = { x: 0, ...{} }; +var s5: string = o5.y; // ok (spreads make object types extensible) + +var o6: { x: number; [_:any]:any } = { x: 0 }; +var s6: string = o6.y; // ok (indexers make object types extensible) + +var o7: { x: number; y?: string; } = ({ x: 0, y: 0 }: { x: number; [_:any]:number}); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o1 = { x: 0 }; +var s1: string = o1.y;// error +var o2: { x: number, y?: string } = { x: 0 }; +var s2: string = o2.y || "";// ok +var o3: { x: number, y?: string } = ({ x: 0, y: 0 }: { x: number }); +var s3: string = o3.y || "";// error +var o4: { x: number, y?: string } = ({ x: 0 }: { [_: any]: any, x: number }); +var s4: string = o4.y || "";// ok +var o5 = { x: 0, ...{} }; +var s5: string = o5.y;// ok (spreads make object types extensible) +var o6: { [_: any]: any, x: number } = { x: 0 }; +var s6: string = o6.y;// ok (indexers make object types extensible) +var o7: { x: number, y?: string } = ({ x: 0, y: 0 }: { + [_: any]: number, + x: number +});// error + +" +`; diff --git a/tests/sealed_objects/jsfmt.spec.js b/tests/sealed_objects/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/sealed_objects/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/sealed_objects/test.js b/tests/sealed_objects/test.js new file mode 100644 index 000000000000..746ef5d81951 --- /dev/null +++ b/tests/sealed_objects/test.js @@ -0,0 +1,19 @@ +var o1 = { x: 0 }; +var s1: string = o1.y; // error + +var o2: { x: number; y?: string; } = { x: 0 }; +var s2: string = o2.y || ""; // ok + +var o3: { x: number; y?: string; } = ({ x: 0, y: 0 }: { x: number; }); +var s3: string = o3.y || ""; // error + +var o4: { x: number; y?: string; } = ({ x: 0 }: { x: number; [_:any]:any}); +var s4: string = o4.y || ""; // ok + +var o5 = { x: 0, ...{} }; +var s5: string = o5.y; // ok (spreads make object types extensible) + +var o6: { x: number; [_:any]:any } = { x: 0 }; +var s6: string = o6.y; // ok (indexers make object types extensible) + +var o7: { x: number; y?: string; } = ({ x: 0, y: 0 }: { x: number; [_:any]:number}); // error diff --git a/tests/shape/__snapshots__/jsfmt.spec.js.snap b/tests/shape/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6797d7f4a419 --- /dev/null +++ b/tests/shape/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,26 @@ +exports[`test test.js 1`] = ` +"type Foo = { + field: number, +} + +var x: {field?: number} = {}; +var y: $Shape = x; +(y.field: number) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/shape/jsfmt.spec.js b/tests/shape/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/shape/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/shape/test.js b/tests/shape/test.js new file mode 100644 index 000000000000..c71770f50278 --- /dev/null +++ b/tests/shape/test.js @@ -0,0 +1,7 @@ +type Foo = { + field: number, +} + +var x: {field?: number} = {}; +var y: $Shape = x; +(y.field: number) diff --git a/tests/simple_arrays/__snapshots__/jsfmt.spec.js.snap b/tests/simple_arrays/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..53a54ba638f7 --- /dev/null +++ b/tests/simple_arrays/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,77 @@ +exports[`test array.js 1`] = ` +"/* @flow */ +var a = []; +for (var i = 0; i < 10; ++i) { + if (i % 2 == 0) { a[i] = 0; } + else { a[i] = ''; }; +} + +// \`i\` never gets a lower bound, so the array access is stalled until the +// function is called. +function foo(i): string { return a[i]; } + +// here, because we call \`bar\`, we the array access constraint is discharged and +// we realize a type error. +function bar(i): string { return a[i]; } +bar(0); + +// annotations suffice to unblock the access constraint as well, so only +// uncalled internal functions will not find a type error, which is acceptable +// behavior as such functions are dead code. +function baz(i:number): string { return a[i]; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var a = [ ]; +for (var i = 0; i < 10; ++i) { + if (i % 2 == 0) { + a[i] = 0; + } else { + a[i] = ""; + } +} +// \`i\` never gets a lower bound, so the array access is stalled until the +// function is called. +function foo(i): string { + return a[i]; +} +// here, because we call \`bar\`, we the array access constraint is discharged and +// we realize a type error. +function bar(i): string { + return a[i]; +} +bar(0); +// annotations suffice to unblock the access constraint as well, so only +// uncalled internal functions will not find a type error, which is acceptable +// behavior as such functions are dead code. +function baz(i: number): string { + return a[i]; +} + +" +`; + +exports[`test array2.js 1`] = ` +"/* @flow */ +var a = []; +for (var i = 0; i < 10; ++i) { + if (i % 2 == 0) { a[i] = 0; } + else { a[i] = ''; }; +} + +function foo(i: number): string { return a[i]; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var a = [ ]; +for (var i = 0; i < 10; ++i) { + if (i % 2 == 0) { + a[i] = 0; + } else { + a[i] = ""; + } +} +function foo(i: number): string { + return a[i]; +} + +" +`; diff --git a/tests/simple_arrays/array.js b/tests/simple_arrays/array.js new file mode 100644 index 000000000000..c44a1442b19c --- /dev/null +++ b/tests/simple_arrays/array.js @@ -0,0 +1,20 @@ +/* @flow */ +var a = []; +for (var i = 0; i < 10; ++i) { + if (i % 2 == 0) { a[i] = 0; } + else { a[i] = ''; }; +} + +// `i` never gets a lower bound, so the array access is stalled until the +// function is called. +function foo(i): string { return a[i]; } + +// here, because we call `bar`, we the array access constraint is discharged and +// we realize a type error. +function bar(i): string { return a[i]; } +bar(0); + +// annotations suffice to unblock the access constraint as well, so only +// uncalled internal functions will not find a type error, which is acceptable +// behavior as such functions are dead code. +function baz(i:number): string { return a[i]; } diff --git a/tests/simple_arrays/array2.js b/tests/simple_arrays/array2.js new file mode 100644 index 000000000000..b42ec500eac3 --- /dev/null +++ b/tests/simple_arrays/array2.js @@ -0,0 +1,8 @@ +/* @flow */ +var a = []; +for (var i = 0; i < 10; ++i) { + if (i % 2 == 0) { a[i] = 0; } + else { a[i] = ''; }; +} + +function foo(i: number): string { return a[i]; } diff --git a/tests/simple_arrays/jsfmt.spec.js b/tests/simple_arrays/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/simple_arrays/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/singleton/__snapshots__/jsfmt.spec.js.snap b/tests/singleton/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..882d3227ca6f --- /dev/null +++ b/tests/singleton/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,117 @@ +exports[`test boolean.js 1`] = ` +"/* @flow */ + +function veryOptimistic(isThisAwesome: true): boolean { + return isThisAwesome; +} + +var x : boolean = veryOptimistic(true); +var y : boolean = veryOptimistic(false); // error + +function veryPessimistic(isThisAwesome: true): boolean { + return !isThisAwesome; // test bool conversion +} + +var x : boolean = veryPessimistic(true); +var y : boolean = veryPessimistic(false); // error + +type MyOwnBooleanLOL = true | false + +function bar(x: MyOwnBooleanLOL): false { + if (x) { + return x; + } else { + return !x; + } +} + +bar(true); +bar(false); +bar(1); // error + +function alwaysFalsy(x: boolean): false { + if (x) { + return !x; + } else { + return x; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test number.js 1`] = ` +"/* @flow */ + +function highlander(howMany: 1): number { + return howMany; // there can be only one! +} + +highlander(1); +highlander(2); // error + + +type Foo = 1 | 2 + +function bar(num: Foo): number { + return num + 1; +} + +bar(1); +bar(2); +bar(3); // error + +type ComparatorResult = -1 | 0 | 1 +function sort(fn: (x: any, y: any) => ComparatorResult) {} +sort((x, y) => -1); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 42, end: 43, loc: [object Object], value: 1, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; + +exports[`test string.js 1`] = ` +"/* @flow */ + +type NoSpaces = \"foobar\" +(\"foobar\": NoSpaces); + +type HasSpaces = \"foo bar\" +(\"foo bar\": HasSpaces); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +type NoSpaces = \"foobar\"; +(\"foobar\": NoSpaces); +type HasSpaces = \"foo bar\"; +(\"foo bar\": HasSpaces); + +" +`; diff --git a/tests/singleton/boolean.js b/tests/singleton/boolean.js new file mode 100644 index 000000000000..dede9679e160 --- /dev/null +++ b/tests/singleton/boolean.js @@ -0,0 +1,37 @@ +/* @flow */ + +function veryOptimistic(isThisAwesome: true): boolean { + return isThisAwesome; +} + +var x : boolean = veryOptimistic(true); +var y : boolean = veryOptimistic(false); // error + +function veryPessimistic(isThisAwesome: true): boolean { + return !isThisAwesome; // test bool conversion +} + +var x : boolean = veryPessimistic(true); +var y : boolean = veryPessimistic(false); // error + +type MyOwnBooleanLOL = true | false + +function bar(x: MyOwnBooleanLOL): false { + if (x) { + return x; + } else { + return !x; + } +} + +bar(true); +bar(false); +bar(1); // error + +function alwaysFalsy(x: boolean): false { + if (x) { + return !x; + } else { + return x; + } +} diff --git a/tests/singleton/jsfmt.spec.js b/tests/singleton/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/singleton/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/singleton/number.js b/tests/singleton/number.js new file mode 100644 index 000000000000..160e9223d340 --- /dev/null +++ b/tests/singleton/number.js @@ -0,0 +1,23 @@ +/* @flow */ + +function highlander(howMany: 1): number { + return howMany; // there can be only one! +} + +highlander(1); +highlander(2); // error + + +type Foo = 1 | 2 + +function bar(num: Foo): number { + return num + 1; +} + +bar(1); +bar(2); +bar(3); // error + +type ComparatorResult = -1 | 0 | 1 +function sort(fn: (x: any, y: any) => ComparatorResult) {} +sort((x, y) => -1); diff --git a/tests/singleton/string.js b/tests/singleton/string.js new file mode 100644 index 000000000000..aac4a5c70372 --- /dev/null +++ b/tests/singleton/string.js @@ -0,0 +1,7 @@ +/* @flow */ + +type NoSpaces = "foobar" +("foobar": NoSpaces); + +type HasSpaces = "foo bar" +("foo bar": HasSpaces); diff --git a/tests/spread/__snapshots__/jsfmt.spec.js.snap b/tests/spread/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6267c1718017 --- /dev/null +++ b/tests/spread/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,225 @@ +exports[`test test.js 1`] = ` +"function parseTimestamp(timestamp: string): number { + return 0; +} + +function parseCounter(line: string): number { + return 0; +} + +function parseGroup(lines: Array): { + counter: number; + begin: number; + end: number; + text: string; +} { + var counter = parseCounter(lines[0]); + var timeframe = parseTimeframe(lines[1]); + return { + counter, + ...timeframe, + text: lines[2] + }; +} + +function parseTimeframe(line: string): { begin: number; end: number } { + var timestamps = line.split(\'-->\'); + return { + begin: parseTimestamp(timestamps[0].trim()), + end: parseTimestamp(timestamps[1].trim()) + }; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"/** + * @flow + */ + +function foo(o) { + bar({...o}); +} +function bar(_: {foo:number}) { } +foo({foo: 42}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +function foo(o) { + bar({ ...o }); +} +function bar(_: { foo: number }) { + +} +foo({ foo: 42 }); + +" +`; + +exports[`test test3.js 1`] = ` +"var p = { y: \"\" }; +var q = { z: \"\" }; +var o = { + x: 5, + ...p, + ...q, +}; +var y: number = o.y; +var z: number = o.z; + +// test conflicting keys (they get unioned) +var r = { y: 123 }; +var s = { + ...p, + ...r, +}; +var t: boolean = s.y; // error, string or number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var p = { y: \"\" }; +var q = { z: \"\" }; +var o = { x: 5, ...p, ...q }; +var y: number = o.y; +var z: number = o.z; +// test conflicting keys (they get unioned) +var r = { y: 123 }; +var s = { ...p, ...r }; +var t: boolean = s.y;// error, string or number + +" +`; + +exports[`test test4.js 1`] = ` +"/* @flow */ +function test(...nums: Array) {} + +test(0, ...[1, 2, 3]); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function test(...nums) { + +} +test(0, ...[ 1, 2, 3 ]); + +" +`; + +exports[`test test5.js 1`] = ` +"/* @flow */ + +declare function map( + obj: {[key: string]: Tv}, + iterator:((obj: Tv) => TNext), +): Array; + +/** + * Tests overriding a property via a spread, where the value is a tvar. the + * type of the prop from the object that is being overridden (\`x.kind\` in the + * case below) should //not// feed back into the tvar (\`value\`), since the + * result is a new object. + */ +function test( + x: {kind: ?string}, + kinds: {[key: string]: string} +): Array<{kind: ?string}> { + return map(kinds, (value) => { + (value: string); // OK + return { + ...x, + kind: value, + }; + }); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1368:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test6.js 1`] = ` +"var o = { + foo: \'bar\' +}; +o = {...o}; +(o: {foo: string}); + +var p = { + foo: \'bar\' +}; +(p: {foo: string; abc: string}); // error, p doesn\'t have \`abc\` yet +p = {...p, abc: \'def\'}; +(p: {foo: string; abc: string}); + +var q = { + foo: \'bar\' +}; +for (var i = 0; i < 10; i++) { + q = {...q}; +} +(q: {foo: string}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = { foo: \"bar\" }; +o = { ...o }; +(o: { foo: string }); +var p = { foo: \"bar\" }; +(p: { foo: string, abc: string });// error, p doesn\'t have \`abc\` yet +p = { ...p, abc: \"def\" }; +(p: { foo: string, abc: string }); +var q = { foo: \"bar\" }; +for (var i = 0; i < 10; i++) { + q = { ...q }; +} +(q: { foo: string }); + +" +`; + +exports[`test test7.js 1`] = ` +"// @flow + +let tests = [ + function(x: Object) { + ({...x}: Object); + ({...x}: void); // error, Object + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + function(x: Object) { + ({ ...x }: Object); + ({ ...x }: void);// error, Object + } +]; + +" +`; diff --git a/tests/spread/jsfmt.spec.js b/tests/spread/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/spread/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/spread/test.js b/tests/spread/test.js new file mode 100644 index 000000000000..19c223947226 --- /dev/null +++ b/tests/spread/test.js @@ -0,0 +1,30 @@ +function parseTimestamp(timestamp: string): number { + return 0; +} + +function parseCounter(line: string): number { + return 0; +} + +function parseGroup(lines: Array): { + counter: number; + begin: number; + end: number; + text: string; +} { + var counter = parseCounter(lines[0]); + var timeframe = parseTimeframe(lines[1]); + return { + counter, + ...timeframe, + text: lines[2] + }; +} + +function parseTimeframe(line: string): { begin: number; end: number } { + var timestamps = line.split('-->'); + return { + begin: parseTimestamp(timestamps[0].trim()), + end: parseTimestamp(timestamps[1].trim()) + }; +} diff --git a/tests/spread/test2.js b/tests/spread/test2.js new file mode 100644 index 000000000000..d2efac4f66b4 --- /dev/null +++ b/tests/spread/test2.js @@ -0,0 +1,9 @@ +/** + * @flow + */ + +function foo(o) { + bar({...o}); +} +function bar(_: {foo:number}) { } +foo({foo: 42}); diff --git a/tests/spread/test3.js b/tests/spread/test3.js new file mode 100644 index 000000000000..85c1194be5b1 --- /dev/null +++ b/tests/spread/test3.js @@ -0,0 +1,17 @@ +var p = { y: "" }; +var q = { z: "" }; +var o = { + x: 5, + ...p, + ...q, +}; +var y: number = o.y; +var z: number = o.z; + +// test conflicting keys (they get unioned) +var r = { y: 123 }; +var s = { + ...p, + ...r, +}; +var t: boolean = s.y; // error, string or number diff --git a/tests/spread/test4.js b/tests/spread/test4.js new file mode 100644 index 000000000000..6b58cbdc7dac --- /dev/null +++ b/tests/spread/test4.js @@ -0,0 +1,4 @@ +/* @flow */ +function test(...nums: Array) {} + +test(0, ...[1, 2, 3]); diff --git a/tests/spread/test5.js b/tests/spread/test5.js new file mode 100644 index 000000000000..500a78f203c0 --- /dev/null +++ b/tests/spread/test5.js @@ -0,0 +1,25 @@ +/* @flow */ + +declare function map( + obj: {[key: string]: Tv}, + iterator:((obj: Tv) => TNext), +): Array; + +/** + * Tests overriding a property via a spread, where the value is a tvar. the + * type of the prop from the object that is being overridden (`x.kind` in the + * case below) should //not// feed back into the tvar (`value`), since the + * result is a new object. + */ +function test( + x: {kind: ?string}, + kinds: {[key: string]: string} +): Array<{kind: ?string}> { + return map(kinds, (value) => { + (value: string); // OK + return { + ...x, + kind: value, + }; + }); +} diff --git a/tests/spread/test6.js b/tests/spread/test6.js new file mode 100644 index 000000000000..54613a74d78c --- /dev/null +++ b/tests/spread/test6.js @@ -0,0 +1,20 @@ +var o = { + foo: 'bar' +}; +o = {...o}; +(o: {foo: string}); + +var p = { + foo: 'bar' +}; +(p: {foo: string; abc: string}); // error, p doesn't have `abc` yet +p = {...p, abc: 'def'}; +(p: {foo: string; abc: string}); + +var q = { + foo: 'bar' +}; +for (var i = 0; i < 10; i++) { + q = {...q}; +} +(q: {foo: string}); diff --git a/tests/spread/test7.js b/tests/spread/test7.js new file mode 100644 index 000000000000..a0c090fc7874 --- /dev/null +++ b/tests/spread/test7.js @@ -0,0 +1,8 @@ +// @flow + +let tests = [ + function(x: Object) { + ({...x}: Object); + ({...x}: void); // error, Object + }, +]; diff --git a/tests/static_overload/__snapshots__/jsfmt.spec.js.snap b/tests/static_overload/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5f11981fdd11 --- /dev/null +++ b/tests/static_overload/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,7 @@ +exports[`test test.js 1`] = ` +"var x: number = StaticOverload.foo(0); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var x: number = StaticOverload.foo(0); + +" +`; diff --git a/tests/static_overload/jsfmt.spec.js b/tests/static_overload/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/static_overload/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/static_overload/lib/__snapshots__/jsfmt.spec.js.snap b/tests/static_overload/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3e5e45e624ec --- /dev/null +++ b/tests/static_overload/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,23 @@ +exports[`test lib.js 1`] = ` +"declare class StaticOverload { + static foo(x: number): number; + static foo(x: string): string; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/static_overload/lib/jsfmt.spec.js b/tests/static_overload/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/static_overload/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/static_overload/lib/lib.js b/tests/static_overload/lib/lib.js new file mode 100644 index 000000000000..61179705b9d2 --- /dev/null +++ b/tests/static_overload/lib/lib.js @@ -0,0 +1,4 @@ +declare class StaticOverload { + static foo(x: number): number; + static foo(x: string): string; +} diff --git a/tests/static_overload/test.js b/tests/static_overload/test.js new file mode 100644 index 000000000000..f72428ff8ccd --- /dev/null +++ b/tests/static_overload/test.js @@ -0,0 +1 @@ +var x: number = StaticOverload.foo(0); diff --git a/tests/statics/__snapshots__/jsfmt.spec.js.snap b/tests/statics/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..342379db62a2 --- /dev/null +++ b/tests/statics/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,47 @@ +exports[`test class_statics.js 1`] = ` +"class C { + static f(x:number) { } + static x:string; +} + +C.g = function(x:string) { C.f(x); }; +C.g(0); + +var x:number = C.x; +C.x = 0;~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + f(x: number) { + + } + static x: string; +} +C.g = function(x: string) { + C.f(x); +}; +C.g(0); +var x: number = C.x; +C.x = 0; + +" +`; + +exports[`test funstatics.js 1`] = ` +"function C() { } +C.prototype.f = function() { return C.g(0); } +C.g = function(x) { return x; }; + +var x:string = new C().f(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function C() { + +} +C.prototype.f = function() { + return C.g(0); +}; +C.g = function(x) { + return x; +}; +var x: string = new C().f(); + +" +`; diff --git a/tests/statics/class_statics.js b/tests/statics/class_statics.js new file mode 100644 index 000000000000..fc9a02a2b7b1 --- /dev/null +++ b/tests/statics/class_statics.js @@ -0,0 +1,10 @@ +class C { + static f(x:number) { } + static x:string; +} + +C.g = function(x:string) { C.f(x); }; +C.g(0); + +var x:number = C.x; +C.x = 0; \ No newline at end of file diff --git a/tests/statics/funstatics.js b/tests/statics/funstatics.js new file mode 100644 index 000000000000..0e50eca1213c --- /dev/null +++ b/tests/statics/funstatics.js @@ -0,0 +1,5 @@ +function C() { } +C.prototype.f = function() { return C.g(0); } +C.g = function(x) { return x; }; + +var x:string = new C().f(); diff --git a/tests/statics/jsfmt.spec.js b/tests/statics/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/statics/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/strict/__snapshots__/jsfmt.spec.js.snap b/tests/strict/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..82c4b9ed76a8 --- /dev/null +++ b/tests/strict/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,83 @@ +exports[`test annot.js 1`] = ` +"var A = require('./unknown_class'); + +class B extends A { + foo(x:A):A { return x; } + bar(x) { } + qux(x:X,y:Y):X { return x;} +} + +module.exports = B; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var A = require("./unknown_class"); +class B extends A { + foo(x: A): A { + return x; + } + bar(x) { + + } + qux(x: X, y: Y): X { + return x; + } +} +module.exports = B; + +" +`; + +exports[`test fun.js 1`] = ` +"/** + * @flow + */ + +// progressively annotate: + +//function f(x) { return x; } +function f(x:number) { return x; } +//function f(x:number):string { return x; } + +var x:string = f(0); + +module.exports = f; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +// progressively annotate: +//function f(x) { return x; } +function f(x: number) { + return x; +} +//function f(x:number):string { return x; } +var x: string = f(0); +module.exports = f; + +" +`; + +exports[`test obj.js 1`] = ` +"/** + * @flow + */ + +// progressively annotate: + +var o = { x: 0 } +//var o: {x: number;} = { x: 0 } + +var x:string = o.x; + +module.exports = o; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +// progressively annotate: +var o = { x: 0 }; +//var o: {x: number;} = { x: 0 } +var x: string = o.x; +module.exports = o; + +" +`; diff --git a/tests/strict/annot.js b/tests/strict/annot.js new file mode 100644 index 000000000000..69e385f2ca2c --- /dev/null +++ b/tests/strict/annot.js @@ -0,0 +1,9 @@ +var A = require('./unknown_class'); + +class B extends A { + foo(x:A):A { return x; } + bar(x) { } + qux(x:X,y:Y):X { return x;} +} + +module.exports = B; diff --git a/tests/strict/fun.js b/tests/strict/fun.js new file mode 100644 index 000000000000..b09992315b1e --- /dev/null +++ b/tests/strict/fun.js @@ -0,0 +1,13 @@ +/** + * @flow + */ + +// progressively annotate: + +//function f(x) { return x; } +function f(x:number) { return x; } +//function f(x:number):string { return x; } + +var x:string = f(0); + +module.exports = f; diff --git a/tests/strict/jsfmt.spec.js b/tests/strict/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/strict/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/strict/obj.js b/tests/strict/obj.js new file mode 100644 index 000000000000..0add7bed5bb1 --- /dev/null +++ b/tests/strict/obj.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +// progressively annotate: + +var o = { x: 0 } +//var o: {x: number;} = { x: 0 } + +var x:string = o.x; + +module.exports = o; diff --git a/tests/strict_requires/A.js b/tests/strict_requires/A.js new file mode 100644 index 000000000000..0df880dc9718 --- /dev/null +++ b/tests/strict_requires/A.js @@ -0,0 +1,2 @@ +/* @flow */ +module.exports = 0; diff --git a/tests/strict_requires/B.js b/tests/strict_requires/B.js new file mode 100644 index 000000000000..e954bc64a74b --- /dev/null +++ b/tests/strict_requires/B.js @@ -0,0 +1,2 @@ +/* @flow */ +module.exports = { foo: "" } diff --git a/tests/strict_requires/C.js b/tests/strict_requires/C.js new file mode 100644 index 000000000000..991ad5a6ca64 --- /dev/null +++ b/tests/strict_requires/C.js @@ -0,0 +1,6 @@ +/* @flow */ +var o = { + A: require('./A'), + ...require('./B'), +}; +module.exports = o; diff --git a/tests/strict_requires/D.js b/tests/strict_requires/D.js new file mode 100644 index 000000000000..53659ea52004 --- /dev/null +++ b/tests/strict_requires/D.js @@ -0,0 +1,5 @@ +/* @flow */ +var C = require('./C'); +var x: number = C.foo; +var y: string = C.A; +C.A = false; diff --git a/tests/strict_requires/__snapshots__/jsfmt.spec.js.snap b/tests/strict_requires/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a9e678089e60 --- /dev/null +++ b/tests/strict_requires/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,50 @@ +exports[`test A.js 1`] = ` +"/* @flow */ +module.exports = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports = 0; + +" +`; + +exports[`test B.js 1`] = ` +"/* @flow */ +module.exports = { foo: "" } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +module.exports = { foo: "" }; + +" +`; + +exports[`test C.js 1`] = ` +"/* @flow */ +var o = { + A: require('./A'), + ...require('./B'), +}; +module.exports = o; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var o = { A: require("./A"), ...require("./B") }; +module.exports = o; + +" +`; + +exports[`test D.js 1`] = ` +"/* @flow */ +var C = require('./C'); +var x: number = C.foo; +var y: string = C.A; +C.A = false; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var C = require("./C"); +var x: number = C.foo; +var y: string = C.A; +C.A = false; + +" +`; diff --git a/tests/strict_requires/jsfmt.spec.js b/tests/strict_requires/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/strict_requires/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/strings/__snapshots__/jsfmt.spec.js.snap b/tests/strings/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6ec2f5384a0a --- /dev/null +++ b/tests/strings/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,42 @@ +exports[`test strings.js 1`] = ` +"\"abc\" +\'abc\' + +\'\\\'\' + +\'\"\' +\'\\\"\' +\'\\\\\"\' + +\"\'\" +\"\\\'\" +\"\\\\\'\" + +\"\'\\\"\" +\'\\\'\"\' + +\'\\\\\' +\"\\\\\" + +\'\\0\' +\'🐶\' +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\"abc\"; +\"abc\"; +\"\\\\\'\"; +\"\\\"\"; +\"\\\\\\\"\"; +\"\\\\\\\\\\\"\"; +\"\'\"; +\"\\\\\'\"; +\"\\\\\\\\\'\"; +\"\'\\\\\\\"\"; +\"\\\\\'\\\"\"; +\"\\\\\\\\\"; +\"\\\\\\\\\"; +\"\\\\0\"; +\"🐶\"; + + +" +`; diff --git a/tests/strings/jsfmt.spec.js b/tests/strings/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/strings/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/strings/strings.js b/tests/strings/strings.js new file mode 100644 index 000000000000..b296b144d398 --- /dev/null +++ b/tests/strings/strings.js @@ -0,0 +1,21 @@ +"abc" +'abc' + +'\'' + +'"' +'\"' +'\\"' + +"'" +"\'" +"\\'" + +"'\"" +'\'"' + +'\\' +"\\" + +'\0' +'🐶' diff --git a/tests/structural_subtyping/__snapshots__/jsfmt.spec.js.snap b/tests/structural_subtyping/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..e216003a5a18 --- /dev/null +++ b/tests/structural_subtyping/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,146 @@ +exports[`test builtin.js 1`] = ` +"/** + * @flow + */ + +interface IHasLength { + length: number; +} + +var lengthTest1: IHasLength = []; +var lengthTest2: IHasLength = \'hello\'; +var lengthTest3: IHasLength = 123; // number doesn\'t have length +var lengthTest4: IHasLength = true; // bool doesn\'t have length +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test class.js 1`] = ` +"/** + * @flow + */ + +class ClassWithXString { + x: string; +} + +interface IHasXString { + x: string; +} + +interface IHasXNumber { + x: number; +} + +interface IHasYString { + y: string; +} + +var testInstance1: IHasXString = new ClassWithXString(); +var testInstance2: IHasXNumber = new ClassWithXString(); // Error wrong type +var testInstance3: IHasYString = new ClassWithXString(); // Error missing prop +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test obj.js 1`] = ` +"/** + * @flow + */ + +interface IHasXString { + x: string; +} + +var propTest1: IHasXString = { x: \'hello\' }; +var propTest2: IHasXString = { x: 123 }; // Error string != number +var propTest3: IHasXString = {}; // Property not found +var propTest4: IHasXString = ({}: Object); + +function propTest5(y: {[key: string]: string}) { + (y: IHasXString); // OK +} + +function propTest6(y: {[key: string]: number}) { + (y: IHasXString); // error: string != number +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test optional.js 1`] = ` +"/* @flow */ + +interface HasOptional { + a: string, + b?: number, +}; + +var test1: HasOptional = { a: \"hello\" } + +var test2: HasOptional = {}; // Error: missing property a + +var test3: HasOptional = { a: \"hello\", b: true }; // Error: boolean ~> number +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; diff --git a/tests/structural_subtyping/builtin.js b/tests/structural_subtyping/builtin.js new file mode 100644 index 000000000000..ebc0b2de9c27 --- /dev/null +++ b/tests/structural_subtyping/builtin.js @@ -0,0 +1,12 @@ +/** + * @flow + */ + +interface IHasLength { + length: number; +} + +var lengthTest1: IHasLength = []; +var lengthTest2: IHasLength = 'hello'; +var lengthTest3: IHasLength = 123; // number doesn't have length +var lengthTest4: IHasLength = true; // bool doesn't have length diff --git a/tests/structural_subtyping/class.js b/tests/structural_subtyping/class.js new file mode 100644 index 000000000000..9fa9d3039674 --- /dev/null +++ b/tests/structural_subtyping/class.js @@ -0,0 +1,23 @@ +/** + * @flow + */ + +class ClassWithXString { + x: string; +} + +interface IHasXString { + x: string; +} + +interface IHasXNumber { + x: number; +} + +interface IHasYString { + y: string; +} + +var testInstance1: IHasXString = new ClassWithXString(); +var testInstance2: IHasXNumber = new ClassWithXString(); // Error wrong type +var testInstance3: IHasYString = new ClassWithXString(); // Error missing prop diff --git a/tests/structural_subtyping/jsfmt.spec.js b/tests/structural_subtyping/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/structural_subtyping/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/structural_subtyping/obj.js b/tests/structural_subtyping/obj.js new file mode 100644 index 000000000000..6a9189ac0f62 --- /dev/null +++ b/tests/structural_subtyping/obj.js @@ -0,0 +1,20 @@ +/** + * @flow + */ + +interface IHasXString { + x: string; +} + +var propTest1: IHasXString = { x: 'hello' }; +var propTest2: IHasXString = { x: 123 }; // Error string != number +var propTest3: IHasXString = {}; // Property not found +var propTest4: IHasXString = ({}: Object); + +function propTest5(y: {[key: string]: string}) { + (y: IHasXString); // OK +} + +function propTest6(y: {[key: string]: number}) { + (y: IHasXString); // error: string != number +} diff --git a/tests/structural_subtyping/optional.js b/tests/structural_subtyping/optional.js new file mode 100644 index 000000000000..102a511ef7a2 --- /dev/null +++ b/tests/structural_subtyping/optional.js @@ -0,0 +1,12 @@ +/* @flow */ + +interface HasOptional { + a: string, + b?: number, +}; + +var test1: HasOptional = { a: "hello" } + +var test2: HasOptional = {}; // Error: missing property a + +var test3: HasOptional = { a: "hello", b: true }; // Error: boolean ~> number diff --git a/tests/suggest/__snapshots__/jsfmt.spec.js.snap b/tests/suggest/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9b7010ce1817 --- /dev/null +++ b/tests/suggest/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,39 @@ +exports[`test lib.js 1`] = ` +"/* @flow */ + +function bar(w: number): number { return w; } + +module.exports = bar; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function bar(w: number): number { + return w; +} +module.exports = bar; + +" +`; + +exports[`test suggest.js 1`] = ` +"/* @flow */ + +var bar = require('./lib'); + +function foo(z: number) { return bar(z); } + +var array = ["foo", "bar"]; +array; + +module.exports = {foo:foo}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +var bar = require("./lib"); +function foo(z: number) { + return bar(z); +} +var array = [ "foo", "bar" ]; +array; +module.exports = { foo: foo }; + +" +`; diff --git a/tests/suggest/jsfmt.spec.js b/tests/suggest/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/suggest/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/suggest/lib.js b/tests/suggest/lib.js new file mode 100644 index 000000000000..f89c80bf62c5 --- /dev/null +++ b/tests/suggest/lib.js @@ -0,0 +1,5 @@ +/* @flow */ + +function bar(w: number): number { return w; } + +module.exports = bar; diff --git a/tests/suggest/suggest.js b/tests/suggest/suggest.js new file mode 100644 index 000000000000..e2b005194721 --- /dev/null +++ b/tests/suggest/suggest.js @@ -0,0 +1,10 @@ +/* @flow */ + +var bar = require('./lib'); + +function foo(z: number) { return bar(z); } + +var array = ["foo", "bar"]; +array; + +module.exports = {foo:foo}; diff --git a/tests/super/__snapshots__/jsfmt.spec.js.snap b/tests/super/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3173dd9a56b6 --- /dev/null +++ b/tests/super/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,263 @@ +exports[`test constructor.js 1`] = ` +"class A { x: number; } + +class B { + x: number; + constructor() { + this.x; // OK + } +} + +class C extends A { } + +class D extends A { + y: number; + constructor() { + this.y; // error (no super call) + this.x; // error (no super call) + } +} + +class E extends A { + y: number; + constructor() { + super(); + this.y; // OK + this.x; // OK + } +} + +function leak(f) { + f.y; // error + f.x; // error +} +class F extends A { + y: number; + constructor() { + leak(this); // error (no super call yet) + super(); + this.y; + this.x; + } +} + +class G extends A { + constructor(b) { + super.x; // error (no super call) + } +} + +class H extends A { + y: number; + constructor() { + if (Math.random() < 0.5) + super(); + else + super(); + this.y; // OK + this.x; // OK + } +} + +class I_ { + constructor(leaked_this) { + leaked_this.foo() + } + foo() { } +} +class I extends I_ { + constructor() { + super(this); // error (no super call yet) + } +} + +class J__ { } +class J_ extends J__ { + constructor(closure_leaking_this) { + closure_leaking_this(); + super(); + } + foo() { } +} +class J extends J_ { + constructor() { + super(() => this.foo()); // error (no super call yet) + // The reason for this error is that super constructor could call the + // closure and therefore access this before calling its own super + // constructor (as shown above). The only safe thing to do in the super + // constructor is to save the closure so that it can be called later, after + // initialization is done (as shown below). + } +} + +class K_ { + closure_leaking_this: () => void; + constructor(closure_leaking_this) { + this.closure_leaking_this = closure_leaking_this; + } + foo() { } +} +class K extends K_ { + constructor() { + super(() => { if (_this) _this.foo() }); // OK + var _this = this; + this.closure_leaking_this(); + } +} + +// even though super() calls the parent\'s constructor(), it does not do the same +// conversion on non-objects. so \`new L_()\` returns an instance of \`L_\` because +// the constructor returns false (a non-object), but \`super()\` returns false, +// which then similarly causes \`new L()\` to return an instance of \`L\`. +class L_ { + constructor() { + return false; + } +} +class L extends L_ { + constructor() { + let x: boolean = super(); + return x; + } +} +(new L_(): L_); +(new L(): L); + +// similarly, the converse is true: if the parent\'s constructor returns an +// object, then the child does too. +class M_ { + constructor() { + return {foo: \'foo\'}; + } +} +class M extends M_ { + constructor() { + return super(); + } +} +(new M_(): {foo: string}); +(new M(): {foo: string}); + +// however! super() calls the parent constructor with the subclass as its \`this\` +// value (essentially \`super.constructor.call(this)\`). +class N_ { + constructor(): this { + let x = this; + return x; + } +} +class N extends N_ { + constructor() { + return super(); + } +} +(new N_(): N_); +(new N(): N); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test import.js 1`] = ` +"class D { + foo(): number { return 0; } +} +module.exports = D; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class D { + foo(): number { + return 0; + } +} +module.exports = D; + +" +`; + +exports[`test super.js 1`] = ` +" +class A { + constructor(x:number) { } + static staticMethod(x:string): string { return x; } + f(x:string) { } +} + +class B extends A { + constructor(x:string,y:number) { + super(x); + } + + static anotherStatic() { + (super.staticMethod(\'foo\'): number); // error, string !~> number + (super.doesntExist()); // error, A doesn\'t have a doesntExist method + } + + g() { + super.f(0); + return super.g; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A { + constructor(x: number) { + + } + staticMethod(x: string): string { + return x; + } + f(x: string) { + + } +} +class B extends A { + constructor(x: string, y: number) { + super(x); + } + anotherStatic() { + (super.staticMethod(\"foo\"): number);// error, string !~> number + super.doesntExist();// error, A doesn\'t have a doesntExist method + } + g() { + super.f(0); + return super.g; + } +} + +" +`; + +exports[`test test.js 1`] = ` +"var D = require(\'./import\'); +class C extends D { + constructor() { return super(); } + foo() { return super.foo(); } +} +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var D = require(\"./import\"); +class C extends D { + constructor() { + return super(); + } + foo() { + return super.foo(); + } +} +module.exports = C; + +" +`; diff --git a/tests/super/constructor.js b/tests/super/constructor.js new file mode 100644 index 000000000000..3e11a1dfdb03 --- /dev/null +++ b/tests/super/constructor.js @@ -0,0 +1,154 @@ +class A { x: number; } + +class B { + x: number; + constructor() { + this.x; // OK + } +} + +class C extends A { } + +class D extends A { + y: number; + constructor() { + this.y; // error (no super call) + this.x; // error (no super call) + } +} + +class E extends A { + y: number; + constructor() { + super(); + this.y; // OK + this.x; // OK + } +} + +function leak(f) { + f.y; // error + f.x; // error +} +class F extends A { + y: number; + constructor() { + leak(this); // error (no super call yet) + super(); + this.y; + this.x; + } +} + +class G extends A { + constructor(b) { + super.x; // error (no super call) + } +} + +class H extends A { + y: number; + constructor() { + if (Math.random() < 0.5) + super(); + else + super(); + this.y; // OK + this.x; // OK + } +} + +class I_ { + constructor(leaked_this) { + leaked_this.foo() + } + foo() { } +} +class I extends I_ { + constructor() { + super(this); // error (no super call yet) + } +} + +class J__ { } +class J_ extends J__ { + constructor(closure_leaking_this) { + closure_leaking_this(); + super(); + } + foo() { } +} +class J extends J_ { + constructor() { + super(() => this.foo()); // error (no super call yet) + // The reason for this error is that super constructor could call the + // closure and therefore access this before calling its own super + // constructor (as shown above). The only safe thing to do in the super + // constructor is to save the closure so that it can be called later, after + // initialization is done (as shown below). + } +} + +class K_ { + closure_leaking_this: () => void; + constructor(closure_leaking_this) { + this.closure_leaking_this = closure_leaking_this; + } + foo() { } +} +class K extends K_ { + constructor() { + super(() => { if (_this) _this.foo() }); // OK + var _this = this; + this.closure_leaking_this(); + } +} + +// even though super() calls the parent's constructor(), it does not do the same +// conversion on non-objects. so `new L_()` returns an instance of `L_` because +// the constructor returns false (a non-object), but `super()` returns false, +// which then similarly causes `new L()` to return an instance of `L`. +class L_ { + constructor() { + return false; + } +} +class L extends L_ { + constructor() { + let x: boolean = super(); + return x; + } +} +(new L_(): L_); +(new L(): L); + +// similarly, the converse is true: if the parent's constructor returns an +// object, then the child does too. +class M_ { + constructor() { + return {foo: 'foo'}; + } +} +class M extends M_ { + constructor() { + return super(); + } +} +(new M_(): {foo: string}); +(new M(): {foo: string}); + +// however! super() calls the parent constructor with the subclass as its `this` +// value (essentially `super.constructor.call(this)`). +class N_ { + constructor(): this { + let x = this; + return x; + } +} +class N extends N_ { + constructor() { + return super(); + } +} +(new N_(): N_); +(new N(): N); diff --git a/tests/super/import.js b/tests/super/import.js new file mode 100644 index 000000000000..4ca97a19d780 --- /dev/null +++ b/tests/super/import.js @@ -0,0 +1,4 @@ +class D { + foo(): number { return 0; } +} +module.exports = D; diff --git a/tests/super/jsfmt.spec.js b/tests/super/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/super/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/super/super.js b/tests/super/super.js new file mode 100644 index 000000000000..1bdae53e2366 --- /dev/null +++ b/tests/super/super.js @@ -0,0 +1,22 @@ + +class A { + constructor(x:number) { } + static staticMethod(x:string): string { return x; } + f(x:string) { } +} + +class B extends A { + constructor(x:string,y:number) { + super(x); + } + + static anotherStatic() { + (super.staticMethod('foo'): number); // error, string !~> number + (super.doesntExist()); // error, A doesn't have a doesntExist method + } + + g() { + super.f(0); + return super.g; + } +} diff --git a/tests/super/test.js b/tests/super/test.js new file mode 100644 index 000000000000..3a9a3c3654d7 --- /dev/null +++ b/tests/super/test.js @@ -0,0 +1,6 @@ +var D = require('./import'); +class C extends D { + constructor() { return super(); } + foo() { return super.foo(); } +} +module.exports = C; diff --git a/tests/suppress/A.js b/tests/suppress/A.js new file mode 100644 index 000000000000..3411f3e65e0a --- /dev/null +++ b/tests/suppress/A.js @@ -0,0 +1,24 @@ +// $FlowFixMe +var test1: string = 123; // This error should be suppressed + +// $FlowIssue +var test2: string = 123; // This error should be suppressed + +function getNum() { + return 123; +} + +// $FlowFixMe This was the second loc in the error +var test3: string = getNum(); // This error should be suppressed + +// $FlowFixMe Error unused suppression + +var test4: string = 123; // This error is NOT suppressed + + // $FlowFixMe Indentation shouldn't matter +var test5: string = 123; // This error should be suppressed + +/* + * $FlowNewLine + */ +var test6: string = 123; diff --git a/tests/suppress/B.js b/tests/suppress/B.js new file mode 100644 index 000000000000..b4f41e62eb69 --- /dev/null +++ b/tests/suppress/B.js @@ -0,0 +1,2 @@ +// $FlowFixMe +var test1: string = library_num; diff --git a/tests/suppress/C.js b/tests/suppress/C.js new file mode 100644 index 000000000000..80c35d500c6e --- /dev/null +++ b/tests/suppress/C.js @@ -0,0 +1,8 @@ +function takesAString(x: string): void {} + +function runTest(y: number): void { + takesAString( + /* $FlowFixMe - suppressing the error op location should also work */ + y, + ); +} diff --git a/tests/suppress/__snapshots__/jsfmt.spec.js.snap b/tests/suppress/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..4b43391295c6 --- /dev/null +++ b/tests/suppress/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,86 @@ +exports[`test A.js 1`] = ` +"// $FlowFixMe +var test1: string = 123; // This error should be suppressed + +// $FlowIssue +var test2: string = 123; // This error should be suppressed + +function getNum() { + return 123; +} + +// $FlowFixMe This was the second loc in the error +var test3: string = getNum(); // This error should be suppressed + +// $FlowFixMe Error unused suppression + +var test4: string = 123; // This error is NOT suppressed + + // $FlowFixMe Indentation shouldn't matter +var test5: string = 123; // This error should be suppressed + +/* + * $FlowNewLine + */ +var test6: string = 123; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// $FlowFixMe +var test1: string = 123;// This error should be suppressed +// $FlowIssue +var test2: string = 123;// This error should be suppressed +function getNum() { + return 123; +} +// $FlowFixMe This was the second loc in the error +var test3: string = getNum();// This error should be suppressed +// $FlowFixMe Error unused suppression +var test4: string = 123;// This error is NOT suppressed// $FlowFixMe Indentation shouldn't matter +var test5: string = 123;// This error should be suppressed +/* + * $FlowNewLine + */ +var test6: string = 123; + +" +`; + +exports[`test B.js 1`] = ` +"// $FlowFixMe +var test1: string = library_num; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// $FlowFixMe +var test1: string = library_num; + +" +`; + +exports[`test C.js 1`] = ` +"function takesAString(x: string): void {} + +function runTest(y: number): void { + takesAString( + /* $FlowFixMe - suppressing the error op location should also work */ + y, + ); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function takesAString(x: string): void { + +} +function runTest(y: number): void { + takesAString( + /* $FlowFixMe - suppressing the error op location should also work */ + y + ); +} + +" +`; + +exports[`test lib.js 1`] = ` +"declare var library_num: number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare var library_num: number; + +" +`; diff --git a/tests/suppress/jsfmt.spec.js b/tests/suppress/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/suppress/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/suppress/lib.js b/tests/suppress/lib.js new file mode 100644 index 000000000000..21cfa88e53e5 --- /dev/null +++ b/tests/suppress/lib.js @@ -0,0 +1 @@ +declare var library_num: number; diff --git a/tests/suppress_incremental/__snapshots__/jsfmt.spec.js.snap b/tests/suppress_incremental/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..16a23d3be09a --- /dev/null +++ b/tests/suppress_incremental/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test test.js 1`] = ` +"// @flow + +(123: number); // no errors +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +(123: number);// no errors + +" +`; diff --git a/tests/suppress_incremental/jsfmt.spec.js b/tests/suppress_incremental/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/suppress_incremental/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/suppress_incremental/test.js b/tests/suppress_incremental/test.js new file mode 100644 index 000000000000..8f4e80213ed3 --- /dev/null +++ b/tests/suppress_incremental/test.js @@ -0,0 +1,3 @@ +// @flow + +(123: number); // no errors diff --git a/tests/suppress_traces/__snapshots__/jsfmt.spec.js.snap b/tests/suppress_traces/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..32292e7511df --- /dev/null +++ b/tests/suppress_traces/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,34 @@ +exports[`test traces.js 1`] = ` +"/* + * The location marked with the FlowFixMe does not show up in the original + * error but shows up in the flow check --traces 10 result. This test makes + * sure that we don't suppress the error due to a location that only shows up + * when --traces is turned on. + */ + +// $FlowFixMe - Error unused suppression +function bar(): number { return 5; } + +function foo(x: string) { + return bar(); +} + +var a: string = foo('hi'); // error number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* + * The location marked with the FlowFixMe does not show up in the original + * error but shows up in the flow check --traces 10 result. This test makes + * sure that we don't suppress the error due to a location that only shows up + * when --traces is turned on. + */ +// $FlowFixMe - Error unused suppression +function bar(): number { + return 5; +} +function foo(x: string) { + return bar(); +} +var a: string = foo("hi");// error number ~> string + +" +`; diff --git a/tests/suppress_traces/jsfmt.spec.js b/tests/suppress_traces/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/suppress_traces/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/suppress_traces/traces.js b/tests/suppress_traces/traces.js new file mode 100644 index 000000000000..1a34c3771dc6 --- /dev/null +++ b/tests/suppress_traces/traces.js @@ -0,0 +1,15 @@ +/* + * The location marked with the FlowFixMe does not show up in the original + * error but shows up in the flow check --traces 10 result. This test makes + * sure that we don't suppress the error due to a location that only shows up + * when --traces is turned on. + */ + +// $FlowFixMe - Error unused suppression +function bar(): number { return 5; } + +function foo(x: string) { + return bar(); +} + +var a: string = foo('hi'); // error number ~> string diff --git a/tests/switch/__snapshots__/jsfmt.spec.js.snap b/tests/switch/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ba9fd1e81846 --- /dev/null +++ b/tests/switch/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,262 @@ +exports[`test more_switch.js 1`] = ` +"/* @flow */ + +function foo(x): number { + switch (x) { + case 0: + case 1: return 1; + default: throw new Error(\'hi\'); + } +} + +function bar(x) { + switch (x) { + case 0: break; + default: return; + } + 1; +} + +function baz(x): number { + switch (x) { + case 0: break; + case 1: return 1; + default: throw new Error(\'hi\'); + } + return 2; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test switch.js 1`] = ` +"/** + * @flow + */ +function foo( +): number { + switch (\'foo\') { + case \'foo\': + return 1; + } + return 2; +} + +function bar() { + switch (\'bar\') { + case \'bar\': + break; + default: + break; + } +} + +function qux(b) { + var x = b? 0: \"\"; + switch(\'qux\') { + case \'\': + x = 0; + case \'qux\': + x = x*x; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test switch_default_fallthrough.js 1`] = ` +"/** + * @flow + */ +function foo(x : mixed): string { + var a = \"\"; + var b = \"\"; + + switch (x) { + case \"foo\": + a = 0; + default: + b = 0; + } + + // a is now string | number + (a : string); // error, string | number ~/> string + (a : number); // error, string | number ~/> number + + // b is now number + (b : number); // ok + return b; // error, number ~/> string +} + +function baz(x: mixed): number { + var a = \"\"; + var b = \"\"; + + switch (x) { + case \"baz\": + a = 0; + break; + case \"bar\": + a = \"\"; + default: + b = 0; + } + + // a is now string | number + (a : string); // error, string | number ~/> string + (a : number); // error, string | number ~/> number + + // b is now string | number + (b : string); // error, string | number ~/> string + (b : number); // error, string | number ~/> number + + return a+b; // error, string ~/> number +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test trailing_cases.js 1`] = ` +"/** + * trailing cases are allowed - spot checks that we handle them as usual + * @flow + */ +function f1(i) { + var x; + + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + default: + x = -1; + break; + case 2: + x = \"2\"; + break; + } + + var y:number = x; // error, number | string ~/> number +} + +function f2(i) { + var x; + + switch (i) { + case 0: + case 1: + default: + x = 1; + break; + case 2: + // does not fall through default + } + + var y:number = x; // error, number | uninitialized ~/> number +} + +function f3(i) { + var x; + + switch (i) { + case 0: + case 1: + default: + // falls through to subsequent cases + case 2: + x = 1; + } + + var y:number = x; // no error +} + +function foo(x): number { + switch (x) { + case 0: + default: throw new Error(\'hi\'); + case 1: return 1; + } +} + +function bar(x) { + switch (x) { + default: return; + case 0: break; + } + 1; +} + +function baz(x): number { + switch (x) { + case 0: break; + default: throw new Error(\'hi\'); + case 1: return 1; + } + return 2; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1020 + }, \"consequent\").indent(options.tabWidth)); + ^ + +TypeError: path.call(...).indent is not a function + at genericPrintNoParens (/src/printer.js:1020:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1005:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/switch/jsfmt.spec.js b/tests/switch/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/switch/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/switch/more_switch.js b/tests/switch/more_switch.js new file mode 100644 index 000000000000..1b478e4a708e --- /dev/null +++ b/tests/switch/more_switch.js @@ -0,0 +1,26 @@ +/* @flow */ + +function foo(x): number { + switch (x) { + case 0: + case 1: return 1; + default: throw new Error('hi'); + } +} + +function bar(x) { + switch (x) { + case 0: break; + default: return; + } + 1; +} + +function baz(x): number { + switch (x) { + case 0: break; + case 1: return 1; + default: throw new Error('hi'); + } + return 2; +} diff --git a/tests/switch/switch.js b/tests/switch/switch.js new file mode 100644 index 000000000000..7431b929b4ea --- /dev/null +++ b/tests/switch/switch.js @@ -0,0 +1,30 @@ +/** + * @flow + */ +function foo( +): number { + switch ('foo') { + case 'foo': + return 1; + } + return 2; +} + +function bar() { + switch ('bar') { + case 'bar': + break; + default: + break; + } +} + +function qux(b) { + var x = b? 0: ""; + switch('qux') { + case '': + x = 0; + case 'qux': + x = x*x; + } +} diff --git a/tests/switch/switch_default_fallthrough.js b/tests/switch/switch_default_fallthrough.js new file mode 100644 index 000000000000..2b79bada2503 --- /dev/null +++ b/tests/switch/switch_default_fallthrough.js @@ -0,0 +1,47 @@ +/** + * @flow + */ +function foo(x : mixed): string { + var a = ""; + var b = ""; + + switch (x) { + case "foo": + a = 0; + default: + b = 0; + } + + // a is now string | number + (a : string); // error, string | number ~/> string + (a : number); // error, string | number ~/> number + + // b is now number + (b : number); // ok + return b; // error, number ~/> string +} + +function baz(x: mixed): number { + var a = ""; + var b = ""; + + switch (x) { + case "baz": + a = 0; + break; + case "bar": + a = ""; + default: + b = 0; + } + + // a is now string | number + (a : string); // error, string | number ~/> string + (a : number); // error, string | number ~/> number + + // b is now string | number + (b : string); // error, string | number ~/> string + (b : number); // error, string | number ~/> number + + return a+b; // error, string ~/> number +} diff --git a/tests/switch/trailing_cases.js b/tests/switch/trailing_cases.js new file mode 100644 index 000000000000..72f60aa92c28 --- /dev/null +++ b/tests/switch/trailing_cases.js @@ -0,0 +1,80 @@ +/** + * trailing cases are allowed - spot checks that we handle them as usual + * @flow + */ +function f1(i) { + var x; + + switch (i) { + case 0: + x = 0; + break; + case 1: + x = 1; + break; + default: + x = -1; + break; + case 2: + x = "2"; + break; + } + + var y:number = x; // error, number | string ~/> number +} + +function f2(i) { + var x; + + switch (i) { + case 0: + case 1: + default: + x = 1; + break; + case 2: + // does not fall through default + } + + var y:number = x; // error, number | uninitialized ~/> number +} + +function f3(i) { + var x; + + switch (i) { + case 0: + case 1: + default: + // falls through to subsequent cases + case 2: + x = 1; + } + + var y:number = x; // no error +} + +function foo(x): number { + switch (x) { + case 0: + default: throw new Error('hi'); + case 1: return 1; + } +} + +function bar(x) { + switch (x) { + default: return; + case 0: break; + } + 1; +} + +function baz(x): number { + switch (x) { + case 0: break; + default: throw new Error('hi'); + case 1: return 1; + } + return 2; +} diff --git a/tests/symbol/__snapshots__/jsfmt.spec.js.snap b/tests/symbol/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6d9d2d58fbdd --- /dev/null +++ b/tests/symbol/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,14 @@ +exports[`test symbol.js 1`] = ` +"var FOO = Symbol(); +var BAR = Symbol('bar'); + +// TODO: Expected error +var WAT = Symbol('foo', 'bar'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var FOO = Symbol(); +var BAR = Symbol("bar"); +// TODO: Expected error +var WAT = Symbol("foo", "bar"); + +" +`; diff --git a/tests/symbol/jsfmt.spec.js b/tests/symbol/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/symbol/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/symbol/symbol.js b/tests/symbol/symbol.js new file mode 100644 index 000000000000..f8c625d14c95 --- /dev/null +++ b/tests/symbol/symbol.js @@ -0,0 +1,5 @@ +var FOO = Symbol(); +var BAR = Symbol('bar'); + +// TODO: Expected error +var WAT = Symbol('foo', 'bar'); diff --git a/tests/symlink/__snapshots__/jsfmt.spec.js.snap b/tests/symlink/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..6a3e902ee7d4 --- /dev/null +++ b/tests/symlink/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,25 @@ +exports[`test bar.js 1`] = ` +"export type Foo = { x: number; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +export type Foo = { x: number }; + +" +`; + +exports[`test foo.js 1`] = ` +"export type Foo = { x: number; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +export type Foo = { x: number }; + +" +`; + +exports[`test qux.js 1`] = ` +"import type { Foo } from './bar.js'; +({ x: "" }: Foo); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import type { Foo } from "./bar.js"; +({ x: "" }: Foo); + +" +`; diff --git a/tests/symlink/bar.js b/tests/symlink/bar.js new file mode 100644 index 000000000000..41044c7c6ca9 --- /dev/null +++ b/tests/symlink/bar.js @@ -0,0 +1 @@ +export type Foo = { x: number; } diff --git a/tests/symlink/foo.js b/tests/symlink/foo.js new file mode 100644 index 000000000000..41044c7c6ca9 --- /dev/null +++ b/tests/symlink/foo.js @@ -0,0 +1 @@ +export type Foo = { x: number; } diff --git a/tests/symlink/jsfmt.spec.js b/tests/symlink/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/symlink/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/symlink/qux.js b/tests/symlink/qux.js new file mode 100644 index 000000000000..1595d2426a9d --- /dev/null +++ b/tests/symlink/qux.js @@ -0,0 +1,2 @@ +import type { Foo } from './bar.js'; +({ x: "" }: Foo); diff --git a/tests/tagged-unions/__snapshots__/jsfmt.spec.js.snap b/tests/tagged-unions/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..f1954cc1a99c --- /dev/null +++ b/tests/tagged-unions/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,242 @@ +exports[`test classes.js 1`] = ` +"// @flow + +class Foo { + type: \'foo\'; + foo: string; +} + +class Bar { + type: \'bar\'; + bar: string; +} + +type Foobar = Foo | Bar; + +function foobar(x: Foobar): string { + if (x.type === \'foo\') { + return foo(x); + } else if (x.type === \'bar\') { + return bar(x); + } else { + return \'unknown\'; + } +} + +function foo(x: Foo): string { + return x.foo; +} + +function bar(x: Bar): string { + return x.bar; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test interfaces-neg.js 1`] = ` +"/* @flow */ + +declare interface IDataBase { + id: string, + name: string, +} + +declare interface IUserData extends IDataBase { + kind: \"user\", +} + +declare interface ISystemData extends IDataBase { + kind: \"system\", +} + +declare type IData = IUserData | ISystemData; + +const data: IData = { + id: \"\", + name: \"\", + kind: \"system\", +} + +if (data.kind === \"user\") { + (data: ISystemData); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test interfaces-pos.js 1`] = ` +"/* @flow */ + +declare interface IDataBase { + id: string, + name: string, +} + +declare interface IUserData extends IDataBase { + kind: \"user\", +} + +declare interface ISystemData extends IDataBase { + kind: \"system\", +} + +declare type IData = IUserData | ISystemData; + +const data: IData = { + id: \"\", + name: \"\", + kind: \"system\", +} + +if (data.kind === \"system\") { + (data: ISystemData); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test type-decls-neg.js 1`] = ` +"/* @flow */ + +type DataBase = { + id: string, + name: string, +}; + +type UserData = { + id: string, + name: string, + kind: \"user\", +} + +type SystemData = { + id: string, + name: string, + kind: \"system\", +} + +declare type Data = UserData | SystemData; + +const data: Data = { + id: \"\", + name: \"\", + kind: \"system\", +} + +if (data.kind === \"user\") { + (data: SystemData); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test type-decls-pos.js 1`] = ` +"/* @flow */ + +type DataBase = { + id: string, + name: string, +}; + +type UserData = { + id: string, + name: string, + kind: \"user\", +} + +type SystemData = { + id: string, + name: string, + kind: \"system\", +} + +declare type Data = UserData | SystemData; + +const data: Data = { + id: \"\", + name: \"\", + kind: \"system\", +} + +if (data.kind === \"system\") { + (data: SystemData); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/tagged-unions/classes.js b/tests/tagged-unions/classes.js new file mode 100644 index 000000000000..0a1a0853dfbf --- /dev/null +++ b/tests/tagged-unions/classes.js @@ -0,0 +1,31 @@ +// @flow + +class Foo { + type: 'foo'; + foo: string; +} + +class Bar { + type: 'bar'; + bar: string; +} + +type Foobar = Foo | Bar; + +function foobar(x: Foobar): string { + if (x.type === 'foo') { + return foo(x); + } else if (x.type === 'bar') { + return bar(x); + } else { + return 'unknown'; + } +} + +function foo(x: Foo): string { + return x.foo; +} + +function bar(x: Bar): string { + return x.bar; +} diff --git a/tests/tagged-unions/interfaces-neg.js b/tests/tagged-unions/interfaces-neg.js new file mode 100644 index 000000000000..c9909d06ccad --- /dev/null +++ b/tests/tagged-unions/interfaces-neg.js @@ -0,0 +1,26 @@ +/* @flow */ + +declare interface IDataBase { + id: string, + name: string, +} + +declare interface IUserData extends IDataBase { + kind: "user", +} + +declare interface ISystemData extends IDataBase { + kind: "system", +} + +declare type IData = IUserData | ISystemData; + +const data: IData = { + id: "", + name: "", + kind: "system", +} + +if (data.kind === "user") { + (data: ISystemData); +} diff --git a/tests/tagged-unions/interfaces-pos.js b/tests/tagged-unions/interfaces-pos.js new file mode 100644 index 000000000000..533dfe171e7b --- /dev/null +++ b/tests/tagged-unions/interfaces-pos.js @@ -0,0 +1,26 @@ +/* @flow */ + +declare interface IDataBase { + id: string, + name: string, +} + +declare interface IUserData extends IDataBase { + kind: "user", +} + +declare interface ISystemData extends IDataBase { + kind: "system", +} + +declare type IData = IUserData | ISystemData; + +const data: IData = { + id: "", + name: "", + kind: "system", +} + +if (data.kind === "system") { + (data: ISystemData); +} diff --git a/tests/tagged-unions/jsfmt.spec.js b/tests/tagged-unions/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/tagged-unions/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/tagged-unions/type-decls-neg.js b/tests/tagged-unions/type-decls-neg.js new file mode 100644 index 000000000000..c7fbd789d1c5 --- /dev/null +++ b/tests/tagged-unions/type-decls-neg.js @@ -0,0 +1,30 @@ +/* @flow */ + +type DataBase = { + id: string, + name: string, +}; + +type UserData = { + id: string, + name: string, + kind: "user", +} + +type SystemData = { + id: string, + name: string, + kind: "system", +} + +declare type Data = UserData | SystemData; + +const data: Data = { + id: "", + name: "", + kind: "system", +} + +if (data.kind === "user") { + (data: SystemData); +} diff --git a/tests/tagged-unions/type-decls-pos.js b/tests/tagged-unions/type-decls-pos.js new file mode 100644 index 000000000000..dec1ed6a0c0a --- /dev/null +++ b/tests/tagged-unions/type-decls-pos.js @@ -0,0 +1,30 @@ +/* @flow */ + +type DataBase = { + id: string, + name: string, +}; + +type UserData = { + id: string, + name: string, + kind: "user", +} + +type SystemData = { + id: string, + name: string, + kind: "system", +} + +declare type Data = UserData | SystemData; + +const data: Data = { + id: "", + name: "", + kind: "system", +} + +if (data.kind === "system") { + (data: SystemData); +} diff --git a/tests/taint/__snapshots__/jsfmt.spec.js.snap b/tests/taint/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7acccb220455 --- /dev/null +++ b/tests/taint/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,453 @@ +exports[`test adder.js 1`] = ` +"// @flow + +function f(x : $Tainted, y : $Tainted) { + var z : $Tainted = x + y; +} +function f1(x : $Tainted, y : number) { + var z : $Tainted = x + y; +} +function f2(x : number, y : $Tainted) { + var z : $Tainted = x + y; +} +// This should cause an error. +function f3(x : $Tainted, y : number) { + var z : number = x + y; +} +// This should cause an error. +function f4(x : number, y : $Tainted) { + var z : number = x + y; +} +// This should cause an error. +function f5(x : number, y : $Tainted) { + var z : string = x + y; +} +// This should cause an error. +function f6(x : string, y : $Tainted) { + var z : string = x + y; +} +// This should cause an error. +function f7(x : $Tainted, y : $Tainted) { + var z : string = x + y; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test any_object.js 1`] = ` +"// @flow + +let tests = [ + // setting a property + function(x: $Tainted, y: string) { + let obj: Object = {}; + obj.foo = x; // error, taint ~> any + obj[y] = x; // error, taint ~> any + }, + + // getting a property + function() { + let obj: Object = { foo: \'foo\' }; + (obj.foo: $Tainted); // ok + }, + + // calling a method + function(x: $Tainted) { + let obj: Object = {}; + obj.foo(x); // error, taint ~> any + + let foo = obj.foo; + foo(x); // error, taint ~> any + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test call-object-property.js 1`] = ` +"// @flow + +function foo(x : $Tainted, o : Object) { + // Error + o.f(x); +} +function foo1(x : $Tainted, o : {f : (y : $Tainted) => void}) { + o.f(x); +} +function foo2(o1 : Object, o2 : {t : $Tainted}) { + o1.f(o2.t); +} +function foo3(x : $Tainted, o : {f : (y : $Tainted) => void}) { + o.f(x); +} +function f_foo1(x : $Tainted, f : Function) { + // Error + f(x); +} +function f_foo2(f1 : Function, o : {t : $Tainted}) { + f1(o.t); +} +function f_foo3(f1 : Function, o1 : Object, o2 : {t : $Tainted}) { + (f1(o1))(o2.t); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test comparator.js 1`] = ` +"// @flow +// Should cause an error. +function f(x : $Tainted, y : $Tainted) { + var z : $Tainted = x < y; +} +// Should cause an error. +function f1(x : string, y : $Tainted) { + var z : $Tainted = x < y; +} +// Should cause an error. +function f2(x : $Tainted, y : number) { + var z : $Tainted = x < y; +} +// Note: We allow removing Taint when two tainted +// values are compared. +function f3(x : $Tainted, y : string) { + var z : bool = x < y; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test function.js 1`] = ` +"// @flow + +let tests = [ + // flows any to each param + function(x: any, y: $Tainted) { + x(y); // error, taint ~> any + }, + + // calling \`any\` returns \`any\` + function(x: any, y: $Tainted) { + let z = x(); + z(y); + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test globals.js 1`] = ` +"// @flow + +class A { + f(x : $Tainted) { + fakeDocument.location = x; // error + doStuff(x); // ok + } + f1(x : $Tainted) { + // TODO(rcastano): should cause an error. + window.fakeLocation = x; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test lib.js 1`] = ` +"declare class FakeLocation { + assign(url: string): void; +} + +declare class FakeDocument { + location: FakeLocation; +} + +declare function doStuff(x: $Tainted): void; + +declare var fakeDocument: FakeDocument; +declare var fakeLocation: FakeLocation; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test taint1.js 1`] = ` +"/* + * + * @flow + */ +class A { + f(tainted : $Tainted) { + // This shouldn\'t give a warning (both are tainted) + var also_tainted : $Tainted = tainted; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test taint2.js 1`] = ` +"/* + * + * @flow + */ +class A { + f(tainted : $Tainted) { + // This *should* give a warning. + fakeDocument.location.assign(tainted); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test taint3.js 1`] = ` +"/* + * + * @flow + */ +class A { + f(tainted : $Tainted) { + // The Tainted annotation should still flow. + var safe = tainted; + // This should give a warning. + var loc : string = safe; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test taint4.js 1`] = ` +"/* + * + * @flow + */ + +var safe : string = \"safe\"; +// This should be allowed. +var tainted : $Tainted = safe + +function f(x : $Tainted) { + // Should cause error. + var y : any = x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test use-types.js 1`] = ` +"/* + * @flow + */ + +// Should cause an error. +function foo (x : $Tainted) { + var should_fail : number = x * 42; +} +// Should cause an error. +function foo1 (x : $Tainted<{f: number}>) { + var ok : number = x.f; +} +// Should cause an error. +function foo2 (o : {f (y:number):number}, t: $Tainted) { + return o.f(t); +} + +function foo3 (x : $Tainted<{f: number}>) { + var also_tainted : $Tainted = x.f; +} +// Should cause an error. +function foo4 (a : $Tainted>) { + var trusted : string = a[0]; +} +// Type error. +function foo5 (a : $Tainted>) { + var trusted_number : number = a[0]; +} + +function foo6 (a : $Tainted>) { + var trusted : $Tainted = a[0]; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/taint/adder.js b/tests/taint/adder.js new file mode 100644 index 000000000000..50dbaf2edae3 --- /dev/null +++ b/tests/taint/adder.js @@ -0,0 +1,31 @@ +// @flow + +function f(x : $Tainted, y : $Tainted) { + var z : $Tainted = x + y; +} +function f1(x : $Tainted, y : number) { + var z : $Tainted = x + y; +} +function f2(x : number, y : $Tainted) { + var z : $Tainted = x + y; +} +// This should cause an error. +function f3(x : $Tainted, y : number) { + var z : number = x + y; +} +// This should cause an error. +function f4(x : number, y : $Tainted) { + var z : number = x + y; +} +// This should cause an error. +function f5(x : number, y : $Tainted) { + var z : string = x + y; +} +// This should cause an error. +function f6(x : string, y : $Tainted) { + var z : string = x + y; +} +// This should cause an error. +function f7(x : $Tainted, y : $Tainted) { + var z : string = x + y; +} diff --git a/tests/taint/any_object.js b/tests/taint/any_object.js new file mode 100644 index 000000000000..6569b7b61069 --- /dev/null +++ b/tests/taint/any_object.js @@ -0,0 +1,25 @@ +// @flow + +let tests = [ + // setting a property + function(x: $Tainted, y: string) { + let obj: Object = {}; + obj.foo = x; // error, taint ~> any + obj[y] = x; // error, taint ~> any + }, + + // getting a property + function() { + let obj: Object = { foo: 'foo' }; + (obj.foo: $Tainted); // ok + }, + + // calling a method + function(x: $Tainted) { + let obj: Object = {}; + obj.foo(x); // error, taint ~> any + + let foo = obj.foo; + foo(x); // error, taint ~> any + }, +]; diff --git a/tests/taint/call-object-property.js b/tests/taint/call-object-property.js new file mode 100644 index 000000000000..7cece3014cf2 --- /dev/null +++ b/tests/taint/call-object-property.js @@ -0,0 +1,25 @@ +// @flow + +function foo(x : $Tainted, o : Object) { + // Error + o.f(x); +} +function foo1(x : $Tainted, o : {f : (y : $Tainted) => void}) { + o.f(x); +} +function foo2(o1 : Object, o2 : {t : $Tainted}) { + o1.f(o2.t); +} +function foo3(x : $Tainted, o : {f : (y : $Tainted) => void}) { + o.f(x); +} +function f_foo1(x : $Tainted, f : Function) { + // Error + f(x); +} +function f_foo2(f1 : Function, o : {t : $Tainted}) { + f1(o.t); +} +function f_foo3(f1 : Function, o1 : Object, o2 : {t : $Tainted}) { + (f1(o1))(o2.t); +} diff --git a/tests/taint/comparator.js b/tests/taint/comparator.js new file mode 100644 index 000000000000..defe902f0c6f --- /dev/null +++ b/tests/taint/comparator.js @@ -0,0 +1,18 @@ +// @flow +// Should cause an error. +function f(x : $Tainted, y : $Tainted) { + var z : $Tainted = x < y; +} +// Should cause an error. +function f1(x : string, y : $Tainted) { + var z : $Tainted = x < y; +} +// Should cause an error. +function f2(x : $Tainted, y : number) { + var z : $Tainted = x < y; +} +// Note: We allow removing Taint when two tainted +// values are compared. +function f3(x : $Tainted, y : string) { + var z : bool = x < y; +} diff --git a/tests/taint/function.js b/tests/taint/function.js new file mode 100644 index 000000000000..f007468ba5f8 --- /dev/null +++ b/tests/taint/function.js @@ -0,0 +1,14 @@ +// @flow + +let tests = [ + // flows any to each param + function(x: any, y: $Tainted) { + x(y); // error, taint ~> any + }, + + // calling `any` returns `any` + function(x: any, y: $Tainted) { + let z = x(); + z(y); + } +]; diff --git a/tests/taint/globals.js b/tests/taint/globals.js new file mode 100644 index 000000000000..18efa6515d2e --- /dev/null +++ b/tests/taint/globals.js @@ -0,0 +1,12 @@ +// @flow + +class A { + f(x : $Tainted) { + fakeDocument.location = x; // error + doStuff(x); // ok + } + f1(x : $Tainted) { + // TODO(rcastano): should cause an error. + window.fakeLocation = x; + } +} diff --git a/tests/taint/jsfmt.spec.js b/tests/taint/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/taint/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/taint/lib.js b/tests/taint/lib.js new file mode 100644 index 000000000000..3ca07bf6f6a4 --- /dev/null +++ b/tests/taint/lib.js @@ -0,0 +1,12 @@ +declare class FakeLocation { + assign(url: string): void; +} + +declare class FakeDocument { + location: FakeLocation; +} + +declare function doStuff(x: $Tainted): void; + +declare var fakeDocument: FakeDocument; +declare var fakeLocation: FakeLocation; diff --git a/tests/taint/taint1.js b/tests/taint/taint1.js new file mode 100644 index 000000000000..29b1260e0865 --- /dev/null +++ b/tests/taint/taint1.js @@ -0,0 +1,10 @@ +/* + * + * @flow + */ +class A { + f(tainted : $Tainted) { + // This shouldn't give a warning (both are tainted) + var also_tainted : $Tainted = tainted; + } +} diff --git a/tests/taint/taint2.js b/tests/taint/taint2.js new file mode 100644 index 000000000000..7322d8fe84c6 --- /dev/null +++ b/tests/taint/taint2.js @@ -0,0 +1,10 @@ +/* + * + * @flow + */ +class A { + f(tainted : $Tainted) { + // This *should* give a warning. + fakeDocument.location.assign(tainted); + } +} diff --git a/tests/taint/taint3.js b/tests/taint/taint3.js new file mode 100644 index 000000000000..1e3cb105a7dd --- /dev/null +++ b/tests/taint/taint3.js @@ -0,0 +1,12 @@ +/* + * + * @flow + */ +class A { + f(tainted : $Tainted) { + // The Tainted annotation should still flow. + var safe = tainted; + // This should give a warning. + var loc : string = safe; + } +} diff --git a/tests/taint/taint4.js b/tests/taint/taint4.js new file mode 100644 index 000000000000..61f2ee45b90f --- /dev/null +++ b/tests/taint/taint4.js @@ -0,0 +1,13 @@ +/* + * + * @flow + */ + +var safe : string = "safe"; +// This should be allowed. +var tainted : $Tainted = safe + +function f(x : $Tainted) { + // Should cause error. + var y : any = x; +} diff --git a/tests/taint/use-types.js b/tests/taint/use-types.js new file mode 100644 index 000000000000..07f081fec69e --- /dev/null +++ b/tests/taint/use-types.js @@ -0,0 +1,32 @@ +/* + * @flow + */ + +// Should cause an error. +function foo (x : $Tainted) { + var should_fail : number = x * 42; +} +// Should cause an error. +function foo1 (x : $Tainted<{f: number}>) { + var ok : number = x.f; +} +// Should cause an error. +function foo2 (o : {f (y:number):number}, t: $Tainted) { + return o.f(t); +} + +function foo3 (x : $Tainted<{f: number}>) { + var also_tainted : $Tainted = x.f; +} +// Should cause an error. +function foo4 (a : $Tainted>) { + var trusted : string = a[0]; +} +// Type error. +function foo5 (a : $Tainted>) { + var trusted_number : number = a[0]; +} + +function foo6 (a : $Tainted>) { + var trusted : $Tainted = a[0]; +} diff --git a/tests/template/__snapshots__/jsfmt.spec.js.snap b/tests/template/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..ad3180202c4f --- /dev/null +++ b/tests/template/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,64 @@ +exports[`test template.js 1`] = ` +"/* @flow */ + +(\`foo\`: string); // ok +(\`bar\`: 'bar'); // ok +(\`baz\`: number); // error + +\`foo \${123} bar\`; // ok, number can be appended to string +\`foo \${{bar: 123}} baz\`; // error, object can't be appended + +let tests = [ + function(x: string) { + \`foo \${x}\`; // ok + \`\${x} bar\`; // ok + \`foo \${'bar'} \${x}\`; // ok + }, + function(x: number) { + \`foo \${x}\`; // ok + \`\${x} bar\`; // ok + \`foo \${'bar'} \${x}\`; // ok + }, + function(x: boolean) { + \`foo \${x}\`; // error + \`\${x} bar\`; // error + \`foo \${'bar'} \${x}\`; // error + }, + function(x: mixed) { + \`foo \${x}\`; // error + \`\${x} bar\`; // error + \`foo \${'bar'} \${x}\`; // error + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +(\`foo\`: string);// ok +(\`bar\`: "bar");// ok +(\`baz\`: number);// error +\`foo \${123} bar\`;// ok, number can be appended to string +\`foo \${{ bar: 123 }} baz\`;// error, object can't be appended +let tests = [ + function(x: string) { + \`foo \${x}\`;// ok + \`\${x} bar\`;// ok + \`foo \${"bar"} \${x}\`;// ok + }, + function(x: number) { + \`foo \${x}\`;// ok + \`\${x} bar\`;// ok + \`foo \${"bar"} \${x}\`;// ok + }, + function(x: boolean) { + \`foo \${x}\`;// error + \`\${x} bar\`;// error + \`foo \${"bar"} \${x}\`;// error + }, + function(x: mixed) { + \`foo \${x}\`;// error + \`\${x} bar\`;// error + \`foo \${"bar"} \${x}\`;// error + } +]; + +" +`; diff --git a/tests/template/jsfmt.spec.js b/tests/template/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/template/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/template/template.js b/tests/template/template.js new file mode 100644 index 000000000000..5db2b3976cd3 --- /dev/null +++ b/tests/template/template.js @@ -0,0 +1,31 @@ +/* @flow */ + +(`foo`: string); // ok +(`bar`: 'bar'); // ok +(`baz`: number); // error + +`foo ${123} bar`; // ok, number can be appended to string +`foo ${{bar: 123}} baz`; // error, object can't be appended + +let tests = [ + function(x: string) { + `foo ${x}`; // ok + `${x} bar`; // ok + `foo ${'bar'} ${x}`; // ok + }, + function(x: number) { + `foo ${x}`; // ok + `${x} bar`; // ok + `foo ${'bar'} ${x}`; // ok + }, + function(x: boolean) { + `foo ${x}`; // error + `${x} bar`; // error + `foo ${'bar'} ${x}`; // error + }, + function(x: mixed) { + `foo ${x}`; // error + `${x} bar`; // error + `foo ${'bar'} ${x}`; // error + }, +]; diff --git a/tests/this/This.js b/tests/this/This.js new file mode 100644 index 000000000000..6656c4ae0463 --- /dev/null +++ b/tests/this/This.js @@ -0,0 +1,60 @@ +/* @providesModule This */ + +function F() { this.x = 0; } +F.prototype.m = function() { this.y = 0; } + +function foo(p:string) { } + +var o1 = new F(); // sets o1.x to 0 +o1.x = ""; +foo(o1.x); // ok by definite assignment + +var o2 = new F(); +o1.y = 0; +o2.y = ""; +foo(o2.y); // setting o1.y to 0 has no effect on o2.y + +var o3 = new F(); +o3.m(); // sets o3.y to 0 +o3.y = ""; +foo(o3.y); // ok by definite assignment +foo(o2.y); // setting o3.y to 0 has no effect on o2.y + +/* + * this bindings: + */ + +/* standard functions may rebind this */ +function f1() : number { + return this.x +} + +var f1_1 = f1.bind({x: 0})(); // ok +var f1_2 : string = f1.bind({x: 0})(); // error, number -> string +var f1_3 = f1.bind({x: ""})(); // error, string -> number +// TODO make this error blame the call site, rather than the function body +var f1_4 = f1(); // error, (global object).x + +/* arrow functions bind this at point of definition */ +/* top level arrow functions bind this to global object */ +var a1 = () => { + return this.x +} + +var ax = a1(); // error, (this:mixed).x + +/* nested arrows bind enclosing this (which may itself rebind) */ +function f2() : number { + var a2 = () => { return this.x }; + return a2() +} + +var f2_1 = f2.bind({x: 0})(); // ok +var f2_2 : string = f2.bind({x: 0})(); // error, number -> string +var f2_3 = f2.bind({x: ""})(); // error, string -> number +// TODO make this error blame the call site, rather than the function body +var f2_4 = f2(); // error, (global object).x + +(this: void); + +module.exports = true; diff --git a/tests/this/__snapshots__/jsfmt.spec.js.snap b/tests/this/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9541761fed9f --- /dev/null +++ b/tests/this/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,184 @@ +exports[`test This.js 1`] = ` +"/* @providesModule This */ + +function F() { this.x = 0; } +F.prototype.m = function() { this.y = 0; } + +function foo(p:string) { } + +var o1 = new F(); // sets o1.x to 0 +o1.x = ""; +foo(o1.x); // ok by definite assignment + +var o2 = new F(); +o1.y = 0; +o2.y = ""; +foo(o2.y); // setting o1.y to 0 has no effect on o2.y + +var o3 = new F(); +o3.m(); // sets o3.y to 0 +o3.y = ""; +foo(o3.y); // ok by definite assignment +foo(o2.y); // setting o3.y to 0 has no effect on o2.y + +/* + * this bindings: + */ + +/* standard functions may rebind this */ +function f1() : number { + return this.x +} + +var f1_1 = f1.bind({x: 0})(); // ok +var f1_2 : string = f1.bind({x: 0})(); // error, number -> string +var f1_3 = f1.bind({x: ""})(); // error, string -> number +// TODO make this error blame the call site, rather than the function body +var f1_4 = f1(); // error, (global object).x + +/* arrow functions bind this at point of definition */ +/* top level arrow functions bind this to global object */ +var a1 = () => { + return this.x +} + +var ax = a1(); // error, (this:mixed).x + +/* nested arrows bind enclosing this (which may itself rebind) */ +function f2() : number { + var a2 = () => { return this.x }; + return a2() +} + +var f2_1 = f2.bind({x: 0})(); // ok +var f2_2 : string = f2.bind({x: 0})(); // error, number -> string +var f2_3 = f2.bind({x: ""})(); // error, string -> number +// TODO make this error blame the call site, rather than the function body +var f2_4 = f2(); // error, (global object).x + +(this: void); + +module.exports = true; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule This */ +function F() { + this.x = 0; +} +F.prototype.m = function() { + this.y = 0; +}; +function foo(p: string) { + +} +var o1 = new F();// sets o1.x to 0 +o1.x = ""; +foo(o1.x);// ok by definite assignment +var o2 = new F(); +o1.y = 0; +o2.y = ""; +foo(o2.y);// setting o1.y to 0 has no effect on o2.y +var o3 = new F(); +o3.m();// sets o3.y to 0 +o3.y = ""; +foo(o3.y);// ok by definite assignment +foo(o2.y);// setting o3.y to 0 has no effect on o2.y +/* + * this bindings: + */ +/* standard functions may rebind this */ +function f1(): number { + return this.x; +} +var f1_1 = f1.bind({ x: 0 })();// ok +var f1_2: string = f1.bind({ x: 0 })();// error, number -> string +var f1_3 = f1.bind({ x: "" })();// error, string -> number +// TODO make this error blame the call site, rather than the function body +var f1_4 = f1();// error, (global object).x +/* arrow functions bind this at point of definition */ +/* top level arrow functions bind this to global object */ +var a1 = () => { + return this.x; +}; +var ax = a1();// error, (this:mixed).x +/* nested arrows bind enclosing this (which may itself rebind) */ +function f2(): number { + var a2 = () => { + return this.x; + }; + return a2(); +} +var f2_1 = f2.bind({ x: 0 })();// ok +var f2_2: string = f2.bind({ x: 0 })();// error, number -> string +var f2_3 = f2.bind({ x: "" })();// error, string -> number +// TODO make this error blame the call site, rather than the function body +var f2_4 = f2();// error, (global object).x +(this: void); +module.exports = true; + +" +`; + +exports[`test arrows.js 1`] = ` +"class C { + foo() { + return () => { return this.bar(); }; // OK, since this: C + } + bar() { return this; } // return type is C +} +var c = new C; +var f = c.foo(); +var i = f(); // OK +(i: C); // OK + +class D extends C { } +var d = new D; +var g = d.foo(); +var j = g(); // OK +(j: D); // error, since return type of bar is C, not the type of \`this\` + +class E { + foo(x: number) { } +} +class F extends E { + foo() { // OK to override with generalization + (() => { + super.foo(""); // find super method, error due to incorrect arg + })(); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + foo() { + return () => { + return this.bar(); + };// OK, since this: C + } + bar() { + return this; + }// return type is C +} +var c = new C(); +var f = c.foo(); +var i = f();// OK +(i: C);// OK +class D extends C {} +var d = new D(); +var g = d.foo(); +var j = g();// OK +(j: D);// error, since return type of bar is C, not the type of \`this\` +class E { + foo(x: number) { + + } +} +class F extends E { + foo() { + // OK to override with generalization + (() => { + super.foo("");// find super method, error due to incorrect arg + })(); + } +} + +" +`; diff --git a/tests/this/arrows.js b/tests/this/arrows.js new file mode 100644 index 000000000000..2217bf0b7d56 --- /dev/null +++ b/tests/this/arrows.js @@ -0,0 +1,27 @@ +class C { + foo() { + return () => { return this.bar(); }; // OK, since this: C + } + bar() { return this; } // return type is C +} +var c = new C; +var f = c.foo(); +var i = f(); // OK +(i: C); // OK + +class D extends C { } +var d = new D; +var g = d.foo(); +var j = g(); // OK +(j: D); // error, since return type of bar is C, not the type of `this` + +class E { + foo(x: number) { } +} +class F extends E { + foo() { // OK to override with generalization + (() => { + super.foo(""); // find super method, error due to incorrect arg + })(); + } +} diff --git a/tests/this/jsfmt.spec.js b/tests/this/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/this/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/this_ctor/__snapshots__/jsfmt.spec.js.snap b/tests/this_ctor/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2c702518c36a --- /dev/null +++ b/tests/this_ctor/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,36 @@ +exports[`test test.js 1`] = ` +"class A { + n: number; + constructor(n: number) { + this.n = n; + } + clone(): A { + return new this.constructor(this.n); + } + badClone(): number { + return new this.constructor(this.n); // Error A ~> number + } +} + +var a1 = new A(1); +var a2: A = new a1.constructor(2); +var a3: A = a2.clone(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A { + n: number; + constructor(n: number) { + this.n = n; + } + clone(): A { + return new this.constructor(this.n); + } + badClone(): number { + return new this.constructor(this.n);// Error A ~> number + } +} +var a1 = new A(1); +var a2: A = new a1.constructor(2); +var a3: A = a2.clone(); + +" +`; diff --git a/tests/this_ctor/jsfmt.spec.js b/tests/this_ctor/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/this_ctor/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/this_ctor/test.js b/tests/this_ctor/test.js new file mode 100644 index 000000000000..cbcc6e218d1f --- /dev/null +++ b/tests/this_ctor/test.js @@ -0,0 +1,16 @@ +class A { + n: number; + constructor(n: number) { + this.n = n; + } + clone(): A { + return new this.constructor(this.n); + } + badClone(): number { + return new this.constructor(this.n); // Error A ~> number + } +} + +var a1 = new A(1); +var a2: A = new a1.constructor(2); +var a3: A = a2.clone(); diff --git a/tests/this_type/__snapshots__/jsfmt.spec.js.snap b/tests/this_type/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..887bf7880742 --- /dev/null +++ b/tests/this_type/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,474 @@ +exports[`test class_expr.js 1`] = ` +"/* @flow */ +// issue #1191 + +const Thing = class Thing { + zark() { + this.x = 123; // error: property not found (must be declared) + } +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// issue #1191 +const Thing = class Thing { + zark() { + this.x = 123;// error: property not found (must be declared) + } +}; + +" +`; + +exports[`test contra.js 1`] = ` +"// Counterexample with contravariant this type + +class C { + next: this; // error (see below for exploit): \`this\` should only appear in + // covariant positions +} + +class D extends C { } + +var d = new D(); +(d: C).next = new C; +(d.next: D); // sneaky + +class A { + foo(that: X) { } // error: can\'t hide contravariance using a bound +} + +class B extends A { + foo(that: Y) { } // error (see above, catches hidden override) +} + +// covariance checks on this type in invariant positions + +class Invariant { + out_object(): { _: this } { return { _: this }; } + in_object(_: { _: this }) { } + inout_object: { _: this }; + + out_array(): Array { return [this]; } + in_array(_: Array) { } + inout_array: Array; +} + +// covariance checks on this type as type args + +class Misc { + // Set has invariant X + out_set(): Set { return new Set().add(this); } + in_set(_: Set) { } + inout_set: Set; + + // Promise has covariant X + async out_promise(): Promise { return this; } + in_promise(_: Promise) { } + inout_promise: Promise; + + // Generator has covariant X, covariant Y, contravariant Z + *out_generator(): Generator { + yield this; + return this; + } + in_generator(_: Generator) { } + inout_generator: Generator; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test export.js 1`] = ` +"export class A1 { + foo(): this { return this; } + bar(): this { return this; } +} + +export class A2 { + foo(): this { return this; } + bar(): this { return this; } + qux(x: X): X { return x; } +} + +export class A3 extends A2 {} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test generics.js 1`] = ` +"class Generic { + clone(): Generic { return this; } +} + +class Implicit { arg: X; val: X; } +class ImplicitNumber extends Implicit { arg: number; } + +(new ImplicitNumber().val: string) // error: number ~> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test import.js 1`] = ` +"// Check that imports are handled properly with this types + +import { A1 } from \'./export\'; +import type { A2 } from \'./export\'; +import { A3 } from \'./export\'; + +class B1 extends A1 { + foo(): B1 { return new B1(); } // error +} + +(new B1().bar(): B1); // OK + +class B3 extends A3 { + foo(): B3 { return new B3(); } // error +} + +(new B3().bar(): B3<*>); // OK +(new B3().qux(0): string); // error + +(new B3().bar(): A2<*>); // OK +((new B3().bar(): B3): A2); // error +((new B3(): A2).qux(0): string); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test interface.js 1`] = ` +"interface I { xs: Array; } +interface J { f(): J; } +class C { + xs: Array; + f(): C { return this; } +} +function foo(c: C): I { return c; } +function bar(c: C): J { return c; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; + +exports[`test lib_client.js 1`] = ` +"(new DoublyLinkedList().prev(): DoublyLinkedList); +(new DoublyLinkedList().next(): DoublyLinkedList) + +var MiniImmutable = require(\"mini-immutable\"); +class C { + map: MiniImmutable.OrderedMap; + update() { + this.map = this.map.set(0,\"\"); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test self.js 1`] = ` +"class A { + foo() { return this; } // return of foo is not annotated to get around + // substituting this below + bar(): this { return new A().foo(); } // same as returning : A, so error + qux(): this { return this.bar(); } // OK (don\'t cascade errors) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class A { + foo() { + return this; + }// return of foo is not annotated to get around// substituting this below + bar(): this { + return new A().foo(); + }// same as returning : A, so error + qux(): this { + return this.bar(); + }// OK (don\'t cascade errors) +} + +" +`; + +exports[`test statics.js 1`] = ` +"// supporting \`this\` type in statics + +class A { + static make(): this { // factory method, whose return type \`this\` (still) + // describes instances of A or subclasses of A: the + // meaning of the \`this\` type is not changed simply by + // switching into a static context + return new this; // but in a static context, the value \`this\` is bound to + // the class, instead of instances of the class + } +} +class B extends A { } // inherits statics method too, with \`this\` bound to the class + +(A.make(): A); // OK +(B.make(): B); // OK +(B.make(): A); // OK +(A.make(): B); // error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// supporting \`this\` type in statics +class A { + make(): this { + // factory method, whose return type \`this\` (still) + // describes instances of A or subclasses of A: the + // meaning of the \`this\` type is not changed simply by + // switching into a static context + return new this();// but in a static context, the value \`this\` is bound to// the class, instead of instances of the class + } +} +class B extends A {}// inherits statics method too, with \`this\` bound to the class +(A.make(): A);// OK +(B.make(): B);// OK +(B.make(): A);// OK +(A.make(): B);// error + +" +`; + +exports[`test test.js 1`] = ` +"// Examples without \`this\` types (compare with examples below) + +class Base { + foo() { return this; } + qux() { return new Base; } + + bar() { return this; } + bar_caller() { return this.bar(); } +} + +class Inherit extends Base { } + +class Override extends Base { + foo() { return this; } // OK + qux() { return this; } // OK, too + + bar() { return new Override; } // OK (cf. error below) +} + +class InheritOverride extends Override { } + +(new Inherit().foo(): Base); +(new Inherit().foo(): Inherit); // error (cf. OK below) +((new Inherit(): Base).foo(): Base); +(new Override().foo(): Base); +(new Override().foo(): Override); // OK +((new Override(): Base).foo(): Base); + +(new InheritOverride().bar_caller(): InheritOverride); // error + // blame flips below + +// Examples with \`this\` types (compare with examples above) + +class Base2 { + foo(): this { return this; } + qux(): Base2 { return new Base2; } + + bar(): this { return this; } + bar_caller(): this { return this.bar(); } + + corge(that: this) { } + grault(that: Base2) { } +} + +class Inherit2 extends Base2 { } + +class Override2 extends Base2 { + foo(): this { return this; } // OK + qux(): this { return this; } // OK, too + + bar(): Override2 { return new Override2; } // error (cf. OK above) + // see exploit below + + corge(that: this) { } // error + // see exploit below + grault(that: this) { } // error, too +} + +class InheritOverride2 extends Override2 { } + +(new Inherit2().foo(): Base2); +(new Inherit2().foo(): Inherit2); // OK (cf. error above) +((new Inherit2(): Base2).foo(): Base2); +(new Override2().foo(): Base2); +(new Override2().foo(): Override2); // OK +((new Override2(): Base2).foo(): Base2); + +(new InheritOverride2().bar_caller(): InheritOverride2); // exploits error above + +(new Override2(): Base2).corge(new Base2()); // exploits error above +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Examples without \`this\` types (compare with examples below) +class Base { + foo() { + return this; + } + qux() { + return new Base(); + } + bar() { + return this; + } + bar_caller() { + return this.bar(); + } +} +class Inherit extends Base {} +class Override extends Base { + foo() { + return this; + }// OK + qux() { + return this; + }// OK, too + bar() { + return new Override(); + }// OK (cf. error below) +} +class InheritOverride extends Override {} +(new Inherit().foo(): Base); +(new Inherit().foo(): Inherit);// error (cf. OK below) +((new Inherit(): Base).foo(): Base); +(new Override().foo(): Base); +(new Override().foo(): Override);// OK +((new Override(): Base).foo(): Base); +(new InheritOverride().bar_caller(): InheritOverride);// error// blame flips below +// Examples with \`this\` types (compare with examples above) +class Base2 { + foo(): this { + return this; + } + qux(): Base2 { + return new Base2(); + } + bar(): this { + return this; + } + bar_caller(): this { + return this.bar(); + } + corge(that: this) { + + } + grault(that: Base2) { + + } +} +class Inherit2 extends Base2 {} +class Override2 extends Base2 { + foo(): this { + return this; + }// OK + qux(): this { + return this; + }// OK, too + bar(): Override2 { + return new Override2(); + }// error (cf. OK above)// see exploit below + corge(that: this) { + + }// error// see exploit below + grault(that: this) { + + }// error, too +} +class InheritOverride2 extends Override2 {} +(new Inherit2().foo(): Base2); +(new Inherit2().foo(): Inherit2);// OK (cf. error above) +((new Inherit2(): Base2).foo(): Base2); +(new Override2().foo(): Base2); +(new Override2().foo(): Override2);// OK +((new Override2(): Base2).foo(): Base2); +(new InheritOverride2().bar_caller(): InheritOverride2);// exploits error above +(new Override2(): Base2).corge(new Base2());// exploits error above + +" +`; diff --git a/tests/this_type/class_expr.js b/tests/this_type/class_expr.js new file mode 100644 index 000000000000..9001dfc7b639 --- /dev/null +++ b/tests/this_type/class_expr.js @@ -0,0 +1,8 @@ +/* @flow */ +// issue #1191 + +const Thing = class Thing { + zark() { + this.x = 123; // error: property not found (must be declared) + } +}; diff --git a/tests/this_type/contra.js b/tests/this_type/contra.js new file mode 100644 index 000000000000..1bb3c3397614 --- /dev/null +++ b/tests/this_type/contra.js @@ -0,0 +1,54 @@ +// Counterexample with contravariant this type + +class C { + next: this; // error (see below for exploit): `this` should only appear in + // covariant positions +} + +class D extends C { } + +var d = new D(); +(d: C).next = new C; +(d.next: D); // sneaky + +class A { + foo(that: X) { } // error: can't hide contravariance using a bound +} + +class B extends A { + foo(that: Y) { } // error (see above, catches hidden override) +} + +// covariance checks on this type in invariant positions + +class Invariant { + out_object(): { _: this } { return { _: this }; } + in_object(_: { _: this }) { } + inout_object: { _: this }; + + out_array(): Array { return [this]; } + in_array(_: Array) { } + inout_array: Array; +} + +// covariance checks on this type as type args + +class Misc { + // Set has invariant X + out_set(): Set { return new Set().add(this); } + in_set(_: Set) { } + inout_set: Set; + + // Promise has covariant X + async out_promise(): Promise { return this; } + in_promise(_: Promise) { } + inout_promise: Promise; + + // Generator has covariant X, covariant Y, contravariant Z + *out_generator(): Generator { + yield this; + return this; + } + in_generator(_: Generator) { } + inout_generator: Generator; +} diff --git a/tests/this_type/export.js b/tests/this_type/export.js new file mode 100644 index 000000000000..57303de679e7 --- /dev/null +++ b/tests/this_type/export.js @@ -0,0 +1,12 @@ +export class A1 { + foo(): this { return this; } + bar(): this { return this; } +} + +export class A2 { + foo(): this { return this; } + bar(): this { return this; } + qux(x: X): X { return x; } +} + +export class A3 extends A2 {} diff --git a/tests/this_type/generics.js b/tests/this_type/generics.js new file mode 100644 index 000000000000..0514ed85ae1f --- /dev/null +++ b/tests/this_type/generics.js @@ -0,0 +1,8 @@ +class Generic { + clone(): Generic { return this; } +} + +class Implicit { arg: X; val: X; } +class ImplicitNumber extends Implicit { arg: number; } + +(new ImplicitNumber().val: string) // error: number ~> string diff --git a/tests/this_type/import.js b/tests/this_type/import.js new file mode 100644 index 000000000000..b742e07d7a68 --- /dev/null +++ b/tests/this_type/import.js @@ -0,0 +1,22 @@ +// Check that imports are handled properly with this types + +import { A1 } from './export'; +import type { A2 } from './export'; +import { A3 } from './export'; + +class B1 extends A1 { + foo(): B1 { return new B1(); } // error +} + +(new B1().bar(): B1); // OK + +class B3 extends A3 { + foo(): B3 { return new B3(); } // error +} + +(new B3().bar(): B3<*>); // OK +(new B3().qux(0): string); // error + +(new B3().bar(): A2<*>); // OK +((new B3().bar(): B3): A2); // error +((new B3(): A2).qux(0): string); // error diff --git a/tests/this_type/interface.js b/tests/this_type/interface.js new file mode 100644 index 000000000000..0c1de6a4c9a2 --- /dev/null +++ b/tests/this_type/interface.js @@ -0,0 +1,8 @@ +interface I { xs: Array; } +interface J { f(): J; } +class C { + xs: Array; + f(): C { return this; } +} +function foo(c: C): I { return c; } +function bar(c: C): J { return c; } diff --git a/tests/this_type/jsfmt.spec.js b/tests/this_type/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/this_type/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/this_type/lib/__snapshots__/jsfmt.spec.js.snap b/tests/this_type/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..04cd629de70f --- /dev/null +++ b/tests/this_type/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,38 @@ +exports[`test decl.js 1`] = ` +"// The following declare classes use \`this\` types effectively to avoid type +// errors in ../lib_client.js. If support for \`this\` types in declare classes +// is disabled for perf reasons, these will produce warnings. + +declare class LinkedList { + next(): this; +} +declare class DoublyLinkedList extends LinkedList { + prev(): this; +} + +declare module \"mini-immutable\" { + declare class Map { + set(key: K, value: V): this; // more precise than Map (see below) + } + declare class OrderedMap extends Map { + // inherits set method returning OrderedMap instead of Map + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/this_type/lib/decl.js b/tests/this_type/lib/decl.js new file mode 100644 index 000000000000..f3f3e398a68e --- /dev/null +++ b/tests/this_type/lib/decl.js @@ -0,0 +1,19 @@ +// The following declare classes use `this` types effectively to avoid type +// errors in ../lib_client.js. If support for `this` types in declare classes +// is disabled for perf reasons, these will produce warnings. + +declare class LinkedList { + next(): this; +} +declare class DoublyLinkedList extends LinkedList { + prev(): this; +} + +declare module "mini-immutable" { + declare class Map { + set(key: K, value: V): this; // more precise than Map (see below) + } + declare class OrderedMap extends Map { + // inherits set method returning OrderedMap instead of Map + } +} diff --git a/tests/this_type/lib/jsfmt.spec.js b/tests/this_type/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/this_type/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/this_type/lib_client.js b/tests/this_type/lib_client.js new file mode 100644 index 000000000000..e646c7d721ab --- /dev/null +++ b/tests/this_type/lib_client.js @@ -0,0 +1,10 @@ +(new DoublyLinkedList().prev(): DoublyLinkedList); +(new DoublyLinkedList().next(): DoublyLinkedList) + +var MiniImmutable = require("mini-immutable"); +class C { + map: MiniImmutable.OrderedMap; + update() { + this.map = this.map.set(0,""); + } +} diff --git a/tests/this_type/self.js b/tests/this_type/self.js new file mode 100644 index 000000000000..68a8db1e0f2d --- /dev/null +++ b/tests/this_type/self.js @@ -0,0 +1,6 @@ +class A { + foo() { return this; } // return of foo is not annotated to get around + // substituting this below + bar(): this { return new A().foo(); } // same as returning : A, so error + qux(): this { return this.bar(); } // OK (don't cascade errors) +} diff --git a/tests/this_type/statics.js b/tests/this_type/statics.js new file mode 100644 index 000000000000..c2ed665599c6 --- /dev/null +++ b/tests/this_type/statics.js @@ -0,0 +1,17 @@ +// supporting `this` type in statics + +class A { + static make(): this { // factory method, whose return type `this` (still) + // describes instances of A or subclasses of A: the + // meaning of the `this` type is not changed simply by + // switching into a static context + return new this; // but in a static context, the value `this` is bound to + // the class, instead of instances of the class + } +} +class B extends A { } // inherits statics method too, with `this` bound to the class + +(A.make(): A); // OK +(B.make(): B); // OK +(B.make(): A); // OK +(A.make(): B); // error diff --git a/tests/this_type/test.js b/tests/this_type/test.js new file mode 100644 index 000000000000..a47b3ca57ca8 --- /dev/null +++ b/tests/this_type/test.js @@ -0,0 +1,70 @@ +// Examples without `this` types (compare with examples below) + +class Base { + foo() { return this; } + qux() { return new Base; } + + bar() { return this; } + bar_caller() { return this.bar(); } +} + +class Inherit extends Base { } + +class Override extends Base { + foo() { return this; } // OK + qux() { return this; } // OK, too + + bar() { return new Override; } // OK (cf. error below) +} + +class InheritOverride extends Override { } + +(new Inherit().foo(): Base); +(new Inherit().foo(): Inherit); // error (cf. OK below) +((new Inherit(): Base).foo(): Base); +(new Override().foo(): Base); +(new Override().foo(): Override); // OK +((new Override(): Base).foo(): Base); + +(new InheritOverride().bar_caller(): InheritOverride); // error + // blame flips below + +// Examples with `this` types (compare with examples above) + +class Base2 { + foo(): this { return this; } + qux(): Base2 { return new Base2; } + + bar(): this { return this; } + bar_caller(): this { return this.bar(); } + + corge(that: this) { } + grault(that: Base2) { } +} + +class Inherit2 extends Base2 { } + +class Override2 extends Base2 { + foo(): this { return this; } // OK + qux(): this { return this; } // OK, too + + bar(): Override2 { return new Override2; } // error (cf. OK above) + // see exploit below + + corge(that: this) { } // error + // see exploit below + grault(that: this) { } // error, too +} + +class InheritOverride2 extends Override2 { } + +(new Inherit2().foo(): Base2); +(new Inherit2().foo(): Inherit2); // OK (cf. error above) +((new Inherit2(): Base2).foo(): Base2); +(new Override2().foo(): Base2); +(new Override2().foo(): Override2); // OK +((new Override2(): Base2).foo(): Base2); + +(new InheritOverride2().bar_caller(): InheritOverride2); // exploits error above + +(new Override2(): Base2).corge(new Base2()); // exploits error above diff --git a/tests/throw/__snapshots__/jsfmt.spec.js.snap b/tests/throw/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..14240dc16502 --- /dev/null +++ b/tests/throw/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,46 @@ +exports[`test test.js 1`] = ` +"/** + * @flow + */ + +function f(): number { + throw new Error(); // OK to not return +} + +function g(a: ?string) { + if (a == null) { + throw new Error(); + } + return a*1; // a is not null +} + +function h(x: number): string { + if (x) { + return 'foo'; + } else { + throw new Error(); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +function f(): number { + throw new Error();// OK to not return +} +function g(a: ?string) { + if (a == null) { + throw new Error(); + } + return a * 1;// a is not null +} +function h(x: number): string { + if (x) { + return "foo"; + } else { + throw new Error(); + } +} + +" +`; diff --git a/tests/throw/jsfmt.spec.js b/tests/throw/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/throw/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/throw/test.js b/tests/throw/test.js new file mode 100644 index 000000000000..a77bd4752c38 --- /dev/null +++ b/tests/throw/test.js @@ -0,0 +1,22 @@ +/** + * @flow + */ + +function f(): number { + throw new Error(); // OK to not return +} + +function g(a: ?string) { + if (a == null) { + throw new Error(); + } + return a*1; // a is not null +} + +function h(x: number): string { + if (x) { + return 'foo'; + } else { + throw new Error(); + } +} diff --git a/tests/traces/Traces.js b/tests/traces/Traces.js new file mode 100644 index 000000000000..50dc2194f4c5 --- /dev/null +++ b/tests/traces/Traces.js @@ -0,0 +1,20 @@ +// arg/param type mismatch on arg 0 +function g0(y:string) { } +function f0(x) { g0(x) } +f0(0); + +// ...on arg n +function g1(a:string, b:string) { } +function f1(x, y) { g1(x, y) } +f1("hey", 0); + +// h/o call with function expr +function g2(ylam: (s:string) => number) { } +function f2(xlam) { g2(xlam) } +f2(function(x) { return x * x }); + +// h/o call with function def +function g3(ylam: (s:string) => number) { } +function f3(xlam) { g3(xlam) } +function double(n) { return n * 2 } +f3(double); diff --git a/tests/traces/Traces2.js b/tests/traces/Traces2.js new file mode 100644 index 000000000000..89089d9a4f2f --- /dev/null +++ b/tests/traces/Traces2.js @@ -0,0 +1,19 @@ +// @flow + +var React = require('react'); + +var A = React.createClass({ + propTypes: { foo: React.PropTypes.string.isRequired } +}); + +var B = React.createClass({ + propTypes: { bar: React.PropTypes.string.isRequired } +}); + +function f(b): React.Element<*> { + if (b) { + return ; + } else { + return ; + } +} diff --git a/tests/traces/__snapshots__/jsfmt.spec.js.snap b/tests/traces/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..18c2d489deab --- /dev/null +++ b/tests/traces/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,78 @@ +exports[`test Traces.js 1`] = ` +"// arg/param type mismatch on arg 0 +function g0(y:string) { } +function f0(x) { g0(x) } +f0(0); + +// ...on arg n +function g1(a:string, b:string) { } +function f1(x, y) { g1(x, y) } +f1(\"hey\", 0); + +// h/o call with function expr +function g2(ylam: (s:string) => number) { } +function f2(xlam) { g2(xlam) } +f2(function(x) { return x * x }); + +// h/o call with function def +function g3(ylam: (s:string) => number) { } +function f3(xlam) { g3(xlam) } +function double(n) { return n * 2 } +f3(double); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test Traces2.js 1`] = ` +"// @flow + +var React = require(\'react\'); + +var A = React.createClass({ + propTypes: { foo: React.PropTypes.string.isRequired } +}); + +var B = React.createClass({ + propTypes: { bar: React.PropTypes.string.isRequired } +}); + +function f(b): React.Element<*> { + if (b) { + return ; + } else { + return ; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/traces/jsfmt.spec.js b/tests/traces/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/traces/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/traits/__snapshots__/jsfmt.spec.js.snap b/tests/traits/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..65e29e8fc244 --- /dev/null +++ b/tests/traits/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,54 @@ +exports[`test test.js 1`] = ` +"declare class Foo extends Qux mixins Bar { + // KeyedCollection <: Collection + // ...KeyedIterable +} +declare class Bar extends Baz { + // KeyedIterable <: Iterable + y: T +} +declare class Qux extends Baz { + // Collection <: Iterable + y: T, z: T +} +declare class Baz { + // Iterable + x: T +} + +((new Foo).x: number); // error: Qux wins +((new Foo).y: string); // error: Bar wins +((new Foo).z: number); // error: Qux wins +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare class Foo {} +declare class Bar { // KeyedIterable <: Iterable y: T } +declare class Qux { // Collection <: Iterable y: T, z: T } +declare class Baz { // Iterable x: T } +(new Foo().x: number);// error: Qux wins +(new Foo().y: string);// error: Bar wins +(new Foo().z: number);// error: Qux wins + +" +`; + +exports[`test test2.js 1`] = ` +"declare interface I { } +declare class C mixins I { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1391 + fromString(\", \").join(path.map(print, \"extends\")) + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1391:28) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at /src/printer.js:1601:18 + at FastPath.map (/src/fast-path.js:167:19) + at printStatementSequence (/src/printer.js:1586:8) + at /src/printer.js:238:16 + at FastPath.call (/src/fast-path.js:113:16) +" +`; diff --git a/tests/traits/jsfmt.spec.js b/tests/traits/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/traits/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/traits/test.js b/tests/traits/test.js new file mode 100644 index 000000000000..569907ac1a9c --- /dev/null +++ b/tests/traits/test.js @@ -0,0 +1,20 @@ +declare class Foo extends Qux mixins Bar { + // KeyedCollection <: Collection + // ...KeyedIterable +} +declare class Bar extends Baz { + // KeyedIterable <: Iterable + y: T +} +declare class Qux extends Baz { + // Collection <: Iterable + y: T, z: T +} +declare class Baz { + // Iterable + x: T +} + +((new Foo).x: number); // error: Qux wins +((new Foo).y: string); // error: Bar wins +((new Foo).z: number); // error: Qux wins diff --git a/tests/traits/test2.js b/tests/traits/test2.js new file mode 100644 index 000000000000..244d25a93ed5 --- /dev/null +++ b/tests/traits/test2.js @@ -0,0 +1,2 @@ +declare interface I { } +declare class C mixins I { } diff --git a/tests/try/__snapshots__/jsfmt.spec.js.snap b/tests/try/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1174df0a3b97 --- /dev/null +++ b/tests/try/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,567 @@ +exports[`test abnormals.js 1`] = ` +"/* @flow */ + +/* This test documents an issue we used to have with merging the environment of + * the try block and the catch block. The error variable, when inspected and in + * the presence of an abnormal, would sometimes kind of leak. It would hit an + * abnormal. It was weird. + */ +function foo() { + try { + } catch(error) { + if (error.foo === 4) { + throw error; + } + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +/* This test documents an issue we used to have with merging the environment of + * the try block and the catch block. The error variable, when inspected and in + * the presence of an abnormal, would sometimes kind of leak. It would hit an + * abnormal. It was weird. + */ +function foo() { + try { + + } catch (error) { + if (error.foo === 4) { + throw error; + } + } +} + +" +`; + +exports[`test init.js 1`] = ` +"/*** + * test initialization tracking of hoisted stuff + * @flow + */ + +// for illustrative purposes only - Flow considers a throw possible +// anywhere within a block +function might_throw() {} + +// local use of annotated var within try is ok +function f() { + try { + var x:number = 0; + var y:number = x; + } catch (e) { + } +} + +// and within catch +function f() { + try { + } catch (e) { + var x:number = 0; + var y:number = x; + } +} + +// but not across try/catch +function f() { + try { + might_throw(); + var x:number = 0; + } catch (e) { + var y:number = x; // error + } +} + +// or try/finally +function f() { + try { + might_throw(); + var x:number = 0; + } finally { + var y:number = x; // error + } +} + +// or catch/finally +function f() { + try { + } catch (e) { + var x:number = 0; + } finally { + var y:number = x; // error + } +} + +// or try/catch/finally if init doesn't dominate +function f() { + try { + var x:number = 0; + } catch (e) { + might_throw(); + var x:number = 0; + } finally { + var y:number = x; // error + } +} + +// post-use ok because init dominates here +function f() { + try { + var x:number = 0; + } catch (e) { + might_throw(); // ...but if so, suffix is not reached + var x:number = 0; + } + var y:number = x; +} + +// and here +function f() { + try { + } catch (e) { + } finally { + might_throw(); // ...but if so, suffix is not reached + var x:number = 0; + } + var y:number = x; +} + +// and here +function f() { + try { + var x:number; + } catch (e) { + } finally { + might_throw(); // ...but if so, suffix is not reached + x = 0; + } + var y:number = x; +} + +// and here, thank you JS for the wonder that is hoisting +function f() { + try { + } catch (e) { + var x:number; + } finally { + might_throw(); // ...but if so, suffix is not reached + x = 0; + } + var y:number = x; +} + +// error if used prior to init +function f() { + var y:number = x; // error + try { + var x:number = 0; + } catch (e) { + } +} + +// another non-dominated post +function f() { + try { + var x:number = 0; + } catch (e) { + } + var y:number = x; // error +} + +// ditto +function f() { + try { + } catch (e) { + var x:number = 0; + } + var y:number = x; // error +} + +// ditto +function f(b) { + try { + var x:number; + if (b) { + throw new Error(); + } + x = 0; + } catch (e) { + } + var y:number = x; // error +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/*** + * test initialization tracking of hoisted stuff + * @flow + */ +// for illustrative purposes only - Flow considers a throw possible +// anywhere within a block +function might_throw() { + +} +// local use of annotated var within try is ok +function f() { + try { + var x: number = 0; + var y: number = x; + } catch (e) { + + } +} +// and within catch +function f() { + try { + + } catch (e) { + var x: number = 0; + var y: number = x; + } +} +// but not across try/catch +function f() { + try { + might_throw(); + var x: number = 0; + } catch (e) { + var y: number = x;// error + } +} +// or try/finally +function f() { + try { + might_throw(); + var x: number = 0; + } finally { + var y: number = x;// error + } +} +// or catch/finally +function f() { + try { + + } catch (e) { + var x: number = 0; + } finally { + var y: number = x;// error + } +} +// or try/catch/finally if init doesn't dominate +function f() { + try { + var x: number = 0; + } catch (e) { + might_throw(); + var x: number = 0; + } finally { + var y: number = x;// error + } +} +// post-use ok because init dominates here +function f() { + try { + var x: number = 0; + } catch (e) { + might_throw();// ...but if so, suffix is not reached + var x: number = 0; + } + var y: number = x; +} +// and here +function f() { + try { + + } catch (e) { + + } finally { + might_throw();// ...but if so, suffix is not reached + var x: number = 0; + } + var y: number = x; +} +// and here +function f() { + try { + var x: number; + } catch (e) { + + } finally { + might_throw();// ...but if so, suffix is not reached + x = 0; + } + var y: number = x; +} +// and here, thank you JS for the wonder that is hoisting +function f() { + try { + + } catch (e) { + var x: number; + } finally { + might_throw();// ...but if so, suffix is not reached + x = 0; + } + var y: number = x; +} +// error if used prior to init +function f() { + var y: number = x;// error + try { + var x: number = 0; + } catch (e) { + + } +} +// another non-dominated post +function f() { + try { + var x: number = 0; + } catch (e) { + + } + var y: number = x;// error +} +// ditto +function f() { + try { + + } catch (e) { + var x: number = 0; + } + var y: number = x;// error +} +// ditto +function f(b) { + try { + var x: number; + if (b) { + throw new Error(); + } + x = 0; + } catch (e) { + + } + var y: number = x;// error +} + +" +`; + +exports[`test return.js 1`] = ` +"/** + * @flow + */ + +function foo(x: ?number): string { + try { + } catch (e) { + return 'bar'; + } + console.log(); + return 'foo'; +} + +function bar(): string { + try { + return 'foo'; + } catch (e) { + return 'bar'; + } +} + +function baz(): string { + try { + throw new Error("foo"); + } catch (e) { + return "foo"; + } + return "bar"; // unreachable +} + +function qux(): string { + try { + throw new Error("foo"); + } catch (e) { + } + console.log(); + return 'bar'; +} + +function quux(): string { + try { + return qux(); + } catch (e) { + } + return 'bar'; +} + +function bliffl(): string { + try { + throw new Error("foo"); + } catch (e) { + return "foo"; + } finally { + return "bar"; + } +} + +function corge(): string { + try { + return 'foo'; + } catch (e) { + throw new Error('bar'); + } + bar(); // unreachable +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +function foo(x: ?number): string { + try { + + } catch (e) { + return "bar"; + } + console.log(); + return "foo"; +} +function bar(): string { + try { + return "foo"; + } catch (e) { + return "bar"; + } +} +function baz(): string { + try { + throw new Error("foo"); + } catch (e) { + return "foo"; + } + return "bar";// unreachable +} +function qux(): string { + try { + throw new Error("foo"); + } catch (e) { + + } + console.log(); + return "bar"; +} +function quux(): string { + try { + return qux(); + } catch (e) { + + } + return "bar"; +} +function bliffl(): string { + try { + throw new Error("foo"); + } catch (e) { + return "foo"; + } finally { + return "bar"; + } +} +function corge(): string { + try { + return "foo"; + } catch (e) { + throw new Error("bar"); + } + bar();// unreachable +} + +" +`; + +exports[`test test.js 1`] = ` +"/*** + * test env state tracking thru try/catch/finally + * @flow + */ + +function foo() { + var x = 0; + var y; + try { + x = ""; + } catch(e) { + x = false; + throw -1; + } finally { + y = {}; + } + // here via [try; finally] only. + x(); // string ~/> function call (no num or bool error) + y(); // object ~/> function call (no uninitialized error) +} + +function bar(response) { + var payload; + try { + payload = JSON.parse(response); + } catch (e) { + throw new Error('...'); + } + // here via [try] only. + if (payload.error) { // ok + // ... + } +} + +function qux() { + var x = 5; + try { + throw -1; + } finally { + } + x(); // unreachable +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/*** + * test env state tracking thru try/catch/finally + * @flow + */ +function foo() { + var x = 0; + var y; + try { + x = ""; + } catch (e) { + x = false; + throw -1; + } finally { + y = {}; + } + // here via [try; finally] only. + x();// string ~/> function call (no num or bool error) + y();// object ~/> function call (no uninitialized error) +} +function bar(response) { + var payload; + try { + payload = JSON.parse(response); + } catch (e) { + throw new Error("..."); + } + // here via [try] only. + if (payload.error) { + + } +} +function qux() { + var x = 5; + try { + throw -1; + } finally { + + } + x();// unreachable +} + +" +`; diff --git a/tests/try/abnormals.js b/tests/try/abnormals.js new file mode 100644 index 000000000000..93f26579bfb6 --- /dev/null +++ b/tests/try/abnormals.js @@ -0,0 +1,15 @@ +/* @flow */ + +/* This test documents an issue we used to have with merging the environment of + * the try block and the catch block. The error variable, when inspected and in + * the presence of an abnormal, would sometimes kind of leak. It would hit an + * abnormal. It was weird. + */ +function foo() { + try { + } catch(error) { + if (error.foo === 4) { + throw error; + } + } +} diff --git a/tests/try/init.js b/tests/try/init.js new file mode 100644 index 000000000000..be19b23e1b52 --- /dev/null +++ b/tests/try/init.js @@ -0,0 +1,154 @@ +/*** + * test initialization tracking of hoisted stuff + * @flow + */ + +// for illustrative purposes only - Flow considers a throw possible +// anywhere within a block +function might_throw() {} + +// local use of annotated var within try is ok +function f() { + try { + var x:number = 0; + var y:number = x; + } catch (e) { + } +} + +// and within catch +function f() { + try { + } catch (e) { + var x:number = 0; + var y:number = x; + } +} + +// but not across try/catch +function f() { + try { + might_throw(); + var x:number = 0; + } catch (e) { + var y:number = x; // error + } +} + +// or try/finally +function f() { + try { + might_throw(); + var x:number = 0; + } finally { + var y:number = x; // error + } +} + +// or catch/finally +function f() { + try { + } catch (e) { + var x:number = 0; + } finally { + var y:number = x; // error + } +} + +// or try/catch/finally if init doesn't dominate +function f() { + try { + var x:number = 0; + } catch (e) { + might_throw(); + var x:number = 0; + } finally { + var y:number = x; // error + } +} + +// post-use ok because init dominates here +function f() { + try { + var x:number = 0; + } catch (e) { + might_throw(); // ...but if so, suffix is not reached + var x:number = 0; + } + var y:number = x; +} + +// and here +function f() { + try { + } catch (e) { + } finally { + might_throw(); // ...but if so, suffix is not reached + var x:number = 0; + } + var y:number = x; +} + +// and here +function f() { + try { + var x:number; + } catch (e) { + } finally { + might_throw(); // ...but if so, suffix is not reached + x = 0; + } + var y:number = x; +} + +// and here, thank you JS for the wonder that is hoisting +function f() { + try { + } catch (e) { + var x:number; + } finally { + might_throw(); // ...but if so, suffix is not reached + x = 0; + } + var y:number = x; +} + +// error if used prior to init +function f() { + var y:number = x; // error + try { + var x:number = 0; + } catch (e) { + } +} + +// another non-dominated post +function f() { + try { + var x:number = 0; + } catch (e) { + } + var y:number = x; // error +} + +// ditto +function f() { + try { + } catch (e) { + var x:number = 0; + } + var y:number = x; // error +} + +// ditto +function f(b) { + try { + var x:number; + if (b) { + throw new Error(); + } + x = 0; + } catch (e) { + } + var y:number = x; // error +} diff --git a/tests/try/jsfmt.spec.js b/tests/try/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/try/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/try/return.js b/tests/try/return.js new file mode 100644 index 000000000000..eafe017bb3e7 --- /dev/null +++ b/tests/try/return.js @@ -0,0 +1,65 @@ +/** + * @flow + */ + +function foo(x: ?number): string { + try { + } catch (e) { + return 'bar'; + } + console.log(); + return 'foo'; +} + +function bar(): string { + try { + return 'foo'; + } catch (e) { + return 'bar'; + } +} + +function baz(): string { + try { + throw new Error("foo"); + } catch (e) { + return "foo"; + } + return "bar"; // unreachable +} + +function qux(): string { + try { + throw new Error("foo"); + } catch (e) { + } + console.log(); + return 'bar'; +} + +function quux(): string { + try { + return qux(); + } catch (e) { + } + return 'bar'; +} + +function bliffl(): string { + try { + throw new Error("foo"); + } catch (e) { + return "foo"; + } finally { + return "bar"; + } +} + +function corge(): string { + try { + return 'foo'; + } catch (e) { + throw new Error('bar'); + } + bar(); // unreachable +} diff --git a/tests/try/test.js b/tests/try/test.js new file mode 100644 index 000000000000..8ed40eec4766 --- /dev/null +++ b/tests/try/test.js @@ -0,0 +1,42 @@ +/*** + * test env state tracking thru try/catch/finally + * @flow + */ + +function foo() { + var x = 0; + var y; + try { + x = ""; + } catch(e) { + x = false; + throw -1; + } finally { + y = {}; + } + // here via [try; finally] only. + x(); // string ~/> function call (no num or bool error) + y(); // object ~/> function call (no uninitialized error) +} + +function bar(response) { + var payload; + try { + payload = JSON.parse(response); + } catch (e) { + throw new Error('...'); + } + // here via [try] only. + if (payload.error) { // ok + // ... + } +} + +function qux() { + var x = 5; + try { + throw -1; + } finally { + } + x(); // unreachable +} diff --git a/tests/tuples/__snapshots__/jsfmt.spec.js.snap b/tests/tuples/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..1e62f945a534 --- /dev/null +++ b/tests/tuples/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,105 @@ +exports[`test array.js 1`] = ` +"// @flow + +function foo(x: Array): [number, ?number] { + return x; // Error, can\'t enforce arity when flowing array to tuple +} + +function foo(x: Array): [number, ?number] { + return [x[0], x[1]]; // OK. This is unsound, but at least arity is enforced +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test optional.js 1`] = ` +"// @flow + +([0, undefined]: [number, ?string]); // Ok, correct arity +([0]: [number, ?string]); // Error, arity is enforced + +([]: [?number, string]); // error, since second element is not marked optional +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test too-few.js 1`] = ` +"/* @flow */ + +function foo(a: [Object, Object]) {} + +foo([ {} ]); // error, too few elements in array passed to a tuple +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test tuples.js 1`] = ` +"var a: [] = []; +var b: [] = [123]; // Error - arity mismatch +var c: [number] = []; // nope +var d: [number, string] = [123,\'duck\']; +var e: [number, string,] = [123,\'duck\']; +var f: [number, string] = [123, 456]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/tuples/array.js b/tests/tuples/array.js new file mode 100644 index 000000000000..08f7a4c0a972 --- /dev/null +++ b/tests/tuples/array.js @@ -0,0 +1,9 @@ +// @flow + +function foo(x: Array): [number, ?number] { + return x; // Error, can't enforce arity when flowing array to tuple +} + +function foo(x: Array): [number, ?number] { + return [x[0], x[1]]; // OK. This is unsound, but at least arity is enforced +} diff --git a/tests/tuples/jsfmt.spec.js b/tests/tuples/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/tuples/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/tuples/optional.js b/tests/tuples/optional.js new file mode 100644 index 000000000000..46764c0fff06 --- /dev/null +++ b/tests/tuples/optional.js @@ -0,0 +1,6 @@ +// @flow + +([0, undefined]: [number, ?string]); // Ok, correct arity +([0]: [number, ?string]); // Error, arity is enforced + +([]: [?number, string]); // error, since second element is not marked optional diff --git a/tests/tuples/too-few.js b/tests/tuples/too-few.js new file mode 100644 index 000000000000..cb8b2d62a094 --- /dev/null +++ b/tests/tuples/too-few.js @@ -0,0 +1,5 @@ +/* @flow */ + +function foo(a: [Object, Object]) {} + +foo([ {} ]); // error, too few elements in array passed to a tuple diff --git a/tests/tuples/tuples.js b/tests/tuples/tuples.js new file mode 100644 index 000000000000..f44f9c75f7fb --- /dev/null +++ b/tests/tuples/tuples.js @@ -0,0 +1,6 @@ +var a: [] = []; +var b: [] = [123]; // Error - arity mismatch +var c: [number] = []; // nope +var d: [number, string] = [123,'duck']; +var e: [number, string,] = [123,'duck']; +var f: [number, string] = [123, 456]; diff --git a/tests/type-at-pos/__snapshots__/jsfmt.spec.js.snap b/tests/type-at-pos/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..08d61143e1bd --- /dev/null +++ b/tests/type-at-pos/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,275 @@ +exports[`test destructuring.js 1`] = ` +"// @flow + +let [x, y] = [1, 2]; + +/** + * Test what happens when the destructuring is unevaluated. In this case, + * \`this\` in a function is unbound, so we never actually find out the type of + * \`this.returnsATuple()\` is; thus, we never evaluate \`b\` and so type-at-pos + * returns EmptyT. + */ +export const X = { + returnsATuple: function(): [number, number] { + return [1, 2]; + }, + + test: function() { + let [a, b] = this.returnsATuple(); + } +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test function_expressions.js 1`] = ` +"// @flow + +// TODO: type-at-pos between the ()\'s should be () => void +// class X { +// foo(): void {} +// } + +const y = { + bar(): void {} +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +// TODO: type-at-pos between the ()\'s should be () => void +// class X { +// foo(): void {} +// } +const y = { + bar(): void { + + } +}; + +" +`; + +exports[`test generics.js 1`] = ` +"// @flow + +class C { } +var cn: C = new C; +cn; + +function foo() { return C; } +var D = foo(); +var dn: D = new C; +dn; + +type E = C; +var en: E = new C; +en; + +type F = C; +var fn: F = new C; +fn; + +type O = { x: X }; +var on: O = { x: 0 }; +on; + +type Mono = C; +var mn: Mono = new C; // error: application of non-poly type +mn; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test import.js 1`] = ` +"// @flow +var num = 42; +function bar() { } +bar(); +module.exports = num; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +var num = 42; +function bar() { + +} +bar(); +module.exports = num; + +" +`; + +exports[`test object_special_cases.js 1`] = ` +"/* @flow */ + +let tests = [ + function() { + let x = {}; + Object.defineProperty(x, \'foo\', { value: \'\' }); + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +let tests = [ + function() { + let x = {}; + Object.defineProperty(x, \"foo\", { value: \"\" }); + } +]; + +" +`; + +exports[`test optional.js 1`] = ` +"// @flow + +function foo(x?: string) { + return x; +} + +foo(); + +function bar(obj: { x?: string }) { + return obj.x; +} + +function qux(x?) { + return x; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +function foo(x: string) { + return x; +} +foo(); +function bar(obj: { x?: string }) { + return obj.x; +} +function qux(x) { + return x; +} + +" +`; + +exports[`test predicates.js 1`] = ` +"/* @flow */ + +let x = 0; +if (x == null) {} +if (x == undefined) {} +if (Array.isArray(x)) {} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +let x = 0; +if (x == null) { + +} +if (x == undefined) { + +} +if (Array.isArray(x)) { + +} + +" +`; + +exports[`test react.js 1`] = ` +"import React from \"react\"; +React.createElement; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import React from \"react\"; +React.createElement; + +" +`; + +exports[`test templates.js 1`] = ` +"/* @flow */ +\`foo bar\`; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +\`foo bar\`; + +" +`; + +exports[`test test.js 1`] = ` +"// @flow +var str = require(\'./import\'); +function foo() { } +foo(); +str + +type Point = [number, string]; +const x:Point = [1, \"foo\"]; +type MyStr = \"cool\"; +const y:MyStr = \"cool\"; +type MyBool = true; +const z:MyBool = true; +type MyNum = 42; +const w:MyNum = 42; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1237 + throw new Error(\"unprintable type: \" + JSON.stringify(n.type)); + ^ + +Error: unprintable type: \"TupleTypeAnnotation\" + at genericPrintNoParens (/src/printer.js:1237:13) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test trycatch.js 1`] = ` +"// @flow + +try { + throw \"foo\"; +} catch (e) {} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +try { + throw \"foo\"; +} catch (e) { + +} + +" +`; diff --git a/tests/type-at-pos/destructuring.js b/tests/type-at-pos/destructuring.js new file mode 100644 index 000000000000..103545e77005 --- /dev/null +++ b/tests/type-at-pos/destructuring.js @@ -0,0 +1,19 @@ +// @flow + +let [x, y] = [1, 2]; + +/** + * Test what happens when the destructuring is unevaluated. In this case, + * `this` in a function is unbound, so we never actually find out the type of + * `this.returnsATuple()` is; thus, we never evaluate `b` and so type-at-pos + * returns EmptyT. + */ +export const X = { + returnsATuple: function(): [number, number] { + return [1, 2]; + }, + + test: function() { + let [a, b] = this.returnsATuple(); + } +}; diff --git a/tests/type-at-pos/function_expressions.js b/tests/type-at-pos/function_expressions.js new file mode 100644 index 000000000000..81df45793802 --- /dev/null +++ b/tests/type-at-pos/function_expressions.js @@ -0,0 +1,10 @@ +// @flow + +// TODO: type-at-pos between the ()'s should be () => void +// class X { +// foo(): void {} +// } + +const y = { + bar(): void {} +}; diff --git a/tests/type-at-pos/generics.js b/tests/type-at-pos/generics.js new file mode 100644 index 000000000000..a08506b22101 --- /dev/null +++ b/tests/type-at-pos/generics.js @@ -0,0 +1,26 @@ +// @flow + +class C { } +var cn: C = new C; +cn; + +function foo() { return C; } +var D = foo(); +var dn: D = new C; +dn; + +type E = C; +var en: E = new C; +en; + +type F = C; +var fn: F = new C; +fn; + +type O = { x: X }; +var on: O = { x: 0 }; +on; + +type Mono = C; +var mn: Mono = new C; // error: application of non-poly type +mn; diff --git a/tests/type-at-pos/import.js b/tests/type-at-pos/import.js new file mode 100644 index 000000000000..9a49778fd59d --- /dev/null +++ b/tests/type-at-pos/import.js @@ -0,0 +1,5 @@ +// @flow +var num = 42; +function bar() { } +bar(); +module.exports = num; diff --git a/tests/type-at-pos/jsfmt.spec.js b/tests/type-at-pos/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type-at-pos/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type-at-pos/object_special_cases.js b/tests/type-at-pos/object_special_cases.js new file mode 100644 index 000000000000..d34326b96596 --- /dev/null +++ b/tests/type-at-pos/object_special_cases.js @@ -0,0 +1,8 @@ +/* @flow */ + +let tests = [ + function() { + let x = {}; + Object.defineProperty(x, 'foo', { value: '' }); + }, +]; diff --git a/tests/type-at-pos/optional.js b/tests/type-at-pos/optional.js new file mode 100644 index 000000000000..1ed4c4b71c02 --- /dev/null +++ b/tests/type-at-pos/optional.js @@ -0,0 +1,15 @@ +// @flow + +function foo(x?: string) { + return x; +} + +foo(); + +function bar(obj: { x?: string }) { + return obj.x; +} + +function qux(x?) { + return x; +} diff --git a/tests/type-at-pos/predicates.js b/tests/type-at-pos/predicates.js new file mode 100644 index 000000000000..0c68d6da5a4e --- /dev/null +++ b/tests/type-at-pos/predicates.js @@ -0,0 +1,6 @@ +/* @flow */ + +let x = 0; +if (x == null) {} +if (x == undefined) {} +if (Array.isArray(x)) {} diff --git a/tests/type-at-pos/react.js b/tests/type-at-pos/react.js new file mode 100644 index 000000000000..0921cb496171 --- /dev/null +++ b/tests/type-at-pos/react.js @@ -0,0 +1,2 @@ +import React from "react"; +React.createElement; diff --git a/tests/type-at-pos/templates.js b/tests/type-at-pos/templates.js new file mode 100644 index 000000000000..2ce2ae0fba5f --- /dev/null +++ b/tests/type-at-pos/templates.js @@ -0,0 +1,2 @@ +/* @flow */ +`foo bar`; diff --git a/tests/type-at-pos/test.js b/tests/type-at-pos/test.js new file mode 100644 index 000000000000..66d5c396be70 --- /dev/null +++ b/tests/type-at-pos/test.js @@ -0,0 +1,14 @@ +// @flow +var str = require('./import'); +function foo() { } +foo(); +str + +type Point = [number, string]; +const x:Point = [1, "foo"]; +type MyStr = "cool"; +const y:MyStr = "cool"; +type MyBool = true; +const z:MyBool = true; +type MyNum = 42; +const w:MyNum = 42; diff --git a/tests/type-at-pos/trycatch.js b/tests/type-at-pos/trycatch.js new file mode 100644 index 000000000000..35196da89c67 --- /dev/null +++ b/tests/type-at-pos/trycatch.js @@ -0,0 +1,5 @@ +// @flow + +try { + throw "foo"; +} catch (e) {} diff --git a/tests/type-destructors/__snapshots__/jsfmt.spec.js.snap b/tests/type-destructors/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..98f9765766b6 --- /dev/null +++ b/tests/type-destructors/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,86 @@ +exports[`test non_maybe_type.js 1`] = ` +"// @flow + +function foo(x: ?string): $NonMaybeType { + if (x != null) { return x; } + else return 0; // this should be an error +} + +//(foo(): string); // should not be necessary to expose the error above + +(0: $NonMaybeType); // error +(0: $NonMaybeType); // ok +(0: $NonMaybeType); // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test property_type.js 1`] = ` +"type Malformed = $PropertyType; + +type Obj = { x: string }; +type Obj_Prop_x = $PropertyType; + +(42: Obj_Prop_x); + +function foo(o: Obj): $PropertyType { + if (false) return o.x; + else return 0; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test union.js 1`] = ` +"var x0: $NonMaybeType = 0; // ok, number ~> number|string +var x1: $NonMaybeType = true; // err, boolean ~> number|string +var x2: $PropertyType<{p:number}|{p:string},\'p\'> = 0; // ok, number ~> number|string +var x3: $PropertyType<{p:number}|{p:string},\'p\'> = true; // err, boolean ~> number|string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type-destructors/jsfmt.spec.js b/tests/type-destructors/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type-destructors/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type-destructors/non_maybe_type.js b/tests/type-destructors/non_maybe_type.js new file mode 100644 index 000000000000..f3240e822337 --- /dev/null +++ b/tests/type-destructors/non_maybe_type.js @@ -0,0 +1,12 @@ +// @flow + +function foo(x: ?string): $NonMaybeType { + if (x != null) { return x; } + else return 0; // this should be an error +} + +//(foo(): string); // should not be necessary to expose the error above + +(0: $NonMaybeType); // error +(0: $NonMaybeType); // ok +(0: $NonMaybeType); // ok diff --git a/tests/type-destructors/property_type.js b/tests/type-destructors/property_type.js new file mode 100644 index 000000000000..c7bb9752eac2 --- /dev/null +++ b/tests/type-destructors/property_type.js @@ -0,0 +1,11 @@ +type Malformed = $PropertyType; + +type Obj = { x: string }; +type Obj_Prop_x = $PropertyType; + +(42: Obj_Prop_x); + +function foo(o: Obj): $PropertyType { + if (false) return o.x; + else return 0; +} diff --git a/tests/type-destructors/union.js b/tests/type-destructors/union.js new file mode 100644 index 000000000000..bc8b0abc9f40 --- /dev/null +++ b/tests/type-destructors/union.js @@ -0,0 +1,4 @@ +var x0: $NonMaybeType = 0; // ok, number ~> number|string +var x1: $NonMaybeType = true; // err, boolean ~> number|string +var x2: $PropertyType<{p:number}|{p:string},'p'> = 0; // ok, number ~> number|string +var x3: $PropertyType<{p:number}|{p:string},'p'> = true; // err, boolean ~> number|string diff --git a/tests/type-printer/__snapshots__/jsfmt.spec.js.snap b/tests/type-printer/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..001e98bea762 --- /dev/null +++ b/tests/type-printer/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,5104 @@ +exports[`test printBinaryExpression.js 1`] = ` +"\'use babel\'; +/* @flow */ + +/* + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ + +import type {BinaryExpression} from \'./types\'; + +function printBinaryExpression( + node: BinaryExpression, +) { + console.log(node); +} + +module.exports = printBinaryExpression; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +\"use babel\"; +/* @flow */ +/* + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ +import type { BinaryExpression } from \"./types\"; +function printBinaryExpression(node: BinaryExpression) { + console.log(node); +} +module.exports = printBinaryExpression; + +" +`; + +exports[`test types.js 1`] = ` +"/** + * @flow + */ + +\'use strict\'; + +/* + * Flow types for the Babylon AST. + */ + +// Abstract types. Something must extend these. + +export type Comment = { + type: \'CommentLine\'; + _CommentLine: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +} | { + type: \'CommentBlock\'; + _CommentBlock: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +}; + +export type Declaration = { + type: \'ClassBody\'; + _ClassBody: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassDeclaration\'; + _ClassDeclaration: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'FunctionDeclaration\'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'MethodDefinition\'; + _MethodDefinition: void; + computed: boolean; + key: Node; + kind: \'constructor\' | \'method\' | \'get\' | \'set\'; + static: boolean; + value: FunctionExpression; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'VariableDeclaration\'; + _VariableDeclaration: void; + declarations: Array; + kind: \'var\' | \'let\' | \'const\'; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassProperty\'; + _ClassProperty: void; + computed: boolean; + key: Node; + static: boolean; + typeAnnotation: ?TypeAnnotation; + value: ?Expression; + decorators: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Expression = { + type: \'ArrayExpression\'; + _ArrayExpression: void; + elements: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'AssignmentExpression\'; + _AssignmentExpression: void; + left: Pattern; + operator: AssignmentOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'AwaitExpression\'; + _AwaitExpression: void; + all: boolean; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BinaryExpression\'; + _BinaryExpression: void; + left: Expression; + operator: BinaryOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BindExpression\'; + _BindExpression: void; + callee: Node; + object: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'CallExpression\'; + _CallExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassExpression\'; + _ClassExpression: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ComprehensionExpression\'; + _ComprehensionExpression: void; + body: Expression; + blocks: Array; + filter: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ConditionalExpression\'; + _ConditionalExpression: void; + alternate: Expression; + consequent: Expression; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DoExpression\'; + _DoExpression: void; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'FunctionExpression\'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'Identifier\'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Literal\'; + _Literal: void; + raw: string; + regex: ?{pattern: string, flags: string}; + value: ?(string | boolean | number | RegExp); + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'LogicalExpression\'; + _LogicalExpression: void; + left: Expression; + operator: LogicalOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'MemberExpression\'; + _MemberExpression: void; + computed: boolean; + object: Expression; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NewExpression\'; + _NewExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectExpression\'; + _ObjectExpression: void; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SequenceExpression\'; + _SequenceExpression: void; + expression: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TaggedTemplateExpression\'; + _TaggedTemplateExpression: void; + quasi: TemplateLiteral; + tag: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TemplateLiteral\'; + _TemplateLiteral: void; + expressions: Array; + quasis: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ThisExpression\'; + _ThisExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'UnaryExpression\'; + _UnaryExpression: void; + argument: Expression; + operator: UnaryOperator; + prefix: true; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'UpdateExpression\'; + _UpdateExpression: void; + argument: Expression; + operator: UpdateOperator; + prefix: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'YieldExpression\'; + _YieldExpression: void; + argument: ?Expression; + delegate: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeCastExpression\'; + _TypeCastExpression: void; + expression: Expression; + typeAnnotation: TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXElement\'; + _JSXElement: void; + children: Array; + closingElement: ?JSXClosingElement; + openingElement: JSXOpeningElement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXEmptyExpression\'; + _JSXEmptyExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXExpressionContainer\'; + _JSXExpressionContainer: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXMemberExpression\'; + _JSXMemberExpression: void; + computed: boolean; + object: Node; + property: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Function = { + type: \'ArrowFunctionExpression\'; + _ArrowFunctionExpression: void; + body: Node; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'FunctionDeclaration\'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'FunctionExpression\'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +export type Node = { + type: \'ArrayExpression\'; + _ArrayExpression: void; + elements: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ArrayPattern\'; + _ArrayPattern: void; + elements: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ArrowFunctionExpression\'; + _ArrowFunctionExpression: void; + body: Node; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'AssignmentExpression\'; + _AssignmentExpression: void; + left: Pattern; + operator: AssignmentOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'AssignmentPattern\'; + _AssignmentPattern: void; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'AwaitExpression\'; + _AwaitExpression: void; + all: boolean; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BinaryExpression\'; + _BinaryExpression: void; + left: Expression; + operator: BinaryOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BindExpression\'; + _BindExpression: void; + callee: Node; + object: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BlockStatement\'; + _BlockStatement: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BreakStatement\'; + _BreakStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'CallExpression\'; + _CallExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'CatchClause\'; + _CatchClause: void; + body: BlockStatement; + param: Pattern; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassBody\'; + _ClassBody: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassDeclaration\'; + _ClassDeclaration: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassExpression\'; + _ClassExpression: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ComprehensionBlock\'; + _ComprehensionBlock: void; + each: boolean; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ComprehensionExpression\'; + _ComprehensionExpression: void; + body: Expression; + blocks: Array; + filter: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ConditionalExpression\'; + _ConditionalExpression: void; + alternate: Expression; + consequent: Expression; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ContinueStatement\'; + _ContinueStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Decorator\'; + _Decorator: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DebuggerStatement\'; + _DebuggerStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DoWhileStatement\'; + _DoWhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DoExpression\'; + _DoExpression: void; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'EmptyStatement\'; + _EmptyStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExpressionStatement\'; + _ExpressionStatement: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'File\'; + _File: void; + program: Program; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ForInStatement\'; + _ForInStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ForOfStatement\'; + _ForOfStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ForStatement\'; + _ForStatement: void; + init: ?Node; + test: ?Expression; + update: ?Expression; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'FunctionDeclaration\'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'FunctionExpression\'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: \'Identifier\'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'IfStatement\'; + _IfStatement: void; + alternate: ?Statement; + consequent: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ImportDefaultSpecifier\'; + _ImportDefaultSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ImportNamespaceSpecifier\'; + _ImportNamespaceSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ImportDeclaration\'; + _ImportDeclaration: void; + specifiers: Array; + source: Literal; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ImportSpecifier\'; + _ImportSpecifier: void; + imported: Node; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'LabeledStatement\'; + _LabeledStatement: void; + body: Statement; + label: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Literal\'; + _Literal: void; + raw: string; + regex: ?{pattern: string, flags: string}; + value: ?(string | boolean | number | RegExp); + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'LogicalExpression\'; + _LogicalExpression: void; + left: Expression; + operator: LogicalOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'MemberExpression\'; + _MemberExpression: void; + computed: boolean; + object: Expression; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'MetaProperty\'; + _MetaProperty: void; + meta: Node; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'MethodDefinition\'; + _MethodDefinition: void; + computed: boolean; + key: Node; + kind: \'constructor\' | \'method\' | \'get\' | \'set\'; + static: boolean; + value: FunctionExpression; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NewExpression\'; + _NewExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Noop\'; + _Noop: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectExpression\'; + _ObjectExpression: void; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectPattern\'; + _ObjectPattern: void; + properties: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Program\'; + _Program: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Property\'; + _Property: void; + computed: boolean; + key: Node; + kind: \'init\' | \'get\' | \'set\'; + method: boolean; + shorthand: boolean; + value: Node; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'RestElement\'; + _RestElement: void; + argument: Pattern; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ReturnStatement\'; + _ReturnStatement: void; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SequenceExpression\'; + _SequenceExpression: void; + expression: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SpreadElement\'; + _SpreadElement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SpreadProperty\'; + _SpreadProperty: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Super\'; + _Super: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SwitchCase\'; + _SwitchCase: void; + consequent: Array; + test: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SwitchStatement\'; + _SwitchStatement: void; + cases: Array; + discriminant: Expression; + lexical: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TaggedTemplateExpression\'; + _TaggedTemplateExpression: void; + quasi: TemplateLiteral; + tag: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TemplateElement\'; + _TemplateElement: void; + tail: boolean; + value: {cooked: string, raw: string}; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TemplateLiteral\'; + _TemplateLiteral: void; + expressions: Array; + quasis: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ThisExpression\'; + _ThisExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ThrowStatement\'; + _ThrowStatement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TryStatement\'; + _TryStatement: void; + block: BlockStatement; + finalizer: ?BlockStatement; + guardedHandlers: Array; + handler: ?CatchClause; + handlers: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'UnaryExpression\'; + _UnaryExpression: void; + argument: Expression; + operator: UnaryOperator; + prefix: true; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'UpdateExpression\'; + _UpdateExpression: void; + argument: Expression; + operator: UpdateOperator; + prefix: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'VariableDeclaration\'; + _VariableDeclaration: void; + declarations: Array; + kind: \'var\' | \'let\' | \'const\'; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'VariableDeclarator\'; + _VariableDeclarator: void; + id: Pattern; + init: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'WhileStatement\'; + _WhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'WithStatement\'; + _WithStatement: void; + body: Statement; + object: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'YieldExpression\'; + _YieldExpression: void; + argument: ?Expression; + delegate: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExportAllDeclaration\'; + _ExportAllDeclaration: void; + exported: Node; + source: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExportDefaultDeclaration\'; + _ExportDefaultDeclaration: void; + declaration: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExportNamedDeclaration\'; + _ExportNamedDeclaration: void; + declaration: Node; + source: Literal; + specifiers: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExportDefaultSpecifier\'; + _ExportDefaultSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExportNamespaceSpecifier\'; + _ExportNamespaceSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExportSpecifier\'; + _ExportSpecifier: void; + local: Node; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'AnyTypeAnnotation\'; + _AnyTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ArrayTypeAnnotation\'; + _ArrayTypeAnnotation: void; + elementType: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BooleanLiteralTypeAnnotation\'; + _BooleanLiteralTypeAnnotation: void; + raw: string; + value: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BooleanTypeAnnotation\'; + _BooleanTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassImplements\'; + _ClassImplements: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + superClass: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ClassProperty\'; + _ClassProperty: void; + computed: boolean; + key: Node; + static: boolean; + typeAnnotation: ?TypeAnnotation; + value: ?Expression; + decorators: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareClass\'; + _DeclareClass: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareFunction\'; + _DeclareFunction: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareModule\'; + _DeclareModule: void; + body: BlockStatement; + id: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareVariable\'; + _DeclareVariable: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'FunctionTypeAnnotation\'; + _FunctionTypeAnnotation: void; + params: Array; + rest: ?FunctionTypeParam; + returnType: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'FunctionTypeParam\'; + _FunctionTypeParam: void; + name: Identifier; + optional: boolean; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'GenericTypeAnnotation\'; + _GenericTypeAnnotation: void; + id: Node; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'InterfaceExtends\'; + _InterfaceExtends: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'InterfaceDeclaration\'; + _InterfaceDeclaration: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'IntersectionTypeAnnotation\'; + _IntersectionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'MixedTypeAnnotation\'; + _MixedTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NullableTypeAnnotation\'; + _NullableTypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NumberLiteralTypeAnnotation\'; + _NumberLiteralTypeAnnotation: void; + raw: string; + value: number; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NumberTypeAnnotation\'; + _NumberTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'StringLiteralTypeAnnotation\'; + _StringLiteralTypeAnnotation: void; + raw: string; + value: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'StringTypeAnnotation\'; + _StringTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TupleTypeAnnotation\'; + _TupleTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeofTypeAnnotation\'; + _TypeofTypeAnnotation: void; + argument: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeAlias\'; + _TypeAlias: void; + id: Identifier; + right: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeAnnotation\'; + _TypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeCastExpression\'; + _TypeCastExpression: void; + expression: Expression; + typeAnnotation: TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeParameterDeclaration\'; + _TypeParameterDeclaration: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeParameterInstantiation\'; + _TypeParameterInstantiation: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectTypeAnnotation\'; + _ObjectTypeAnnotation: void; + callProperties: Array; + indexers: Array; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectTypeCallProperty\'; + _ObjectTypeCallProperty: void; + static: boolean; + value: FunctionTypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectTypeIndexer\'; + _ObjectTypeIndexer: void; + id: Identifier; + key: Type; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectTypeProperty\'; + _ObjectTypeProperty: void; + key: Node; + optional: boolean; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'QualifiedTypeIdentifier\'; + _QualifiedTypeIdentifier: void; + id: Identifier; + qualification: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'UnionTypeAnnotation\'; + _UnionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'VoidTypeAnnotation\'; + _VoidTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXAttribute\'; + _JSXAttribute: void; + name: Node; + value: ?Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXClosingElement\'; + _JSXClosingElement: void; + name: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXElement\'; + _JSXElement: void; + children: Array; + closingElement: ?JSXClosingElement; + openingElement: JSXOpeningElement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXEmptyExpression\'; + _JSXEmptyExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXExpressionContainer\'; + _JSXExpressionContainer: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXIdentifier\'; + _JSXIdentifier: void; + name: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXMemberExpression\'; + _JSXMemberExpression: void; + computed: boolean; + object: Node; + property: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXNamespacedName\'; + _JSXNamespacedName: void; + name: JSXIdentifier; + namespace: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXOpeningElement\'; + _JSXOpeningElement: void; + attributes: Array; + name: Array; + selfClosing: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'JSXSpreadAttribute\'; + _JSXSpreadAttribute: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Pattern = { + type: \'ArrayPattern\'; + _ArrayPattern: void; + elements: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'AssignmentPattern\'; + _AssignmentPattern: void; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'Identifier\'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectPattern\'; + _ObjectPattern: void; + properties: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'RestElement\'; + _RestElement: void; + argument: Pattern; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Statement = { + type: \'BlockStatement\'; + _BlockStatement: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BreakStatement\'; + _BreakStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ContinueStatement\'; + _ContinueStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DoWhileStatement\'; + _DoWhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'EmptyStatement\'; + _EmptyStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ExpressionStatement\'; + _ExpressionStatement: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ForInStatement\'; + _ForInStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ForOfStatement\'; + _ForOfStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ForStatement\'; + _ForStatement: void; + init: ?Node; + test: ?Expression; + update: ?Expression; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'IfStatement\'; + _IfStatement: void; + alternate: ?Statement; + consequent: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'LabeledStatement\'; + _LabeledStatement: void; + body: Statement; + label: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ReturnStatement\'; + _ReturnStatement: void; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'SwitchStatement\'; + _SwitchStatement: void; + cases: Array; + discriminant: Expression; + lexical: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ThrowStatement\'; + _ThrowStatement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TryStatement\'; + _TryStatement: void; + block: BlockStatement; + finalizer: ?BlockStatement; + guardedHandlers: Array; + handler: ?CatchClause; + handlers: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'WhileStatement\'; + _WhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'WithStatement\'; + _WithStatement: void; + body: Statement; + object: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareClass\'; + _DeclareClass: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareFunction\'; + _DeclareFunction: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareModule\'; + _DeclareModule: void; + body: BlockStatement; + id: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'DeclareVariable\'; + _DeclareVariable: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'InterfaceDeclaration\'; + _InterfaceDeclaration: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TypeAlias\'; + _TypeAlias: void; + id: Identifier; + right: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Type = { + type: \'AnyTypeAnnotation\'; + _AnyTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ArrayTypeAnnotation\'; + _ArrayTypeAnnotation: void; + elementType: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BooleanLiteralTypeAnnotation\'; + _BooleanLiteralTypeAnnotation: void; + raw: string; + value: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'BooleanTypeAnnotation\'; + _BooleanTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'FunctionTypeAnnotation\'; + _FunctionTypeAnnotation: void; + params: Array; + rest: ?FunctionTypeParam; + returnType: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'GenericTypeAnnotation\'; + _GenericTypeAnnotation: void; + id: Node; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'IntersectionTypeAnnotation\'; + _IntersectionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'MixedTypeAnnotation\'; + _MixedTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NullableTypeAnnotation\'; + _NullableTypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NumberLiteralTypeAnnotation\'; + _NumberLiteralTypeAnnotation: void; + raw: string; + value: number; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'NumberTypeAnnotation\'; + _NumberTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'StringLiteralTypeAnnotation\'; + _StringLiteralTypeAnnotation: void; + raw: string; + value: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'StringTypeAnnotation\'; + _StringTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'TupleTypeAnnotation\'; + _TupleTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'ObjectTypeAnnotation\'; + _ObjectTypeAnnotation: void; + callProperties: Array; + indexers: Array; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'UnionTypeAnnotation\'; + _UnionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: \'VoidTypeAnnotation\'; + _VoidTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// Concrete Types. Nothing can extend these. + +export type CommentLine = { + type: \'CommentLine\'; + _CommentLine: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +}; + +export type CommentBlock = { + type: \'CommentBlock\'; + _CommentBlock: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +}; + +// Babel concrete types. + +export type ArrayExpression = { + type: \'ArrayExpression\'; + _ArrayExpression: void; + elements: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ArrayPattern = { + type: \'ArrayPattern\'; + _ArrayPattern: void; + elements: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ArrowFunctionExpression = { + type: \'ArrowFunctionExpression\'; + _ArrowFunctionExpression: void; + body: Node; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +type AssignmentOperator = + \'=\' | + \'+=\' | + \'-=\' | + \'*=\' | + \'/=\' | + \'%=\' | + \'<<=\' | + \'>>=\' | + \'>>>=\' | + \'|=\' | + \'^=\' | + \'&=\'; + +export type AssignmentExpression = { + type: \'AssignmentExpression\'; + _AssignmentExpression: void; + left: Pattern; + operator: AssignmentOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type AssignmentPattern = { + type: \'AssignmentPattern\'; + _AssignmentPattern: void; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type AwaitExpression = { + type: \'AwaitExpression\'; + _AwaitExpression: void; + all: boolean; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type BinaryOperator = + \'==\' | + \'!=\' | + \'===\' | + \'!==\' | + \'<\' | + \'<=\' | + \'>\' | + \'>=\' | + \'<<\' | + \'>>\' | + \'>>>\' | + \'+\' | + \'-\' | + \'*\' | + \'/\' | + \'%\' | + \'&\' | + \'|\' | + \'^\' | + \'in\' | + \'instanceof\' | + \'..\'; + +export type BinaryExpression = { + type: \'BinaryExpression\'; + _BinaryExpression: void; + left: Expression; + operator: BinaryOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: What is this? +export type BindExpression = { + type: \'BindExpression\'; + _BindExpression: void; + callee: Node; + object: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BlockStatement = { + type: \'BlockStatement\'; + _BlockStatement: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BreakStatement = { + type: \'BreakStatement\'; + _BreakStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type CallExpression = { + type: \'CallExpression\'; + _CallExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type CatchClause = { + type: \'CatchClause\'; + _CatchClause: void; + body: BlockStatement; + param: Pattern; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassBody = { + type: \'ClassBody\'; + _ClassBody: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassDeclaration = { + type: \'ClassDeclaration\'; + _ClassDeclaration: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassExpression = { + type: \'ClassExpression\'; + _ClassExpression: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ComprehensionBlock = { + type: \'ComprehensionBlock\'; + _ComprehensionBlock: void; + each: boolean; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ComprehensionExpression = { + type: \'ComprehensionExpression\'; + _ComprehensionExpression: void; + body: Expression; + blocks: Array; + filter: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ConditionalExpression = { + type: \'ConditionalExpression\'; + _ConditionalExpression: void; + alternate: Expression; + consequent: Expression; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ContinueStatement = { + type: \'ContinueStatement\'; + _ContinueStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type Decorator = { + type: \'Decorator\'; + _Decorator: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DebuggerStatement = { + type: \'DebuggerStatement\'; + _DebuggerStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DoWhileStatement = { + type: \'DoWhileStatement\'; + _DoWhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type DoExpression = { + type: \'DoExpression\'; + _DoExpression: void; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type EmptyStatement = { + type: \'EmptyStatement\'; + _EmptyStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ExpressionStatement = { + type: \'ExpressionStatement\'; + _ExpressionStatement: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type File = { + type: \'File\'; + _File: void; + program: Program; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ForInStatement = { + type: \'ForInStatement\'; + _ForInStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ForOfStatement = { + type: \'ForOfStatement\'; + _ForOfStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ForStatement = { + type: \'ForStatement\'; + _ForStatement: void; + init: ?Node; + test: ?Expression; + update: ?Expression; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type FunctionDeclaration = { + type: \'FunctionDeclaration\'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +export type FunctionExpression = { + type: \'FunctionExpression\'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +export type Identifier = { + type: \'Identifier\'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type IfStatement = { + type: \'IfStatement\'; + _IfStatement: void; + alternate: ?Statement; + consequent: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportDefaultSpecifier = { + type: \'ImportDefaultSpecifier\'; + _ImportDefaultSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportNamespaceSpecifier = { + type: \'ImportNamespaceSpecifier\'; + _ImportNamespaceSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportDeclaration = { + type: \'ImportDeclaration\'; + _ImportDeclaration: void; + specifiers: Array; + source: Literal; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportSpecifier = { + type: \'ImportSpecifier\'; + _ImportSpecifier: void; + imported: Node; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type LabeledStatement = { + type: \'LabeledStatement\'; + _LabeledStatement: void; + body: Statement; + label: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Literal = { + type: \'Literal\'; + _Literal: void; + raw: string; + regex: ?{pattern: string, flags: string}; + value: ?(string | boolean | number | RegExp); + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type LogicalOperator = \'||\' | \'&&\'; + +export type LogicalExpression = { + type: \'LogicalExpression\'; + _LogicalExpression: void; + left: Expression; + operator: LogicalOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type MemberExpression = { + type: \'MemberExpression\'; + _MemberExpression: void; + computed: boolean; + object: Expression; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type MetaProperty = { + type: \'MetaProperty\'; + _MetaProperty: void; + meta: Node; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type MethodDefinition = { + type: \'MethodDefinition\'; + _MethodDefinition: void; + computed: boolean; + key: Node; + kind: \'constructor\' | \'method\' | \'get\' | \'set\'; + static: boolean; + value: FunctionExpression; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NewExpression = { + type: \'NewExpression\'; + _NewExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Noop = { + type: \'Noop\'; + _Noop: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectExpression = { + type: \'ObjectExpression\'; + _ObjectExpression: void; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectPattern = { + type: \'ObjectPattern\'; + _ObjectPattern: void; + properties: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Program = { + type: \'Program\'; + _Program: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Property = { + type: \'Property\'; + _Property: void; + computed: boolean; + key: Node; + kind: \'init\' | \'get\' | \'set\'; + method: boolean; + shorthand: boolean; + value: Node; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type RestElement = { + type: \'RestElement\'; + _RestElement: void; + argument: Pattern; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ReturnStatement = { + type: \'ReturnStatement\'; + _ReturnStatement: void; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SequenceExpression = { + type: \'SequenceExpression\'; + _SequenceExpression: void; + expression: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SpreadElement = { + type: \'SpreadElement\'; + _SpreadElement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SpreadProperty = { + type: \'SpreadProperty\'; + _SpreadProperty: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Super = { + type: \'Super\'; + _Super: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SwitchCase = { + type: \'SwitchCase\'; + _SwitchCase: void; + consequent: Array; + test: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SwitchStatement = { + type: \'SwitchStatement\'; + _SwitchStatement: void; + cases: Array; + discriminant: Expression; + lexical: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TaggedTemplateExpression = { + type: \'TaggedTemplateExpression\'; + _TaggedTemplateExpression: void; + quasi: TemplateLiteral; + tag: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TemplateElement = { + type: \'TemplateElement\'; + _TemplateElement: void; + tail: boolean; + value: {cooked: string, raw: string}; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TemplateLiteral = { + type: \'TemplateLiteral\'; + _TemplateLiteral: void; + expressions: Array; + quasis: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ThisExpression = { + type: \'ThisExpression\'; + _ThisExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ThrowStatement = { + type: \'ThrowStatement\'; + _ThrowStatement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TryStatement = { + type: \'TryStatement\'; + _TryStatement: void; + block: BlockStatement; + finalizer: ?BlockStatement; + guardedHandlers: Array; + handler: ?CatchClause; + handlers: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type UnaryOperator = \'-\' | \'+\' | \'!\' | \'~\' | \'typeof\' | \'void\' | \'delete\'; + +export type UnaryExpression = { + type: \'UnaryExpression\'; + _UnaryExpression: void; + argument: Expression; + operator: UnaryOperator; + prefix: true; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type UpdateOperator = \'++\' | \'--\'; + +export type UpdateExpression = { + type: \'UpdateExpression\'; + _UpdateExpression: void; + argument: Expression; + operator: UpdateOperator; + prefix: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type VariableDeclaration = { + type: \'VariableDeclaration\'; + _VariableDeclaration: void; + declarations: Array; + kind: \'var\' | \'let\' | \'const\'; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type VariableDeclarator = { + type: \'VariableDeclarator\'; + _VariableDeclarator: void; + id: Pattern; + init: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type WhileStatement = { + type: \'WhileStatement\'; + _WhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type WithStatement = { + type: \'WithStatement\'; + _WithStatement: void; + body: Statement; + object: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type YieldExpression = { + type: \'YieldExpression\'; + _YieldExpression: void; + argument: ?Expression; + delegate: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportAllDeclaration = { + type: \'ExportAllDeclaration\'; + _ExportAllDeclaration: void; + exported: Node; + source: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportDefaultDeclaration = { + type: \'ExportDefaultDeclaration\'; + _ExportDefaultDeclaration: void; + declaration: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportNamedDeclaration = { + type: \'ExportNamedDeclaration\'; + _ExportNamedDeclaration: void; + declaration: Node; + source: Literal; + specifiers: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportDefaultSpecifier = { + type: \'ExportDefaultSpecifier\'; + _ExportDefaultSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportNamespaceSpecifier = { + type: \'ExportNamespaceSpecifier\'; + _ExportNamespaceSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportSpecifier = { + type: \'ExportSpecifier\'; + _ExportSpecifier: void; + local: Node; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type AnyTypeAnnotation = { + type: \'AnyTypeAnnotation\'; + _AnyTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ArrayTypeAnnotation = { + type: \'ArrayTypeAnnotation\'; + _ArrayTypeAnnotation: void; + elementType: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BooleanLiteralTypeAnnotation = { + type: \'BooleanLiteralTypeAnnotation\'; + _BooleanLiteralTypeAnnotation: void; + raw: string; + value: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BooleanTypeAnnotation = { + type: \'BooleanTypeAnnotation\'; + _BooleanTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassImplements = { + type: \'ClassImplements\'; + _ClassImplements: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + superClass: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassProperty = { + type: \'ClassProperty\'; + _ClassProperty: void; + computed: boolean; + key: Node; + static: boolean; + typeAnnotation: ?TypeAnnotation; + value: ?Expression; + decorators: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DeclareClass = { + type: \'DeclareClass\'; + _DeclareClass: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type DeclareFunction = { + type: \'DeclareFunction\'; + _DeclareFunction: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DeclareModule = { + type: \'DeclareModule\'; + _DeclareModule: void; + body: BlockStatement; + id: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type DeclareVariable = { + type: \'DeclareVariable\'; + _DeclareVariable: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type FunctionTypeAnnotation = { + type: \'FunctionTypeAnnotation\'; + _FunctionTypeAnnotation: void; + params: Array; + rest: ?FunctionTypeParam; + returnType: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type FunctionTypeParam = { + type: \'FunctionTypeParam\'; + _FunctionTypeParam: void; + name: Identifier; + optional: boolean; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type GenericTypeAnnotation = { + type: \'GenericTypeAnnotation\'; + _GenericTypeAnnotation: void; + id: Node; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type InterfaceExtends = { + type: \'InterfaceExtends\'; + _InterfaceExtends: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type InterfaceDeclaration = { + type: \'InterfaceDeclaration\'; + _InterfaceDeclaration: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type IntersectionTypeAnnotation = { + type: \'IntersectionTypeAnnotation\'; + _IntersectionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type MixedTypeAnnotation = { + type: \'MixedTypeAnnotation\'; + _MixedTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NullableTypeAnnotation = { + type: \'NullableTypeAnnotation\'; + _NullableTypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NumberLiteralTypeAnnotation = { + type: \'NumberLiteralTypeAnnotation\'; + _NumberLiteralTypeAnnotation: void; + raw: string; + value: number; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NumberTypeAnnotation = { + type: \'NumberTypeAnnotation\'; + _NumberTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type StringLiteralTypeAnnotation = { + type: \'StringLiteralTypeAnnotation\'; + _StringLiteralTypeAnnotation: void; + raw: string; + value: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type StringTypeAnnotation = { + type: \'StringTypeAnnotation\'; + _StringTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TupleTypeAnnotation = { + type: \'TupleTypeAnnotation\'; + _TupleTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeofTypeAnnotation = { + type: \'TypeofTypeAnnotation\'; + _TypeofTypeAnnotation: void; + argument: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeAlias = { + type: \'TypeAlias\'; + _TypeAlias: void; + id: Identifier; + right: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeAnnotation = { + type: \'TypeAnnotation\'; + _TypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeCastExpression = { + type: \'TypeCastExpression\'; + _TypeCastExpression: void; + expression: Expression; + typeAnnotation: TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeParameterDeclaration = { + type: \'TypeParameterDeclaration\'; + _TypeParameterDeclaration: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeParameterInstantiation = { + type: \'TypeParameterInstantiation\'; + _TypeParameterInstantiation: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeAnnotation = { + type: \'ObjectTypeAnnotation\'; + _ObjectTypeAnnotation: void; + callProperties: Array; + indexers: Array; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeCallProperty = { + type: \'ObjectTypeCallProperty\'; + _ObjectTypeCallProperty: void; + static: boolean; + value: FunctionTypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeIndexer = { + type: \'ObjectTypeIndexer\'; + _ObjectTypeIndexer: void; + id: Identifier; + key: Type; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeProperty = { + type: \'ObjectTypeProperty\'; + _ObjectTypeProperty: void; + key: Node; + optional: boolean; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type QualifiedTypeIdentifier = { + type: \'QualifiedTypeIdentifier\'; + _QualifiedTypeIdentifier: void; + id: Identifier; + qualification: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type UnionTypeAnnotation = { + type: \'UnionTypeAnnotation\'; + _UnionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type VoidTypeAnnotation = { + type: \'VoidTypeAnnotation\'; + _VoidTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXAttribute = { + type: \'JSXAttribute\'; + _JSXAttribute: void; + name: Node; + value: ?Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXClosingElement = { + type: \'JSXClosingElement\'; + _JSXClosingElement: void; + name: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXElement = { + type: \'JSXElement\'; + _JSXElement: void; + children: Array; + closingElement: ?JSXClosingElement; + openingElement: JSXOpeningElement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXEmptyExpression = { + type: \'JSXEmptyExpression\'; + _JSXEmptyExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXExpressionContainer = { + type: \'JSXExpressionContainer\'; + _JSXExpressionContainer: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXIdentifier = { + type: \'JSXIdentifier\'; + _JSXIdentifier: void; + name: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXMemberExpression = { + type: \'JSXMemberExpression\'; + _JSXMemberExpression: void; + computed: boolean; + object: Node; + property: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXNamespacedName = { + type: \'JSXNamespacedName\'; + _JSXNamespacedName: void; + name: JSXIdentifier; + namespace: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXOpeningElement = { + type: \'JSXOpeningElement\'; + _JSXOpeningElement: void; + attributes: Array; + name: Array; + selfClosing: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXSpreadAttribute = { + type: \'JSXSpreadAttribute\'; + _JSXSpreadAttribute: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type-printer/jsfmt.spec.js b/tests/type-printer/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type-printer/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type-printer/printBinaryExpression.js b/tests/type-printer/printBinaryExpression.js new file mode 100644 index 000000000000..4b3241fd1bd2 --- /dev/null +++ b/tests/type-printer/printBinaryExpression.js @@ -0,0 +1,20 @@ +'use babel'; +/* @flow */ + +/* + * Copyright (c) 2015-present, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the license found in the LICENSE file in + * the root directory of this source tree. + */ + +import type {BinaryExpression} from './types'; + +function printBinaryExpression( + node: BinaryExpression, +) { + console.log(node); +} + +module.exports = printBinaryExpression; diff --git a/tests/type-printer/types.js b/tests/type-printer/types.js new file mode 100644 index 000000000000..4f7e499e4def --- /dev/null +++ b/tests/type-printer/types.js @@ -0,0 +1,5045 @@ +/** + * @flow + */ + +'use strict'; + +/* + * Flow types for the Babylon AST. + */ + +// Abstract types. Something must extend these. + +export type Comment = { + type: 'CommentLine'; + _CommentLine: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +} | { + type: 'CommentBlock'; + _CommentBlock: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +}; + +export type Declaration = { + type: 'ClassBody'; + _ClassBody: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassDeclaration'; + _ClassDeclaration: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'FunctionDeclaration'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'MethodDefinition'; + _MethodDefinition: void; + computed: boolean; + key: Node; + kind: 'constructor' | 'method' | 'get' | 'set'; + static: boolean; + value: FunctionExpression; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'VariableDeclaration'; + _VariableDeclaration: void; + declarations: Array; + kind: 'var' | 'let' | 'const'; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassProperty'; + _ClassProperty: void; + computed: boolean; + key: Node; + static: boolean; + typeAnnotation: ?TypeAnnotation; + value: ?Expression; + decorators: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Expression = { + type: 'ArrayExpression'; + _ArrayExpression: void; + elements: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'AssignmentExpression'; + _AssignmentExpression: void; + left: Pattern; + operator: AssignmentOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'AwaitExpression'; + _AwaitExpression: void; + all: boolean; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BinaryExpression'; + _BinaryExpression: void; + left: Expression; + operator: BinaryOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BindExpression'; + _BindExpression: void; + callee: Node; + object: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'CallExpression'; + _CallExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassExpression'; + _ClassExpression: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ComprehensionExpression'; + _ComprehensionExpression: void; + body: Expression; + blocks: Array; + filter: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ConditionalExpression'; + _ConditionalExpression: void; + alternate: Expression; + consequent: Expression; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DoExpression'; + _DoExpression: void; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'FunctionExpression'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'Identifier'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Literal'; + _Literal: void; + raw: string; + regex: ?{pattern: string, flags: string}; + value: ?(string | boolean | number | RegExp); + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'LogicalExpression'; + _LogicalExpression: void; + left: Expression; + operator: LogicalOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'MemberExpression'; + _MemberExpression: void; + computed: boolean; + object: Expression; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NewExpression'; + _NewExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectExpression'; + _ObjectExpression: void; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SequenceExpression'; + _SequenceExpression: void; + expression: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TaggedTemplateExpression'; + _TaggedTemplateExpression: void; + quasi: TemplateLiteral; + tag: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TemplateLiteral'; + _TemplateLiteral: void; + expressions: Array; + quasis: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ThisExpression'; + _ThisExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'UnaryExpression'; + _UnaryExpression: void; + argument: Expression; + operator: UnaryOperator; + prefix: true; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'UpdateExpression'; + _UpdateExpression: void; + argument: Expression; + operator: UpdateOperator; + prefix: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'YieldExpression'; + _YieldExpression: void; + argument: ?Expression; + delegate: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeCastExpression'; + _TypeCastExpression: void; + expression: Expression; + typeAnnotation: TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXElement'; + _JSXElement: void; + children: Array; + closingElement: ?JSXClosingElement; + openingElement: JSXOpeningElement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXEmptyExpression'; + _JSXEmptyExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXExpressionContainer'; + _JSXExpressionContainer: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXMemberExpression'; + _JSXMemberExpression: void; + computed: boolean; + object: Node; + property: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Function = { + type: 'ArrowFunctionExpression'; + _ArrowFunctionExpression: void; + body: Node; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'FunctionDeclaration'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'FunctionExpression'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +export type Node = { + type: 'ArrayExpression'; + _ArrayExpression: void; + elements: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ArrayPattern'; + _ArrayPattern: void; + elements: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ArrowFunctionExpression'; + _ArrowFunctionExpression: void; + body: Node; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'AssignmentExpression'; + _AssignmentExpression: void; + left: Pattern; + operator: AssignmentOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'AssignmentPattern'; + _AssignmentPattern: void; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'AwaitExpression'; + _AwaitExpression: void; + all: boolean; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BinaryExpression'; + _BinaryExpression: void; + left: Expression; + operator: BinaryOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BindExpression'; + _BindExpression: void; + callee: Node; + object: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BlockStatement'; + _BlockStatement: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BreakStatement'; + _BreakStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'CallExpression'; + _CallExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'CatchClause'; + _CatchClause: void; + body: BlockStatement; + param: Pattern; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassBody'; + _ClassBody: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassDeclaration'; + _ClassDeclaration: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassExpression'; + _ClassExpression: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ComprehensionBlock'; + _ComprehensionBlock: void; + each: boolean; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ComprehensionExpression'; + _ComprehensionExpression: void; + body: Expression; + blocks: Array; + filter: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ConditionalExpression'; + _ConditionalExpression: void; + alternate: Expression; + consequent: Expression; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ContinueStatement'; + _ContinueStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Decorator'; + _Decorator: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DebuggerStatement'; + _DebuggerStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DoWhileStatement'; + _DoWhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DoExpression'; + _DoExpression: void; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'EmptyStatement'; + _EmptyStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExpressionStatement'; + _ExpressionStatement: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'File'; + _File: void; + program: Program; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ForInStatement'; + _ForInStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ForOfStatement'; + _ForOfStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ForStatement'; + _ForStatement: void; + init: ?Node; + test: ?Expression; + update: ?Expression; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'FunctionDeclaration'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'FunctionExpression'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +} | { + type: 'Identifier'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'IfStatement'; + _IfStatement: void; + alternate: ?Statement; + consequent: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ImportDefaultSpecifier'; + _ImportDefaultSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ImportNamespaceSpecifier'; + _ImportNamespaceSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ImportDeclaration'; + _ImportDeclaration: void; + specifiers: Array; + source: Literal; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ImportSpecifier'; + _ImportSpecifier: void; + imported: Node; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'LabeledStatement'; + _LabeledStatement: void; + body: Statement; + label: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Literal'; + _Literal: void; + raw: string; + regex: ?{pattern: string, flags: string}; + value: ?(string | boolean | number | RegExp); + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'LogicalExpression'; + _LogicalExpression: void; + left: Expression; + operator: LogicalOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'MemberExpression'; + _MemberExpression: void; + computed: boolean; + object: Expression; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'MetaProperty'; + _MetaProperty: void; + meta: Node; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'MethodDefinition'; + _MethodDefinition: void; + computed: boolean; + key: Node; + kind: 'constructor' | 'method' | 'get' | 'set'; + static: boolean; + value: FunctionExpression; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NewExpression'; + _NewExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Noop'; + _Noop: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectExpression'; + _ObjectExpression: void; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectPattern'; + _ObjectPattern: void; + properties: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Program'; + _Program: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Property'; + _Property: void; + computed: boolean; + key: Node; + kind: 'init' | 'get' | 'set'; + method: boolean; + shorthand: boolean; + value: Node; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'RestElement'; + _RestElement: void; + argument: Pattern; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ReturnStatement'; + _ReturnStatement: void; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SequenceExpression'; + _SequenceExpression: void; + expression: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SpreadElement'; + _SpreadElement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SpreadProperty'; + _SpreadProperty: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Super'; + _Super: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SwitchCase'; + _SwitchCase: void; + consequent: Array; + test: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SwitchStatement'; + _SwitchStatement: void; + cases: Array; + discriminant: Expression; + lexical: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TaggedTemplateExpression'; + _TaggedTemplateExpression: void; + quasi: TemplateLiteral; + tag: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TemplateElement'; + _TemplateElement: void; + tail: boolean; + value: {cooked: string, raw: string}; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TemplateLiteral'; + _TemplateLiteral: void; + expressions: Array; + quasis: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ThisExpression'; + _ThisExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ThrowStatement'; + _ThrowStatement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TryStatement'; + _TryStatement: void; + block: BlockStatement; + finalizer: ?BlockStatement; + guardedHandlers: Array; + handler: ?CatchClause; + handlers: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'UnaryExpression'; + _UnaryExpression: void; + argument: Expression; + operator: UnaryOperator; + prefix: true; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'UpdateExpression'; + _UpdateExpression: void; + argument: Expression; + operator: UpdateOperator; + prefix: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'VariableDeclaration'; + _VariableDeclaration: void; + declarations: Array; + kind: 'var' | 'let' | 'const'; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'VariableDeclarator'; + _VariableDeclarator: void; + id: Pattern; + init: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'WhileStatement'; + _WhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'WithStatement'; + _WithStatement: void; + body: Statement; + object: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'YieldExpression'; + _YieldExpression: void; + argument: ?Expression; + delegate: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExportAllDeclaration'; + _ExportAllDeclaration: void; + exported: Node; + source: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExportDefaultDeclaration'; + _ExportDefaultDeclaration: void; + declaration: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExportNamedDeclaration'; + _ExportNamedDeclaration: void; + declaration: Node; + source: Literal; + specifiers: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExportDefaultSpecifier'; + _ExportDefaultSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExportNamespaceSpecifier'; + _ExportNamespaceSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExportSpecifier'; + _ExportSpecifier: void; + local: Node; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'AnyTypeAnnotation'; + _AnyTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ArrayTypeAnnotation'; + _ArrayTypeAnnotation: void; + elementType: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BooleanLiteralTypeAnnotation'; + _BooleanLiteralTypeAnnotation: void; + raw: string; + value: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BooleanTypeAnnotation'; + _BooleanTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassImplements'; + _ClassImplements: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + superClass: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ClassProperty'; + _ClassProperty: void; + computed: boolean; + key: Node; + static: boolean; + typeAnnotation: ?TypeAnnotation; + value: ?Expression; + decorators: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareClass'; + _DeclareClass: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareFunction'; + _DeclareFunction: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareModule'; + _DeclareModule: void; + body: BlockStatement; + id: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareVariable'; + _DeclareVariable: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'FunctionTypeAnnotation'; + _FunctionTypeAnnotation: void; + params: Array; + rest: ?FunctionTypeParam; + returnType: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'FunctionTypeParam'; + _FunctionTypeParam: void; + name: Identifier; + optional: boolean; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'GenericTypeAnnotation'; + _GenericTypeAnnotation: void; + id: Node; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'InterfaceExtends'; + _InterfaceExtends: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'InterfaceDeclaration'; + _InterfaceDeclaration: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'IntersectionTypeAnnotation'; + _IntersectionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'MixedTypeAnnotation'; + _MixedTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NullableTypeAnnotation'; + _NullableTypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NumberLiteralTypeAnnotation'; + _NumberLiteralTypeAnnotation: void; + raw: string; + value: number; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NumberTypeAnnotation'; + _NumberTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'StringLiteralTypeAnnotation'; + _StringLiteralTypeAnnotation: void; + raw: string; + value: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'StringTypeAnnotation'; + _StringTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TupleTypeAnnotation'; + _TupleTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeofTypeAnnotation'; + _TypeofTypeAnnotation: void; + argument: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeAlias'; + _TypeAlias: void; + id: Identifier; + right: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeAnnotation'; + _TypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeCastExpression'; + _TypeCastExpression: void; + expression: Expression; + typeAnnotation: TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeParameterDeclaration'; + _TypeParameterDeclaration: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeParameterInstantiation'; + _TypeParameterInstantiation: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectTypeAnnotation'; + _ObjectTypeAnnotation: void; + callProperties: Array; + indexers: Array; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectTypeCallProperty'; + _ObjectTypeCallProperty: void; + static: boolean; + value: FunctionTypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectTypeIndexer'; + _ObjectTypeIndexer: void; + id: Identifier; + key: Type; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectTypeProperty'; + _ObjectTypeProperty: void; + key: Node; + optional: boolean; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'QualifiedTypeIdentifier'; + _QualifiedTypeIdentifier: void; + id: Identifier; + qualification: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'UnionTypeAnnotation'; + _UnionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'VoidTypeAnnotation'; + _VoidTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXAttribute'; + _JSXAttribute: void; + name: Node; + value: ?Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXClosingElement'; + _JSXClosingElement: void; + name: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXElement'; + _JSXElement: void; + children: Array; + closingElement: ?JSXClosingElement; + openingElement: JSXOpeningElement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXEmptyExpression'; + _JSXEmptyExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXExpressionContainer'; + _JSXExpressionContainer: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXIdentifier'; + _JSXIdentifier: void; + name: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXMemberExpression'; + _JSXMemberExpression: void; + computed: boolean; + object: Node; + property: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXNamespacedName'; + _JSXNamespacedName: void; + name: JSXIdentifier; + namespace: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXOpeningElement'; + _JSXOpeningElement: void; + attributes: Array; + name: Array; + selfClosing: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'JSXSpreadAttribute'; + _JSXSpreadAttribute: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Pattern = { + type: 'ArrayPattern'; + _ArrayPattern: void; + elements: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'AssignmentPattern'; + _AssignmentPattern: void; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'Identifier'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectPattern'; + _ObjectPattern: void; + properties: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'RestElement'; + _RestElement: void; + argument: Pattern; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Statement = { + type: 'BlockStatement'; + _BlockStatement: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BreakStatement'; + _BreakStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ContinueStatement'; + _ContinueStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DoWhileStatement'; + _DoWhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'EmptyStatement'; + _EmptyStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ExpressionStatement'; + _ExpressionStatement: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ForInStatement'; + _ForInStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ForOfStatement'; + _ForOfStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ForStatement'; + _ForStatement: void; + init: ?Node; + test: ?Expression; + update: ?Expression; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'IfStatement'; + _IfStatement: void; + alternate: ?Statement; + consequent: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'LabeledStatement'; + _LabeledStatement: void; + body: Statement; + label: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ReturnStatement'; + _ReturnStatement: void; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'SwitchStatement'; + _SwitchStatement: void; + cases: Array; + discriminant: Expression; + lexical: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ThrowStatement'; + _ThrowStatement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TryStatement'; + _TryStatement: void; + block: BlockStatement; + finalizer: ?BlockStatement; + guardedHandlers: Array; + handler: ?CatchClause; + handlers: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'WhileStatement'; + _WhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'WithStatement'; + _WithStatement: void; + body: Statement; + object: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareClass'; + _DeclareClass: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareFunction'; + _DeclareFunction: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareModule'; + _DeclareModule: void; + body: BlockStatement; + id: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'DeclareVariable'; + _DeclareVariable: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'InterfaceDeclaration'; + _InterfaceDeclaration: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TypeAlias'; + _TypeAlias: void; + id: Identifier; + right: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Type = { + type: 'AnyTypeAnnotation'; + _AnyTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ArrayTypeAnnotation'; + _ArrayTypeAnnotation: void; + elementType: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BooleanLiteralTypeAnnotation'; + _BooleanLiteralTypeAnnotation: void; + raw: string; + value: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'BooleanTypeAnnotation'; + _BooleanTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'FunctionTypeAnnotation'; + _FunctionTypeAnnotation: void; + params: Array; + rest: ?FunctionTypeParam; + returnType: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'GenericTypeAnnotation'; + _GenericTypeAnnotation: void; + id: Node; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'IntersectionTypeAnnotation'; + _IntersectionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'MixedTypeAnnotation'; + _MixedTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NullableTypeAnnotation'; + _NullableTypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NumberLiteralTypeAnnotation'; + _NumberLiteralTypeAnnotation: void; + raw: string; + value: number; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'NumberTypeAnnotation'; + _NumberTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'StringLiteralTypeAnnotation'; + _StringLiteralTypeAnnotation: void; + raw: string; + value: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'StringTypeAnnotation'; + _StringTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'TupleTypeAnnotation'; + _TupleTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'ObjectTypeAnnotation'; + _ObjectTypeAnnotation: void; + callProperties: Array; + indexers: Array; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'UnionTypeAnnotation'; + _UnionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +} | { + type: 'VoidTypeAnnotation'; + _VoidTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// Concrete Types. Nothing can extend these. + +export type CommentLine = { + type: 'CommentLine'; + _CommentLine: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +}; + +export type CommentBlock = { + type: 'CommentBlock'; + _CommentBlock: void; + value: string; + end: number; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; +}; + +// Babel concrete types. + +export type ArrayExpression = { + type: 'ArrayExpression'; + _ArrayExpression: void; + elements: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ArrayPattern = { + type: 'ArrayPattern'; + _ArrayPattern: void; + elements: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ArrowFunctionExpression = { + type: 'ArrowFunctionExpression'; + _ArrowFunctionExpression: void; + body: Node; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +type AssignmentOperator = + '=' | + '+=' | + '-=' | + '*=' | + '/=' | + '%=' | + '<<=' | + '>>=' | + '>>>=' | + '|=' | + '^=' | + '&='; + +export type AssignmentExpression = { + type: 'AssignmentExpression'; + _AssignmentExpression: void; + left: Pattern; + operator: AssignmentOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type AssignmentPattern = { + type: 'AssignmentPattern'; + _AssignmentPattern: void; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type AwaitExpression = { + type: 'AwaitExpression'; + _AwaitExpression: void; + all: boolean; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type BinaryOperator = + '==' | + '!=' | + '===' | + '!==' | + '<' | + '<=' | + '>' | + '>=' | + '<<' | + '>>' | + '>>>' | + '+' | + '-' | + '*' | + '/' | + '%' | + '&' | + '|' | + '^' | + 'in' | + 'instanceof' | + '..'; + +export type BinaryExpression = { + type: 'BinaryExpression'; + _BinaryExpression: void; + left: Expression; + operator: BinaryOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: What is this? +export type BindExpression = { + type: 'BindExpression'; + _BindExpression: void; + callee: Node; + object: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BlockStatement = { + type: 'BlockStatement'; + _BlockStatement: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BreakStatement = { + type: 'BreakStatement'; + _BreakStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type CallExpression = { + type: 'CallExpression'; + _CallExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type CatchClause = { + type: 'CatchClause'; + _CatchClause: void; + body: BlockStatement; + param: Pattern; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassBody = { + type: 'ClassBody'; + _ClassBody: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassDeclaration = { + type: 'ClassDeclaration'; + _ClassDeclaration: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassExpression = { + type: 'ClassExpression'; + _ClassExpression: void; + body: ClassBody; + id: ?Identifier; + superClass: ?Expression; + decorators: any; + superTypeParameters: any; + typeParameters: any; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ComprehensionBlock = { + type: 'ComprehensionBlock'; + _ComprehensionBlock: void; + each: boolean; + left: Pattern; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ComprehensionExpression = { + type: 'ComprehensionExpression'; + _ComprehensionExpression: void; + body: Expression; + blocks: Array; + filter: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ConditionalExpression = { + type: 'ConditionalExpression'; + _ConditionalExpression: void; + alternate: Expression; + consequent: Expression; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ContinueStatement = { + type: 'ContinueStatement'; + _ContinueStatement: void; + label: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type Decorator = { + type: 'Decorator'; + _Decorator: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DebuggerStatement = { + type: 'DebuggerStatement'; + _DebuggerStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DoWhileStatement = { + type: 'DoWhileStatement'; + _DoWhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type DoExpression = { + type: 'DoExpression'; + _DoExpression: void; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type EmptyStatement = { + type: 'EmptyStatement'; + _EmptyStatement: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ExpressionStatement = { + type: 'ExpressionStatement'; + _ExpressionStatement: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type File = { + type: 'File'; + _File: void; + program: Program; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ForInStatement = { + type: 'ForInStatement'; + _ForInStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ForOfStatement = { + type: 'ForOfStatement'; + _ForOfStatement: void; + body: Statement; + left: Node; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ForStatement = { + type: 'ForStatement'; + _ForStatement: void; + init: ?Node; + test: ?Expression; + update: ?Expression; + body: Statement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type FunctionDeclaration = { + type: 'FunctionDeclaration'; + _FunctionDeclaration: void; + body: BlockStatement; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +export type FunctionExpression = { + type: 'FunctionExpression'; + _FunctionExpression: void; + body: BlockStatement; + id: ?Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; + async: boolean; + defaults: Array; + expression: boolean; + generator: boolean; + params: Array; + rest: ?Identifier; + returnType: ?TypeAnnotation; + typeParameters: ?TypeParameterDeclaration; +}; + +export type Identifier = { + type: 'Identifier'; + _Identifier: void; + name: string; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type IfStatement = { + type: 'IfStatement'; + _IfStatement: void; + alternate: ?Statement; + consequent: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportDefaultSpecifier = { + type: 'ImportDefaultSpecifier'; + _ImportDefaultSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportNamespaceSpecifier = { + type: 'ImportNamespaceSpecifier'; + _ImportNamespaceSpecifier: void; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportDeclaration = { + type: 'ImportDeclaration'; + _ImportDeclaration: void; + specifiers: Array; + source: Literal; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ImportSpecifier = { + type: 'ImportSpecifier'; + _ImportSpecifier: void; + imported: Node; + local: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type LabeledStatement = { + type: 'LabeledStatement'; + _LabeledStatement: void; + body: Statement; + label: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Literal = { + type: 'Literal'; + _Literal: void; + raw: string; + regex: ?{pattern: string, flags: string}; + value: ?(string | boolean | number | RegExp); + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type LogicalOperator = '||' | '&&'; + +export type LogicalExpression = { + type: 'LogicalExpression'; + _LogicalExpression: void; + left: Expression; + operator: LogicalOperator; + right: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type MemberExpression = { + type: 'MemberExpression'; + _MemberExpression: void; + computed: boolean; + object: Expression; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type MetaProperty = { + type: 'MetaProperty'; + _MetaProperty: void; + meta: Node; + property: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type MethodDefinition = { + type: 'MethodDefinition'; + _MethodDefinition: void; + computed: boolean; + key: Node; + kind: 'constructor' | 'method' | 'get' | 'set'; + static: boolean; + value: FunctionExpression; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NewExpression = { + type: 'NewExpression'; + _NewExpression: void; + arguments: Array; + callee: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Noop = { + type: 'Noop'; + _Noop: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectExpression = { + type: 'ObjectExpression'; + _ObjectExpression: void; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectPattern = { + type: 'ObjectPattern'; + _ObjectPattern: void; + properties: Array; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Program = { + type: 'Program'; + _Program: void; + body: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Property = { + type: 'Property'; + _Property: void; + computed: boolean; + key: Node; + kind: 'init' | 'get' | 'set'; + method: boolean; + shorthand: boolean; + value: Node; + decorators: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type RestElement = { + type: 'RestElement'; + _RestElement: void; + argument: Pattern; + typeAnnotation: ?TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ReturnStatement = { + type: 'ReturnStatement'; + _ReturnStatement: void; + argument: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SequenceExpression = { + type: 'SequenceExpression'; + _SequenceExpression: void; + expression: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SpreadElement = { + type: 'SpreadElement'; + _SpreadElement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SpreadProperty = { + type: 'SpreadProperty'; + _SpreadProperty: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type Super = { + type: 'Super'; + _Super: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SwitchCase = { + type: 'SwitchCase'; + _SwitchCase: void; + consequent: Array; + test: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type SwitchStatement = { + type: 'SwitchStatement'; + _SwitchStatement: void; + cases: Array; + discriminant: Expression; + lexical: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TaggedTemplateExpression = { + type: 'TaggedTemplateExpression'; + _TaggedTemplateExpression: void; + quasi: TemplateLiteral; + tag: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TemplateElement = { + type: 'TemplateElement'; + _TemplateElement: void; + tail: boolean; + value: {cooked: string, raw: string}; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TemplateLiteral = { + type: 'TemplateLiteral'; + _TemplateLiteral: void; + expressions: Array; + quasis: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ThisExpression = { + type: 'ThisExpression'; + _ThisExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ThrowStatement = { + type: 'ThrowStatement'; + _ThrowStatement: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TryStatement = { + type: 'TryStatement'; + _TryStatement: void; + block: BlockStatement; + finalizer: ?BlockStatement; + guardedHandlers: Array; + handler: ?CatchClause; + handlers: ?Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type UnaryOperator = '-' | '+' | '!' | '~' | 'typeof' | 'void' | 'delete'; + +export type UnaryExpression = { + type: 'UnaryExpression'; + _UnaryExpression: void; + argument: Expression; + operator: UnaryOperator; + prefix: true; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +type UpdateOperator = '++' | '--'; + +export type UpdateExpression = { + type: 'UpdateExpression'; + _UpdateExpression: void; + argument: Expression; + operator: UpdateOperator; + prefix: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type VariableDeclaration = { + type: 'VariableDeclaration'; + _VariableDeclaration: void; + declarations: Array; + kind: 'var' | 'let' | 'const'; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type VariableDeclarator = { + type: 'VariableDeclarator'; + _VariableDeclarator: void; + id: Pattern; + init: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type WhileStatement = { + type: 'WhileStatement'; + _WhileStatement: void; + body: Statement; + test: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type WithStatement = { + type: 'WithStatement'; + _WithStatement: void; + body: Statement; + object: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type YieldExpression = { + type: 'YieldExpression'; + _YieldExpression: void; + argument: ?Expression; + delegate: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportAllDeclaration = { + type: 'ExportAllDeclaration'; + _ExportAllDeclaration: void; + exported: Node; + source: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportDefaultDeclaration = { + type: 'ExportDefaultDeclaration'; + _ExportDefaultDeclaration: void; + declaration: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportNamedDeclaration = { + type: 'ExportNamedDeclaration'; + _ExportNamedDeclaration: void; + declaration: Node; + source: Literal; + specifiers: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportDefaultSpecifier = { + type: 'ExportDefaultSpecifier'; + _ExportDefaultSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportNamespaceSpecifier = { + type: 'ExportNamespaceSpecifier'; + _ExportNamespaceSpecifier: void; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type ExportSpecifier = { + type: 'ExportSpecifier'; + _ExportSpecifier: void; + local: Node; + exported: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type AnyTypeAnnotation = { + type: 'AnyTypeAnnotation'; + _AnyTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ArrayTypeAnnotation = { + type: 'ArrayTypeAnnotation'; + _ArrayTypeAnnotation: void; + elementType: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BooleanLiteralTypeAnnotation = { + type: 'BooleanLiteralTypeAnnotation'; + _BooleanLiteralTypeAnnotation: void; + raw: string; + value: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type BooleanTypeAnnotation = { + type: 'BooleanTypeAnnotation'; + _BooleanTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassImplements = { + type: 'ClassImplements'; + _ClassImplements: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + superClass: ?Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ClassProperty = { + type: 'ClassProperty'; + _ClassProperty: void; + computed: boolean; + key: Node; + static: boolean; + typeAnnotation: ?TypeAnnotation; + value: ?Expression; + decorators: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DeclareClass = { + type: 'DeclareClass'; + _DeclareClass: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type DeclareFunction = { + type: 'DeclareFunction'; + _DeclareFunction: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type DeclareModule = { + type: 'DeclareModule'; + _DeclareModule: void; + body: BlockStatement; + id: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +// TODO: Make this correct. +export type DeclareVariable = { + type: 'DeclareVariable'; + _DeclareVariable: void; + id: Identifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type FunctionTypeAnnotation = { + type: 'FunctionTypeAnnotation'; + _FunctionTypeAnnotation: void; + params: Array; + rest: ?FunctionTypeParam; + returnType: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type FunctionTypeParam = { + type: 'FunctionTypeParam'; + _FunctionTypeParam: void; + name: Identifier; + optional: boolean; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type GenericTypeAnnotation = { + type: 'GenericTypeAnnotation'; + _GenericTypeAnnotation: void; + id: Node; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type InterfaceExtends = { + type: 'InterfaceExtends'; + _InterfaceExtends: void; + id: Identifier; + typeParameters: ?TypeParameterInstantiation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type InterfaceDeclaration = { + type: 'InterfaceDeclaration'; + _InterfaceDeclaration: void; + body: ObjectTypeAnnotation; + extends: Array; + id: Identifier; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type IntersectionTypeAnnotation = { + type: 'IntersectionTypeAnnotation'; + _IntersectionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type MixedTypeAnnotation = { + type: 'MixedTypeAnnotation'; + _MixedTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NullableTypeAnnotation = { + type: 'NullableTypeAnnotation'; + _NullableTypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NumberLiteralTypeAnnotation = { + type: 'NumberLiteralTypeAnnotation'; + _NumberLiteralTypeAnnotation: void; + raw: string; + value: number; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type NumberTypeAnnotation = { + type: 'NumberTypeAnnotation'; + _NumberTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type StringLiteralTypeAnnotation = { + type: 'StringLiteralTypeAnnotation'; + _StringLiteralTypeAnnotation: void; + raw: string; + value: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type StringTypeAnnotation = { + type: 'StringTypeAnnotation'; + _StringTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TupleTypeAnnotation = { + type: 'TupleTypeAnnotation'; + _TupleTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeofTypeAnnotation = { + type: 'TypeofTypeAnnotation'; + _TypeofTypeAnnotation: void; + argument: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeAlias = { + type: 'TypeAlias'; + _TypeAlias: void; + id: Identifier; + right: Type; + typeParameters: ?TypeParameterDeclaration; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeAnnotation = { + type: 'TypeAnnotation'; + _TypeAnnotation: void; + typeAnnotation: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeCastExpression = { + type: 'TypeCastExpression'; + _TypeCastExpression: void; + expression: Expression; + typeAnnotation: TypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeParameterDeclaration = { + type: 'TypeParameterDeclaration'; + _TypeParameterDeclaration: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type TypeParameterInstantiation = { + type: 'TypeParameterInstantiation'; + _TypeParameterInstantiation: void; + params: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeAnnotation = { + type: 'ObjectTypeAnnotation'; + _ObjectTypeAnnotation: void; + callProperties: Array; + indexers: Array; + properties: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeCallProperty = { + type: 'ObjectTypeCallProperty'; + _ObjectTypeCallProperty: void; + static: boolean; + value: FunctionTypeAnnotation; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeIndexer = { + type: 'ObjectTypeIndexer'; + _ObjectTypeIndexer: void; + id: Identifier; + key: Type; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type ObjectTypeProperty = { + type: 'ObjectTypeProperty'; + _ObjectTypeProperty: void; + key: Node; + optional: boolean; + value: Type; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type QualifiedTypeIdentifier = { + type: 'QualifiedTypeIdentifier'; + _QualifiedTypeIdentifier: void; + id: Identifier; + qualification: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type UnionTypeAnnotation = { + type: 'UnionTypeAnnotation'; + _UnionTypeAnnotation: void; + types: Array; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type VoidTypeAnnotation = { + type: 'VoidTypeAnnotation'; + _VoidTypeAnnotation: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXAttribute = { + type: 'JSXAttribute'; + _JSXAttribute: void; + name: Node; + value: ?Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXClosingElement = { + type: 'JSXClosingElement'; + _JSXClosingElement: void; + name: Node; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXElement = { + type: 'JSXElement'; + _JSXElement: void; + children: Array; + closingElement: ?JSXClosingElement; + openingElement: JSXOpeningElement; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXEmptyExpression = { + type: 'JSXEmptyExpression'; + _JSXEmptyExpression: void; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXExpressionContainer = { + type: 'JSXExpressionContainer'; + _JSXExpressionContainer: void; + expression: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXIdentifier = { + type: 'JSXIdentifier'; + _JSXIdentifier: void; + name: string; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXMemberExpression = { + type: 'JSXMemberExpression'; + _JSXMemberExpression: void; + computed: boolean; + object: Node; + property: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXNamespacedName = { + type: 'JSXNamespacedName'; + _JSXNamespacedName: void; + name: JSXIdentifier; + namespace: JSXIdentifier; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXOpeningElement = { + type: 'JSXOpeningElement'; + _JSXOpeningElement: void; + attributes: Array; + name: Array; + selfClosing: boolean; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; + +export type JSXSpreadAttribute = { + type: 'JSXSpreadAttribute'; + _JSXSpreadAttribute: void; + argument: Expression; + end: number; + innerComments: ?Array; + leadingComments: ?Array; + loc: { + end: {column: number, line: number}, + start: {column: number, line: number}, + }; + start: number; + trailingComments: ?Array; +}; diff --git a/tests/type_args_nonstrict/__snapshots__/jsfmt.spec.js.snap b/tests/type_args_nonstrict/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a7603c13b402 --- /dev/null +++ b/tests/type_args_nonstrict/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,91 @@ +exports[`test test.js 1`] = ` +"/** + * Test nonstrict type param arity checking, + * as enabled by + * + * [options] + * experimental.strict_type_args=false + * + * in .flowconfig. + * + * @flow + */ + +// no arity error in type annotation using polymorphic class + +class MyClass { + x: T; + constructor(x: T) { + this.x = x; + } +} + +var c: MyClass = new MyClass(0); // no error + +// no arity error in type annotation using polymorphic class with defaulting + +class MyClass2 { + x: T; + y: U; + constructor(x: T, y: U) { + this.x = x; + this.y = y; + } +} + +var c2: MyClass2 = new MyClass2(0, \"\"); // no error + +// no arity error in type annotation using polymorphic type alias + +type MyObject = { + x: T; +} + +var o: MyObject = { x: 0 }; // no error + +// arity error in type alias rhs + +type MySubobject = { y: number } & MyObject; // no error + +// arity error in interface extends + +interface MyInterface { + x: T; +} + +interface MySubinterface extends MyInterface { // no error + y: number; +} + +// no arity error in extends of polymorphic class + +class MySubclass extends MyClass { // ok, type arg inferred + y: number; + constructor(y: number) { + super(y); + } +} + +// no arity error in call of polymorphic function + +function singleton(x: T):Array { return [x]; } + +var num_array:Array = singleton(0); // ok, type arg inferred +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_args_nonstrict/jsfmt.spec.js b/tests/type_args_nonstrict/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_args_nonstrict/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_args_nonstrict/test.js b/tests/type_args_nonstrict/test.js new file mode 100644 index 000000000000..79ad1329f72b --- /dev/null +++ b/tests/type_args_nonstrict/test.js @@ -0,0 +1,72 @@ +/** + * Test nonstrict type param arity checking, + * as enabled by + * + * [options] + * experimental.strict_type_args=false + * + * in .flowconfig. + * + * @flow + */ + +// no arity error in type annotation using polymorphic class + +class MyClass { + x: T; + constructor(x: T) { + this.x = x; + } +} + +var c: MyClass = new MyClass(0); // no error + +// no arity error in type annotation using polymorphic class with defaulting + +class MyClass2 { + x: T; + y: U; + constructor(x: T, y: U) { + this.x = x; + this.y = y; + } +} + +var c2: MyClass2 = new MyClass2(0, ""); // no error + +// no arity error in type annotation using polymorphic type alias + +type MyObject = { + x: T; +} + +var o: MyObject = { x: 0 }; // no error + +// arity error in type alias rhs + +type MySubobject = { y: number } & MyObject; // no error + +// arity error in interface extends + +interface MyInterface { + x: T; +} + +interface MySubinterface extends MyInterface { // no error + y: number; +} + +// no arity error in extends of polymorphic class + +class MySubclass extends MyClass { // ok, type arg inferred + y: number; + constructor(y: number) { + super(y); + } +} + +// no arity error in call of polymorphic function + +function singleton(x: T):Array { return [x]; } + +var num_array:Array = singleton(0); // ok, type arg inferred diff --git a/tests/type_args_strict/__snapshots__/jsfmt.spec.js.snap b/tests/type_args_strict/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..07374c543490 --- /dev/null +++ b/tests/type_args_strict/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,90 @@ +exports[`test test.js 1`] = ` +"/** + * Test strict type param arity checking. + * + * Full type argument lists are required in type expressions, + * such as type annotations and interface extends clauses. + * Type arguments are optional in value expressions, such as + * class extends clauses and calls of polymorphic functions. + * + * @flow + */ + +// arity error in type annotation using polymorphic class + +class MyClass { + x: T; + constructor(x: T) { + this.x = x; + } +} + +var c: MyClass = new MyClass(0); // error, missing argument list (1) + +// arity error in type annotation using polymorphic class with defaulting + +class MyClass2 { + x: T; + y: U; + constructor(x: T, y: U) { + this.x = x; + this.y = y; + } +} + +var c2: MyClass2 = new MyClass2(0, \"\"); // error, missing argument list (1-2) + +// arity error in type annotation using polymorphic type alias + +type MyObject = { + x: T; +} + +var o: MyObject = { x: 0 }; // error, missing argument list + +// arity error in type alias rhs + +type MySubobject = { y: number } & MyObject; // error, missing argument list + +// arity error in interface extends + +interface MyInterface { + x: T; +} + +interface MySubinterface extends MyInterface { // error, missing argument list + y: number; +} + +// *no* arity error in extends of polymorphic class + +class MySubclass extends MyClass { // ok, type arg inferred + y: number; + constructor(y: number) { + super(y); + } +} + +// *no* arity error in call of polymorphic function + +function singleton(x: T):Array { return [x]; } + +var num_array:Array = singleton(0); // ok, type arg inferred +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_args_strict/jsfmt.spec.js b/tests/type_args_strict/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_args_strict/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_args_strict/test.js b/tests/type_args_strict/test.js new file mode 100644 index 000000000000..785285f5e63c --- /dev/null +++ b/tests/type_args_strict/test.js @@ -0,0 +1,71 @@ +/** + * Test strict type param arity checking. + * + * Full type argument lists are required in type expressions, + * such as type annotations and interface extends clauses. + * Type arguments are optional in value expressions, such as + * class extends clauses and calls of polymorphic functions. + * + * @flow + */ + +// arity error in type annotation using polymorphic class + +class MyClass { + x: T; + constructor(x: T) { + this.x = x; + } +} + +var c: MyClass = new MyClass(0); // error, missing argument list (1) + +// arity error in type annotation using polymorphic class with defaulting + +class MyClass2 { + x: T; + y: U; + constructor(x: T, y: U) { + this.x = x; + this.y = y; + } +} + +var c2: MyClass2 = new MyClass2(0, ""); // error, missing argument list (1-2) + +// arity error in type annotation using polymorphic type alias + +type MyObject = { + x: T; +} + +var o: MyObject = { x: 0 }; // error, missing argument list + +// arity error in type alias rhs + +type MySubobject = { y: number } & MyObject; // error, missing argument list + +// arity error in interface extends + +interface MyInterface { + x: T; +} + +interface MySubinterface extends MyInterface { // error, missing argument list + y: number; +} + +// *no* arity error in extends of polymorphic class + +class MySubclass extends MyClass { // ok, type arg inferred + y: number; + constructor(y: number) { + super(y); + } +} + +// *no* arity error in call of polymorphic function + +function singleton(x: T):Array { return [x]; } + +var num_array:Array = singleton(0); // ok, type arg inferred diff --git a/tests/type_only_vars/A.js b/tests/type_only_vars/A.js new file mode 100644 index 000000000000..9473797985ff --- /dev/null +++ b/tests/type_only_vars/A.js @@ -0,0 +1,14 @@ +/** + * @flow + */ + +class Foo { +} + +class Bar { +} + +module.exports = { + Foo: Foo, + Bar: Bar +}; diff --git a/tests/type_only_vars/__snapshots__/jsfmt.spec.js.snap b/tests/type_only_vars/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..7ddfb0e9f771 --- /dev/null +++ b/tests/type_only_vars/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,174 @@ +exports[`test A.js 1`] = ` +"/** + * @flow + */ + +class Foo { +} + +class Bar { +} + +module.exports = { + Foo: Foo, + Bar: Bar +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +class Foo {} +class Bar {} +module.exports = { Foo: Foo, Bar: Bar }; + +" +`; + +exports[`test bad_shadowing.js 1`] = ` +"/** + * @flow + */ + +import typeof A from \"./A.js\"; +import type {Foo, Bar as Baz} from \"./A.js\"; + +type duck = { + quack: () => string; +} + +// These string types should confict with the imported types +var A: string = \"Hello\"; +var Foo: string = \"Goodbye\"; +var Baz: string = \"Go away please\"; + +// This string type should conflict with the typedef +var duck: string = \"quack\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test good_shadowing.js 1`] = ` +"/** + * @flow + */ + +import typeof A from \"./A.js\"; +import type {Foo, Bar as Baz} from \"./A.js\"; + +var A = require(\'./A.js\'); +var Foo = A.Foo; +var Baz = A.Bar; + +// errors in prev block leave type bindings in place, so these are errors +var m = A; +var n = Foo; +var o = Baz; + +// errors from value positions only +var a: Foo = new Foo(); +var b: Foo = new A.Foo(); +(new A.Bar(): Baz); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +import typeof A from \"./A.js\"; +import type { Foo, Bar as Baz } from \"./A.js\"; +var A = require(\"./A.js\"); +var Foo = A.Foo; +var Baz = A.Bar; +// errors in prev block leave type bindings in place, so these are errors +var m = A; +var n = Foo; +var o = Baz; +// errors from value positions only +var a: Foo = new Foo(); +var b: Foo = new A.Foo(); +(new A.Bar(): Baz); + +" +`; + +exports[`test import_type.js 1`] = ` +"/** + * @flow + */ + +import typeof A from \"./A.js\"; +import type {Foo, Bar as Baz} from \"./A.js\"; + +var actualA = require(\'./A.js\'); + +// You can\'t use it as an identifier +var m = A; +var n = Foo; +var o = Baz; + +// But using it in a type should still work +var a: Foo = new actualA.Foo(); +(new actualA.Bar(): Baz); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +import typeof A from \"./A.js\"; +import type { Foo, Bar as Baz } from \"./A.js\"; +var actualA = require(\"./A.js\"); +// You can\'t use it as an identifier +var m = A; +var n = Foo; +var o = Baz; +// But using it in a type should still work +var a: Foo = new actualA.Foo(); +(new actualA.Bar(): Baz); + +" +`; + +exports[`test type_alias.js 1`] = ` +"/** + * @flow + */ + +type Foo = number; + +// You can\'t use it as an identifier +var x = Foo; + +// But using it in a type should still work +var a: Foo = 123; +var b: Array = [123]; +type c = Foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_only_vars/bad_shadowing.js b/tests/type_only_vars/bad_shadowing.js new file mode 100644 index 000000000000..44fda51444e7 --- /dev/null +++ b/tests/type_only_vars/bad_shadowing.js @@ -0,0 +1,18 @@ +/** + * @flow + */ + +import typeof A from "./A.js"; +import type {Foo, Bar as Baz} from "./A.js"; + +type duck = { + quack: () => string; +} + +// These string types should confict with the imported types +var A: string = "Hello"; +var Foo: string = "Goodbye"; +var Baz: string = "Go away please"; + +// This string type should conflict with the typedef +var duck: string = "quack"; diff --git a/tests/type_only_vars/good_shadowing.js b/tests/type_only_vars/good_shadowing.js new file mode 100644 index 000000000000..010dbabfebbb --- /dev/null +++ b/tests/type_only_vars/good_shadowing.js @@ -0,0 +1,20 @@ +/** + * @flow + */ + +import typeof A from "./A.js"; +import type {Foo, Bar as Baz} from "./A.js"; + +var A = require('./A.js'); +var Foo = A.Foo; +var Baz = A.Bar; + +// errors in prev block leave type bindings in place, so these are errors +var m = A; +var n = Foo; +var o = Baz; + +// errors from value positions only +var a: Foo = new Foo(); +var b: Foo = new A.Foo(); +(new A.Bar(): Baz); diff --git a/tests/type_only_vars/import_type.js b/tests/type_only_vars/import_type.js new file mode 100644 index 000000000000..b8250c2eff86 --- /dev/null +++ b/tests/type_only_vars/import_type.js @@ -0,0 +1,17 @@ +/** + * @flow + */ + +import typeof A from "./A.js"; +import type {Foo, Bar as Baz} from "./A.js"; + +var actualA = require('./A.js'); + +// You can't use it as an identifier +var m = A; +var n = Foo; +var o = Baz; + +// But using it in a type should still work +var a: Foo = new actualA.Foo(); +(new actualA.Bar(): Baz); diff --git a/tests/type_only_vars/jsfmt.spec.js b/tests/type_only_vars/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_only_vars/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_only_vars/type_alias.js b/tests/type_only_vars/type_alias.js new file mode 100644 index 000000000000..1633b664d2a7 --- /dev/null +++ b/tests/type_only_vars/type_alias.js @@ -0,0 +1,13 @@ +/** + * @flow + */ + +type Foo = number; + +// You can't use it as an identifier +var x = Foo; + +// But using it in a type should still work +var a: Foo = 123; +var b: Array = [123]; +type c = Foo; diff --git a/tests/type_param_defaults/__snapshots__/jsfmt.spec.js.snap b/tests/type_param_defaults/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3e30daf61552 --- /dev/null +++ b/tests/type_param_defaults/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,84 @@ +exports[`test classes.js 1`] = ` +"/* @flow */ + +class A { + p: T; + constructor(p: T) { + this.p = p; + } +} + +// Test out simple defaults +class B extends A {} + +var b_number: B = new B(123); +var b_void: B = new B(); +var b_default: B<> = new B(\'hello\'); + +var b_star: B<*> = new B(123); + +(b_number.p: boolean); // Error number ~> boolean +(b_void.p: boolean); // Error void ~> boolean +(b_default.p: boolean); // Error string ~> boolean + +(b_star.p: boolean); // Error number ~> boolean + +class C extends A {} + +var c_number: C = new C(123); // Error number ~> ?string +var c_void: C = new C(); +var c_default: C<> = new C(\'hello\'); +var c_star: C<*> = new C(\'hello\'); + +(c_void.p: boolean); // Error void ~> boolean +(c_default.p: boolean); // Error string ~> boolean +(c_star.p: boolean); // Error string ~> boolean + +class D extends A {} +var d_number: D = new D(123); +var d_void: D = new D(); +var d_default: D = new D(\'hello\'); +var d_too_few_args: D<> = new D(\'hello\'); // Error too few tparams +var d_too_many: D = new D(\'hello\'); // Error too many tparams +var d_star: D<*> = new D(10); // error, number ~> string + +(d_number.p: boolean); // Error number ~> boolean +(d_void.p: boolean); // Error void ~> boolean +(d_default.p: boolean); // Error string ~> boolean +(d_star.p: boolean); // Error number ~> boolean + +class E {} // Error: string ~> number +class F {} // Error: number ~> string + +class G extends A {} + +var g_default: G = new G(\'hello\'); + +(g_default.p: boolean); // Error string ~> boolean + +class H {} // Error - can\'t refer to T before it\'s defined + +class I extends A {} + +var i_number: I = new I(123); // Error number ~> ?string +var i_void: I = new I(); +var i_default: I<> = new I(\'hello\'); +var i_star: I<*> = new I(\'hello\'); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_param_defaults/classes.js b/tests/type_param_defaults/classes.js new file mode 100644 index 000000000000..3c6797bc00c9 --- /dev/null +++ b/tests/type_param_defaults/classes.js @@ -0,0 +1,65 @@ +/* @flow */ + +class A { + p: T; + constructor(p: T) { + this.p = p; + } +} + +// Test out simple defaults +class B extends A {} + +var b_number: B = new B(123); +var b_void: B = new B(); +var b_default: B<> = new B('hello'); + +var b_star: B<*> = new B(123); + +(b_number.p: boolean); // Error number ~> boolean +(b_void.p: boolean); // Error void ~> boolean +(b_default.p: boolean); // Error string ~> boolean + +(b_star.p: boolean); // Error number ~> boolean + +class C extends A {} + +var c_number: C = new C(123); // Error number ~> ?string +var c_void: C = new C(); +var c_default: C<> = new C('hello'); +var c_star: C<*> = new C('hello'); + +(c_void.p: boolean); // Error void ~> boolean +(c_default.p: boolean); // Error string ~> boolean +(c_star.p: boolean); // Error string ~> boolean + +class D extends A {} +var d_number: D = new D(123); +var d_void: D = new D(); +var d_default: D = new D('hello'); +var d_too_few_args: D<> = new D('hello'); // Error too few tparams +var d_too_many: D = new D('hello'); // Error too many tparams +var d_star: D<*> = new D(10); // error, number ~> string + +(d_number.p: boolean); // Error number ~> boolean +(d_void.p: boolean); // Error void ~> boolean +(d_default.p: boolean); // Error string ~> boolean +(d_star.p: boolean); // Error number ~> boolean + +class E {} // Error: string ~> number +class F {} // Error: number ~> string + +class G extends A {} + +var g_default: G = new G('hello'); + +(g_default.p: boolean); // Error string ~> boolean + +class H {} // Error - can't refer to T before it's defined + +class I extends A {} + +var i_number: I = new I(123); // Error number ~> ?string +var i_void: I = new I(); +var i_default: I<> = new I('hello'); +var i_star: I<*> = new I('hello'); diff --git a/tests/type_param_defaults/jsfmt.spec.js b/tests/type_param_defaults/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_param_defaults/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_param_scope/__snapshots__/jsfmt.spec.js.snap b/tests/type_param_scope/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..355cffb598e1 --- /dev/null +++ b/tests/type_param_scope/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,132 @@ +exports[`test class.js 1`] = ` +"class C { + a(x:T, a:A) { + this.b(x); // ok + this.b(a); // error: A ~> incompatible instance of T + } + + b(x:T) {} +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test default_params.js 1`] = ` +"function f(a:T) { + function g(b:U, c:T = a) { + function h(d:U = b) {} + h(); // ok + h(b); // ok + h(c); // err, T ~> U + } + g(0); // ok + g(0,a); // ok + g(0,0); // error: number ~> T +} +f(0); // ok +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test method_shadow.js 1`] = ` +"// Ensure method type params properly shadow outer type params. Subclass ensures +// the generated insttype has the correct tvars. Should behave the same for +// classes, interfaces, and declared classes. + +class A { + x:T; + constructor(x:T) { this.x = x } + m(x:T):A { return new A(x) } +} + +class B extends A { + m(x:T):B { return new B(x) } +} + +interface C { + m(x:T):C; +} + +interface D extends C { + m(x:T):D; +} + +declare class E { + m(x:T):E; +} + +declare class F extends E { + m(x:T):F; +} + + +// Bounds can refer to parent type params (until they are shadowed). + +class G { + x:T; + constructor(x:T) { this.x = x } + m(x:T):G { return new G(x) } // T-as-bound is G\'s T +} + +declare var g: G; +g.m(0); // ok +g.m(true); // err, bool ~> number|string +(g.m(\"\"): G); // err, string ~> number + + +// Shadow bounds incompatible with parent + +class H { + x:T; + m(x:T) { + this.x = x; // err, m\'s T != H\'s T + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_param_scope/class.js b/tests/type_param_scope/class.js new file mode 100644 index 000000000000..ef25adc20642 --- /dev/null +++ b/tests/type_param_scope/class.js @@ -0,0 +1,8 @@ +class C { + a(x:T, a:A) { + this.b(x); // ok + this.b(a); // error: A ~> incompatible instance of T + } + + b(x:T) {} +} diff --git a/tests/type_param_scope/default_params.js b/tests/type_param_scope/default_params.js new file mode 100644 index 000000000000..1c48b67b206c --- /dev/null +++ b/tests/type_param_scope/default_params.js @@ -0,0 +1,12 @@ +function f(a:T) { + function g(b:U, c:T = a) { + function h(d:U = b) {} + h(); // ok + h(b); // ok + h(c); // err, T ~> U + } + g(0); // ok + g(0,a); // ok + g(0,0); // error: number ~> T +} +f(0); // ok diff --git a/tests/type_param_scope/jsfmt.spec.js b/tests/type_param_scope/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_param_scope/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_param_scope/method_shadow.js b/tests/type_param_scope/method_shadow.js new file mode 100644 index 000000000000..93b1223c6f37 --- /dev/null +++ b/tests/type_param_scope/method_shadow.js @@ -0,0 +1,53 @@ +// Ensure method type params properly shadow outer type params. Subclass ensures +// the generated insttype has the correct tvars. Should behave the same for +// classes, interfaces, and declared classes. + +class A { + x:T; + constructor(x:T) { this.x = x } + m(x:T):A { return new A(x) } +} + +class B extends A { + m(x:T):B { return new B(x) } +} + +interface C { + m(x:T):C; +} + +interface D extends C { + m(x:T):D; +} + +declare class E { + m(x:T):E; +} + +declare class F extends E { + m(x:T):F; +} + + +// Bounds can refer to parent type params (until they are shadowed). + +class G { + x:T; + constructor(x:T) { this.x = x } + m(x:T):G { return new G(x) } // T-as-bound is G's T +} + +declare var g: G; +g.m(0); // ok +g.m(true); // err, bool ~> number|string +(g.m(""): G); // err, string ~> number + + +// Shadow bounds incompatible with parent + +class H { + x:T; + m(x:T) { + this.x = x; // err, m's T != H's T + } +} diff --git a/tests/type_param_variance/__snapshots__/jsfmt.spec.js.snap b/tests/type_param_variance/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..a5ec84a76359 --- /dev/null +++ b/tests/type_param_variance/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,46 @@ +exports[`test promise.js 1`] = ` +"/** + * At the moment, all type params are invariant with + * the exception of the single param to the Promise class, + * which is covariant. + * + * Explicit variance control via annotation is coming, + * but not immediately. In the meantime, Promise\'s + * participation in async/await makes certain kinds of + * errors onerous (and nonobvious) without covariance. + * + * @flow + */ + +async function foo(x: boolean): Promise { + if (x) { + return {bar: \'baz\'}; // OK, because of covariant type param + } else { + return null; + } +} + +async function run() { + console.log(await foo(true)); + console.log(await foo(false)); +} + +run() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_param_variance/jsfmt.spec.js b/tests/type_param_variance/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_param_variance/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_param_variance/promise.js b/tests/type_param_variance/promise.js new file mode 100644 index 000000000000..221bc1e52dbc --- /dev/null +++ b/tests/type_param_variance/promise.js @@ -0,0 +1,27 @@ +/** + * At the moment, all type params are invariant with + * the exception of the single param to the Promise class, + * which is covariant. + * + * Explicit variance control via annotation is coming, + * but not immediately. In the meantime, Promise's + * participation in async/await makes certain kinds of + * errors onerous (and nonobvious) without covariance. + * + * @flow + */ + +async function foo(x: boolean): Promise { + if (x) { + return {bar: 'baz'}; // OK, because of covariant type param + } else { + return null; + } +} + +async function run() { + console.log(await foo(true)); + console.log(await foo(false)); +} + +run() diff --git a/tests/type_param_variance2/__snapshots__/jsfmt.spec.js.snap b/tests/type_param_variance2/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3d2b133ccb94 --- /dev/null +++ b/tests/type_param_variance2/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,43 @@ +exports[`test promise.js 1`] = ` +"/** + * Here the definition of Promise is routed to the class Promise + * in the user-specified library libs/Promise.js + * + * In such situations we must desugar async/await primitives + * to the shadowed library definition. + * + * @flow + */ + +async function foo(x: boolean): Promise { + if (x) { + return {bar: \'baz\'}; // OK, because of covariant type param + } else { + return null; + } +} + +async function run() { + console.log(await foo(true)); + console.log(await foo(false)); +} + +run() +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_param_variance2/jsfmt.spec.js b/tests/type_param_variance2/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_param_variance2/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_param_variance2/libs/Promise.js b/tests/type_param_variance2/libs/Promise.js new file mode 100644 index 000000000000..a0b2a5ce810e --- /dev/null +++ b/tests/type_param_variance2/libs/Promise.js @@ -0,0 +1,47 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +// These annotations are copy/pasted from the built-in Flow definitions for +// Native Promises (https://phabricator.fb.com/P19792689), +// with www-specific additions added in. + +// Any definitions here will override similarly-named ones in +// library files declared earlier, including default flow libs. + +declare class Promise { + constructor(callback: ( + resolve: (result?: Promise | R) => void, + reject: (error?: any) => void + ) => void): void; + + then( + onFulfill?: ?(value: R) => Promise | ?U, + onReject?: ?(error: any) => Promise | ?U + ): Promise; + + done( + onFulfill?: ?(value: R) => void, + onReject?: ?(error: any) => void + ): void; + + catch( + onReject?: (error: any) => ?Promise | U + ): Promise; + + static resolve(object?: Promise | T): Promise; + static reject(error?: any): Promise; + + // Non-standard APIs + finally( + onSettled?: ?(value: any) => Promise | U + ): Promise; + + static cast(object?: T): Promise; + static all( + promises: Array | T>, + ): Promise>; + static race(promises: Array>): Promise; + + static allObject( + promisesByKey: T + ): Promise<{[key: $Keys]: any}>; +} diff --git a/tests/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap b/tests/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..acce7f354305 --- /dev/null +++ b/tests/type_param_variance2/libs/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,66 @@ +exports[`test Promise.js 1`] = ` +"// Copyright 2004-present Facebook. All Rights Reserved. + +// These annotations are copy/pasted from the built-in Flow definitions for +// Native Promises (https://phabricator.fb.com/P19792689), +// with www-specific additions added in. + +// Any definitions here will override similarly-named ones in +// library files declared earlier, including default flow libs. + +declare class Promise { + constructor(callback: ( + resolve: (result?: Promise | R) => void, + reject: (error?: any) => void + ) => void): void; + + then( + onFulfill?: ?(value: R) => Promise | ?U, + onReject?: ?(error: any) => Promise | ?U + ): Promise; + + done( + onFulfill?: ?(value: R) => void, + onReject?: ?(error: any) => void + ): void; + + catch( + onReject?: (error: any) => ?Promise | U + ): Promise; + + static resolve(object?: Promise | T): Promise; + static reject(error?: any): Promise; + + // Non-standard APIs + finally( + onSettled?: ?(value: any) => Promise | U + ): Promise; + + static cast(object?: T): Promise; + static all( + promises: Array | T>, + ): Promise>; + static race(promises: Array>): Promise; + + static allObject( + promisesByKey: T + ): Promise<{[key: $Keys]: any}>; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/type_param_variance2/libs/jsfmt.spec.js b/tests/type_param_variance2/libs/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/type_param_variance2/libs/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/type_param_variance2/promise.js b/tests/type_param_variance2/promise.js new file mode 100644 index 000000000000..1d09fca1ebe4 --- /dev/null +++ b/tests/type_param_variance2/promise.js @@ -0,0 +1,24 @@ +/** + * Here the definition of Promise is routed to the class Promise + * in the user-specified library libs/Promise.js + * + * In such situations we must desugar async/await primitives + * to the shadowed library definition. + * + * @flow + */ + +async function foo(x: boolean): Promise { + if (x) { + return {bar: 'baz'}; // OK, because of covariant type param + } else { + return null; + } +} + +async function run() { + console.log(await foo(true)); + console.log(await foo(false)); +} + +run() diff --git a/tests/typeapp_perf/__snapshots__/jsfmt.spec.js.snap b/tests/typeapp_perf/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..11abc849d200 --- /dev/null +++ b/tests/typeapp_perf/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,79 @@ +exports[`test test1.js 1`] = ` +"/* This test ensures that the code below does not take a long time to check. If + * this test is taking a very long time to complete, there is a bug. */ + +class A {} + +type B = A & { + +a: () => B; + +b: () => B; + +c: () => B; + +d: () => B; + +e: () => B; + +f: () => B; + +g: () => B; + +h: () => B; + +i: () => B; +}; + +declare var b: B; + +(b: B); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"/* This test ensures that the code below does not take a long time to check. If + * this test is taking a very long time to complete, there is a bug. */ + +class A {} + +type B = A & { + +a: (x: B) => void; + +b: (x: B) => void; + +c: (x: B) => void; + +d: (x: B) => void; + +e: (x: B) => void; + +f: (x: B) => void; + +g: (x: B) => void; + +h: (x: B) => void; + +i: (x: B) => void; +}; + +declare var b: B; + +(b: B); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/typeapp_perf/jsfmt.spec.js b/tests/typeapp_perf/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/typeapp_perf/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/typeapp_perf/test1.js b/tests/typeapp_perf/test1.js new file mode 100644 index 000000000000..485e397ce548 --- /dev/null +++ b/tests/typeapp_perf/test1.js @@ -0,0 +1,20 @@ +/* This test ensures that the code below does not take a long time to check. If + * this test is taking a very long time to complete, there is a bug. */ + +class A {} + +type B = A & { + +a: () => B; + +b: () => B; + +c: () => B; + +d: () => B; + +e: () => B; + +f: () => B; + +g: () => B; + +h: () => B; + +i: () => B; +}; + +declare var b: B; + +(b: B); diff --git a/tests/typeapp_perf/test2.js b/tests/typeapp_perf/test2.js new file mode 100644 index 000000000000..ee8c145c9a7f --- /dev/null +++ b/tests/typeapp_perf/test2.js @@ -0,0 +1,20 @@ +/* This test ensures that the code below does not take a long time to check. If + * this test is taking a very long time to complete, there is a bug. */ + +class A {} + +type B = A & { + +a: (x: B) => void; + +b: (x: B) => void; + +c: (x: B) => void; + +d: (x: B) => void; + +e: (x: B) => void; + +f: (x: B) => void; + +g: (x: B) => void; + +h: (x: B) => void; + +i: (x: B) => void; +}; + +declare var b: B; + +(b: B); diff --git a/tests/typecast/__snapshots__/jsfmt.spec.js.snap b/tests/typecast/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..98b7ec6dc2c4 --- /dev/null +++ b/tests/typecast/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,45 @@ +exports[`test typecast.js 1`] = ` +"/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +var tests = [ + () => { + // erroneous typcasts raise errors... + var n = (\"hey\" : number); + // ...but \'any\' does dynamic downcasts, if you must + var x: number = (\"hey\": any); + var y = ((\"hey\": any): number); + }, + + () => { + // typecasts in sequences + // (parens always required around typecasts) + var s: string = ((0: number), (\"hey\": string)); + }, + + () => { + // TODO pending array element inference issues + // control case: + // var a : Array = [0, 1, 2, 3, 4, 5, 6, 7, null]; + // typecast case: + // var b = [(0 : ?number), 1, 2, 3, 4, 5, 6, 7, null]; + } +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:706 + return fromString(\", \").join(path.map(print, \"expressions\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:706:31) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:812:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/typecast/jsfmt.spec.js b/tests/typecast/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/typecast/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/typecast/typecast.js b/tests/typecast/typecast.js new file mode 100644 index 000000000000..c3d4d9990534 --- /dev/null +++ b/tests/typecast/typecast.js @@ -0,0 +1,26 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + */ +var tests = [ + () => { + // erroneous typcasts raise errors... + var n = ("hey" : number); + // ...but 'any' does dynamic downcasts, if you must + var x: number = ("hey": any); + var y = (("hey": any): number); + }, + + () => { + // typecasts in sequences + // (parens always required around typecasts) + var s: string = ((0: number), ("hey": string)); + }, + + () => { + // TODO pending array element inference issues + // control case: + // var a : Array = [0, 1, 2, 3, 4, 5, 6, 7, null]; + // typecast case: + // var b = [(0 : ?number), 1, 2, 3, 4, 5, 6, 7, null]; + } +]; diff --git a/tests/typeof/__snapshots__/jsfmt.spec.js.snap b/tests/typeof/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..935fbee15539 --- /dev/null +++ b/tests/typeof/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,101 @@ +exports[`test typeof.js 1`] = ` +"/** + * @flow + */ + +////////////////////////////////// +// == typeof <> == // +////////////////////////////////// + +// MyClass1 is a runtime value, a constructor function +// +class MyClass1 { + getNumber(): number { return 42; } +} + +// a is an instance of MyClass1 - in runtime terms, +// an object produced by the MyClass1 constructor +// function. +// +var a: MyClass1 = new MyClass1(); + +// Following tests are errors which conflate the type +// of the class value itself with the type of its +// instances. + +// Aside: it\'s worth staring at the following (correct) +// type annotations until they make sense: +// +// MyClass1 : Class +// (new MyClass1()) : MyClass1 +// +// The first says that the MyClass1 value (constructor +// function) has type Class - the type of +// functions which produce instances of MyClass1 when +// called as a constructor. +// +// The second says that objects produced by the MyClass1 +// constructor function have type MyClass1 - the type of +// instances of MyClass1. + +// Error: assign the actual MyClass1 value to a variable +// whose annotated type is of instances of MyClass1. +// +var b: MyClass1 = MyClass1; + +class MyClass2 { + getNumber1(): number { return 42; } +} + +// The opposite error: assign an *instance* of MyClass2 +// to a variable whose annotated type is the type of +// the class value (constructor function) MyClass2 itself. +// +var c: typeof MyClass2 = new MyClass2(); + +////////////////////////////////////// +// == typeof <> == // +////////////////////////////////////// + +var numValue:number = 42; +var d: typeof numValue = 100; +var e: typeof numValue = \'asdf\'; // Error: string ~> number + +///////////////////////////////// +// == typeof <> == // +///////////////////////////////// + +type numberAlias = number; + +// This is an error because typeof takes a value, not +// a type, as an argument. However, the current error +// is suboptimal - just \'cannot resolve name\'. TODO. +// +var f: typeof numberAlias = 42; // Error: \'typeof <>\' makes no sense... + +/** + * Use of a non-class/non-function value in type annotation. + * These provoke a specific error, not just the generic + * \"type is incompatible\" + */ + + var Map = { \"A\": \"this is A\", \"B\": \"this is B\", \"C\": \"this is C\" }; + var keys: $Keys = \"A\"; // Error: ineligible value used in type anno +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/typeof/jsfmt.spec.js b/tests/typeof/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/typeof/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/typeof/typeof.js b/tests/typeof/typeof.js new file mode 100644 index 000000000000..f974bb4d58f5 --- /dev/null +++ b/tests/typeof/typeof.js @@ -0,0 +1,82 @@ +/** + * @flow + */ + +////////////////////////////////// +// == typeof <> == // +////////////////////////////////// + +// MyClass1 is a runtime value, a constructor function +// +class MyClass1 { + getNumber(): number { return 42; } +} + +// a is an instance of MyClass1 - in runtime terms, +// an object produced by the MyClass1 constructor +// function. +// +var a: MyClass1 = new MyClass1(); + +// Following tests are errors which conflate the type +// of the class value itself with the type of its +// instances. + +// Aside: it's worth staring at the following (correct) +// type annotations until they make sense: +// +// MyClass1 : Class +// (new MyClass1()) : MyClass1 +// +// The first says that the MyClass1 value (constructor +// function) has type Class - the type of +// functions which produce instances of MyClass1 when +// called as a constructor. +// +// The second says that objects produced by the MyClass1 +// constructor function have type MyClass1 - the type of +// instances of MyClass1. + +// Error: assign the actual MyClass1 value to a variable +// whose annotated type is of instances of MyClass1. +// +var b: MyClass1 = MyClass1; + +class MyClass2 { + getNumber1(): number { return 42; } +} + +// The opposite error: assign an *instance* of MyClass2 +// to a variable whose annotated type is the type of +// the class value (constructor function) MyClass2 itself. +// +var c: typeof MyClass2 = new MyClass2(); + +////////////////////////////////////// +// == typeof <> == // +////////////////////////////////////// + +var numValue:number = 42; +var d: typeof numValue = 100; +var e: typeof numValue = 'asdf'; // Error: string ~> number + +///////////////////////////////// +// == typeof <> == // +///////////////////////////////// + +type numberAlias = number; + +// This is an error because typeof takes a value, not +// a type, as an argument. However, the current error +// is suboptimal - just 'cannot resolve name'. TODO. +// +var f: typeof numberAlias = 42; // Error: 'typeof <>' makes no sense... + +/** + * Use of a non-class/non-function value in type annotation. + * These provoke a specific error, not just the generic + * "type is incompatible" + */ + + var Map = { "A": "this is A", "B": "this is B", "C": "this is C" }; + var keys: $Keys = "A"; // Error: ineligible value used in type anno diff --git a/tests/unary/__snapshots__/jsfmt.spec.js.snap b/tests/unary/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..b8235d8dedbe --- /dev/null +++ b/tests/unary/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,113 @@ +exports[`test unary.js 1`] = ` +"/* @flow */ + +function x0(y: string): number { + return +y; // ok, + exists solely for coercion +} + +function x1(y: string): number { + return -y; // error, we don't allow coercion here +} + +function x3(y: string) { + return ~y; // error, we don't allow coercion here +} + +function x4(y: string): boolean { + return !y; // ok, coercion is allowed +} + +(-1: void); // error, number ~> void +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function x0(y: string): number { + return +y;// ok, + exists solely for coercion +} +function x1(y: string): number { + return -y;// error, we don't allow coercion here +} +function x3(y: string) { + return ~y;// error, we don't allow coercion here +} +function x4(y: string): boolean { + return !y;// ok, coercion is allowed +} +(-1: void);// error, number ~> void + +" +`; + +exports[`test update.js 1`] = ` +"// @flow + +let tests = [ + function(y: number) { + y++; + y--; + ++y; + --y; + }, + + function(y: string) { + y++; // error, we don't allow coercion here + (y: number); // ok, y is a number now + y++; // error, but you still can't write a number to a string + }, + + function(y: string) { + y--; // error, we don't allow coercion here + }, + + function(y: string) { + ++y; // error, we don't allow coercion here + }, + + function(y: string) { + --y; // error, we don't allow coercion here + }, + + function() { + const y = 123; + y++; // error, can't update const + y--; // error, can't update const + }, + + function(y: any) { + y++; // ok + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + function(y: number) { + y++; + y--; + ++y; + --y; + }, + function(y: string) { + y++;// error, we don't allow coercion here + (y: number);// ok, y is a number now + y++;// error, but you still can't write a number to a string + }, + function(y: string) { + y--;// error, we don't allow coercion here + }, + function(y: string) { + ++y;// error, we don't allow coercion here + }, + function(y: string) { + --y;// error, we don't allow coercion here + }, + function() { + const y = 123; + y++;// error, can't update const + y--;// error, can't update const + }, + function(y: any) { + y++;// ok + } +]; + +" +`; diff --git a/tests/unary/jsfmt.spec.js b/tests/unary/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/unary/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/unary/unary.js b/tests/unary/unary.js new file mode 100644 index 000000000000..6588336aaa87 --- /dev/null +++ b/tests/unary/unary.js @@ -0,0 +1,19 @@ +/* @flow */ + +function x0(y: string): number { + return +y; // ok, + exists solely for coercion +} + +function x1(y: string): number { + return -y; // error, we don't allow coercion here +} + +function x3(y: string) { + return ~y; // error, we don't allow coercion here +} + +function x4(y: string): boolean { + return !y; // ok, coercion is allowed +} + +(-1: void); // error, number ~> void diff --git a/tests/unary/update.js b/tests/unary/update.js new file mode 100644 index 000000000000..690a62243627 --- /dev/null +++ b/tests/unary/update.js @@ -0,0 +1,38 @@ +// @flow + +let tests = [ + function(y: number) { + y++; + y--; + ++y; + --y; + }, + + function(y: string) { + y++; // error, we don't allow coercion here + (y: number); // ok, y is a number now + y++; // error, but you still can't write a number to a string + }, + + function(y: string) { + y--; // error, we don't allow coercion here + }, + + function(y: string) { + ++y; // error, we don't allow coercion here + }, + + function(y: string) { + --y; // error, we don't allow coercion here + }, + + function() { + const y = 123; + y++; // error, can't update const + y--; // error, can't update const + }, + + function(y: any) { + y++; // ok + }, +]; diff --git a/tests/unchecked_haste_module_vs_lib/__snapshots__/jsfmt.spec.js.snap b/tests/unchecked_haste_module_vs_lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fd33665c37b8 --- /dev/null +++ b/tests/unchecked_haste_module_vs_lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,59 @@ +exports[`test buffer.js 1`] = ` +"/** + * @providesModule buffer + * + * Not in flow. + * If this module is successfully imported/required, its + * type will be Any, so arbitraty uses won't cause errors. + * However, if a library module declaration is bound to + * the same name as an unchecked module, it will be used + * to satisfy imports/requires instead. + */ + +export var INSPECT_MAX_BYTES = 0; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @providesModule buffer + * + * Not in flow. + * If this module is successfully imported/required, its + * type will be Any, so arbitraty uses won't cause errors. + * However, if a library module declaration is bound to + * the same name as an unchecked module, it will be used + * to satisfy imports/requires instead. + */ +export var INSPECT_MAX_BYTES = 0; + +" +`; + +exports[`test test.js 1`] = ` +"/** + * Copyright 2004-present Facebook. All Rights Reserved. + * @flow + */ + +/* 'buffer' is the name of both an unchecked module in this directory, + * and a module declared in library file node.js. + * If the require below resolves to the unchecked module, the mistyping + * that follows will cause no errors, but if we resolve to the library + * instead, we'll get the desired error. + */ +var buffer = require("buffer"); +var x: string = buffer.INSPECT_MAX_BYTES; // error, number ~/> string +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * @flow + */ +/* 'buffer' is the name of both an unchecked module in this directory, + * and a module declared in library file node.js. + * If the require below resolves to the unchecked module, the mistyping + * that follows will cause no errors, but if we resolve to the library + * instead, we'll get the desired error. + */ +var buffer = require("buffer"); +var x: string = buffer.INSPECT_MAX_BYTES;// error, number ~/> string + +" +`; diff --git a/tests/unchecked_haste_module_vs_lib/buffer.js b/tests/unchecked_haste_module_vs_lib/buffer.js new file mode 100644 index 000000000000..223b08155060 --- /dev/null +++ b/tests/unchecked_haste_module_vs_lib/buffer.js @@ -0,0 +1,12 @@ +/** + * @providesModule buffer + * + * Not in flow. + * If this module is successfully imported/required, its + * type will be Any, so arbitraty uses won't cause errors. + * However, if a library module declaration is bound to + * the same name as an unchecked module, it will be used + * to satisfy imports/requires instead. + */ + +export var INSPECT_MAX_BYTES = 0; diff --git a/tests/unchecked_haste_module_vs_lib/jsfmt.spec.js b/tests/unchecked_haste_module_vs_lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/unchecked_haste_module_vs_lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/unchecked_haste_module_vs_lib/test.js b/tests/unchecked_haste_module_vs_lib/test.js new file mode 100644 index 000000000000..9cb508a5e998 --- /dev/null +++ b/tests/unchecked_haste_module_vs_lib/test.js @@ -0,0 +1,13 @@ +/** + * Copyright 2004-present Facebook. All Rights Reserved. + * @flow + */ + +/* 'buffer' is the name of both an unchecked module in this directory, + * and a module declared in library file node.js. + * If the require below resolves to the unchecked module, the mistyping + * that follows will cause no errors, but if we resolve to the library + * instead, we'll get the desired error. + */ +var buffer = require("buffer"); +var x: string = buffer.INSPECT_MAX_BYTES; // error, number ~/> string diff --git a/tests/unchecked_node_module_vs_lib/__snapshots__/jsfmt.spec.js.snap b/tests/unchecked_node_module_vs_lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..3831c78c27d0 --- /dev/null +++ b/tests/unchecked_node_module_vs_lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,53 @@ +exports[`test test.js 1`] = ` +"/** + * Test resolution precedence in node: + * checked module > lib def > unchecked module + * + * @flow + */ + +// node_modules/buffer/index.js is unchecked, +// so we shouldn't pick up its boolean redefinition of INSPECT_MAX_BYTES +// +var buffer = require("buffer"); +var b: boolean = buffer.INSPECT_MAX_BYTES; // error, number ~/> boolean + +// node_modules/crypto/index.js is checked, +// so we should pick up its boolean redefinition of DEFAULT_ENCODING +// +var crypto = require("crypto"); +var b: boolean = crypto.DEFAULT_ENCODING; // no error, we've overridden + +// names that are explicit paths shouldn't fall back to lib defs +// +var buffer2 = require("./buffer"); +var x2: string = buffer2.INSPECT_MAX_BYTES; // error, module not found + +var buffer3 = require("./buffer.js"); +var x3: string = buffer3.INSPECT_MAX_BYTES; // error, module not found +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * Test resolution precedence in node: + * checked module > lib def > unchecked module + * + * @flow + */ +// node_modules/buffer/index.js is unchecked, +// so we shouldn't pick up its boolean redefinition of INSPECT_MAX_BYTES +// +var buffer = require("buffer"); +var b: boolean = buffer.INSPECT_MAX_BYTES;// error, number ~/> boolean +// node_modules/crypto/index.js is checked, +// so we should pick up its boolean redefinition of DEFAULT_ENCODING +// +var crypto = require("crypto"); +var b: boolean = crypto.DEFAULT_ENCODING;// no error, we've overridden +// names that are explicit paths shouldn't fall back to lib defs +// +var buffer2 = require("./buffer"); +var x2: string = buffer2.INSPECT_MAX_BYTES;// error, module not found +var buffer3 = require("./buffer.js"); +var x3: string = buffer3.INSPECT_MAX_BYTES;// error, module not found + +" +`; diff --git a/tests/unchecked_node_module_vs_lib/jsfmt.spec.js b/tests/unchecked_node_module_vs_lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/unchecked_node_module_vs_lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/unchecked_node_module_vs_lib/test.js b/tests/unchecked_node_module_vs_lib/test.js new file mode 100644 index 000000000000..06b24ab57875 --- /dev/null +++ b/tests/unchecked_node_module_vs_lib/test.js @@ -0,0 +1,26 @@ +/** + * Test resolution precedence in node: + * checked module > lib def > unchecked module + * + * @flow + */ + +// node_modules/buffer/index.js is unchecked, +// so we shouldn't pick up its boolean redefinition of INSPECT_MAX_BYTES +// +var buffer = require("buffer"); +var b: boolean = buffer.INSPECT_MAX_BYTES; // error, number ~/> boolean + +// node_modules/crypto/index.js is checked, +// so we should pick up its boolean redefinition of DEFAULT_ENCODING +// +var crypto = require("crypto"); +var b: boolean = crypto.DEFAULT_ENCODING; // no error, we've overridden + +// names that are explicit paths shouldn't fall back to lib defs +// +var buffer2 = require("./buffer"); +var x2: string = buffer2.INSPECT_MAX_BYTES; // error, module not found + +var buffer3 = require("./buffer.js"); +var x3: string = buffer3.INSPECT_MAX_BYTES; // error, module not found diff --git a/tests/undefined/__snapshots__/jsfmt.spec.js.snap b/tests/undefined/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..543dc8f9448e --- /dev/null +++ b/tests/undefined/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,119 @@ +exports[`test issue-518.js 1`] = ` +"function doSomethingAsync(): Promise { + return new Promise((resolve, reject) => { + resolve(); // OK to leave out arg, same as resolve(undefined) + + var anotherVoidPromise: Promise = Promise.resolve(); + resolve(anotherVoidPromise); + }); +} + +// simpler repro to show that too few args are fine when expecting void +function foo(x: void) { } +foo(); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test undefined.js 1`] = ` +"function foo() { + var x; + x.foo(); +} + +function bar() { + var x:?{ bar():void; }; + if (x) x.bar(); +} + +function qux(x?: number, y:string = \"\", z) { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test undefined2.js 1`] = ` +"// @flow + +let tests = [ + function(x: number) { + var id; + var name = id ? \'John\' : undefined; + (name: boolean); // error, string or void + + const bar = [ + undefined, + \'bar\', + ]; + (bar[x]: boolean); // error, string or void + }, + + function(x: number) { + var undefined = \'foo\'; + (undefined: string); // ok + + var x; + if (x !== undefined) { + x[0]; // should error, could be void + } + + const bar = [ + undefined, + \'bar\', + ]; + (bar[x]: boolean); // error, string only + }, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +let tests = [ + function(x: number) { + var id; + var name = (id ? \"John\" : undefined); + (name: boolean);// error, string or void + const bar = [ undefined, \"bar\" ]; + (bar[x]: boolean);// error, string or void + }, + function(x: number) { + var undefined = \"foo\"; + (undefined: string);// ok + var x; + if (x !== undefined) { + x[0];// should error, could be void + } + const bar = [ undefined, \"bar\" ]; + (bar[x]: boolean);// error, string only + } +]; + +" +`; diff --git a/tests/undefined/issue-518.js b/tests/undefined/issue-518.js new file mode 100644 index 000000000000..e73c51091cb1 --- /dev/null +++ b/tests/undefined/issue-518.js @@ -0,0 +1,12 @@ +function doSomethingAsync(): Promise { + return new Promise((resolve, reject) => { + resolve(); // OK to leave out arg, same as resolve(undefined) + + var anotherVoidPromise: Promise = Promise.resolve(); + resolve(anotherVoidPromise); + }); +} + +// simpler repro to show that too few args are fine when expecting void +function foo(x: void) { } +foo(); diff --git a/tests/undefined/jsfmt.spec.js b/tests/undefined/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/undefined/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/undefined/undefined.js b/tests/undefined/undefined.js new file mode 100644 index 000000000000..347d6206cfc3 --- /dev/null +++ b/tests/undefined/undefined.js @@ -0,0 +1,11 @@ +function foo() { + var x; + x.foo(); +} + +function bar() { + var x:?{ bar():void; }; + if (x) x.bar(); +} + +function qux(x?: number, y:string = "", z) { } diff --git a/tests/undefined/undefined2.js b/tests/undefined/undefined2.js new file mode 100644 index 000000000000..bf7f503f38b5 --- /dev/null +++ b/tests/undefined/undefined2.js @@ -0,0 +1,31 @@ +// @flow + +let tests = [ + function(x: number) { + var id; + var name = id ? 'John' : undefined; + (name: boolean); // error, string or void + + const bar = [ + undefined, + 'bar', + ]; + (bar[x]: boolean); // error, string or void + }, + + function(x: number) { + var undefined = 'foo'; + (undefined: string); // ok + + var x; + if (x !== undefined) { + x[0]; // should error, could be void + } + + const bar = [ + undefined, + 'bar', + ]; + (bar[x]: boolean); // error, string only + }, +]; diff --git a/tests/unicode/UnicodeUtils.js b/tests/unicode/UnicodeUtils.js new file mode 100644 index 000000000000..3a06fc53b987 --- /dev/null +++ b/tests/unicode/UnicodeUtils.js @@ -0,0 +1,34 @@ +/** + * @flow + */ + +/** + * @param {number} codeUnit A Unicode code-unit, in range [0, 0x10FFFF] + * @return {boolean} Whether code-unit is in a surrogate (hi/low) range + */ +function inSurrogateRange(codeUnit) { + return 0xD800 <= codeUnit && codeUnit <= 0xDFFF; +} + + +/** + * Return the length of the original Unicode character at given position in the + * String by looking into the UTF-16 code unit; that is equal to 1 for any + * non-surrogate characters in BMP ([U+0000..U+D7FF] and [U+E000, U+FFFF]); and + * returns 2 for the hi/low surrogates ([U+D800..U+DFFF]), which are in fact + * representing non-BMP characters ([U+10000..U+10FFFF]). + * + * Examples: + * - '\u0020' => 1 + * - '\u3020' => 1 + * - '\uD835' => 2 + * - '\uD835\uDDEF' => 2 + * - '\uDDEF' => 2 + * + * @param {string} str Non-empty string + * @param {number} pos Position in the string to look for one code unit + * @return {number} Number 1 or 2 + */ +function utf16Length(str, pos) { + return 1 + inSurrogateRange(str.charCodeAt(pos)); +} diff --git a/tests/unicode/__snapshots__/jsfmt.spec.js.snap b/tests/unicode/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2ede222aa532 --- /dev/null +++ b/tests/unicode/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,70 @@ +exports[`test UnicodeUtils.js 1`] = ` +"/** + * @flow + */ + +/** + * @param {number} codeUnit A Unicode code-unit, in range [0, 0x10FFFF] + * @return {boolean} Whether code-unit is in a surrogate (hi/low) range + */ +function inSurrogateRange(codeUnit) { + return 0xD800 <= codeUnit && codeUnit <= 0xDFFF; +} + + +/** + * Return the length of the original Unicode character at given position in the + * String by looking into the UTF-16 code unit; that is equal to 1 for any + * non-surrogate characters in BMP ([U+0000..U+D7FF] and [U+E000, U+FFFF]); and + * returns 2 for the hi/low surrogates ([U+D800..U+DFFF]), which are in fact + * representing non-BMP characters ([U+10000..U+10FFFF]). + * + * Examples: + * - \'\\u0020\' => 1 + * - \'\\u3020\' => 1 + * - \'\\uD835\' => 2 + * - \'\\uD835\\uDDEF\' => 2 + * - \'\\uDDEF\' => 2 + * + * @param {string} str Non-empty string + * @param {number} pos Position in the string to look for one code unit + * @return {number} Number 1 or 2 + */ +function utf16Length(str, pos) { + return 1 + inSurrogateRange(str.charCodeAt(pos)); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @flow + */ +/** + * @param {number} codeUnit A Unicode code-unit, in range [0, 0x10FFFF] + * @return {boolean} Whether code-unit is in a surrogate (hi/low) range + */ +function inSurrogateRange(codeUnit) { + return 55296 <= codeUnit && codeUnit <= 57343; +} +/** + * Return the length of the original Unicode character at given position in the + * String by looking into the UTF-16 code unit; that is equal to 1 for any + * non-surrogate characters in BMP ([U+0000..U+D7FF] and [U+E000, U+FFFF]); and + * returns 2 for the hi/low surrogates ([U+D800..U+DFFF]), which are in fact + * representing non-BMP characters ([U+10000..U+10FFFF]). + * + * Examples: + * - \'\\u0020\' => 1 + * - \'\\u3020\' => 1 + * - \'\\uD835\' => 2 + * - \'\\uD835\\uDDEF\' => 2 + * - \'\\uDDEF\' => 2 + * + * @param {string} str Non-empty string + * @param {number} pos Position in the string to look for one code unit + * @return {number} Number 1 or 2 + */ +function utf16Length(str, pos) { + return 1 + inSurrogateRange(str.charCodeAt(pos)); +} + +" +`; diff --git a/tests/unicode/jsfmt.spec.js b/tests/unicode/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/unicode/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/union-intersection/__snapshots__/jsfmt.spec.js.snap b/tests/union-intersection/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..9ae9ba5a1427 --- /dev/null +++ b/tests/union-intersection/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,4057 @@ +exports[`test gen_big_disjoint_union.js 1`] = ` +"// perf test for big disjoint union with 1000 cases +type TAction = +{ + type: \'a1\', + a1: number, +} | +{ + type: \'a2\', + a1: number, +} | +{ + type: \'a3\', + a1: number, +} | +{ + type: \'a4\', + a1: number, +} | +{ + type: \'a5\', + a1: number, +} | +{ + type: \'a6\', + a1: number, +} | +{ + type: \'a7\', + a1: number, +} | +{ + type: \'a8\', + a1: number, +} | +{ + type: \'a9\', + a1: number, +} | +{ + type: \'a10\', + a1: number, +} | +{ + type: \'a11\', + a2: number, +} | +{ + type: \'a12\', + a2: number, +} | +{ + type: \'a13\', + a2: number, +} | +{ + type: \'a14\', + a2: number, +} | +{ + type: \'a15\', + a2: number, +} | +{ + type: \'a16\', + a2: number, +} | +{ + type: \'a17\', + a2: number, +} | +{ + type: \'a18\', + a2: number, +} | +{ + type: \'a19\', + a2: number, +} | +{ + type: \'a20\', + a2: number, +} | +{ + type: \'a21\', + a3: number, +} | +{ + type: \'a22\', + a3: number, +} | +{ + type: \'a23\', + a3: number, +} | +{ + type: \'a24\', + a3: number, +} | +{ + type: \'a25\', + a3: number, +} | +{ + type: \'a26\', + a3: number, +} | +{ + type: \'a27\', + a3: number, +} | +{ + type: \'a28\', + a3: number, +} | +{ + type: \'a29\', + a3: number, +} | +{ + type: \'a30\', + a3: number, +} | +{ + type: \'a31\', + a4: number, +} | +{ + type: \'a32\', + a4: number, +} | +{ + type: \'a33\', + a4: number, +} | +{ + type: \'a34\', + a4: number, +} | +{ + type: \'a35\', + a4: number, +} | +{ + type: \'a36\', + a4: number, +} | +{ + type: \'a37\', + a4: number, +} | +{ + type: \'a38\', + a4: number, +} | +{ + type: \'a39\', + a4: number, +} | +{ + type: \'a40\', + a4: number, +} | +{ + type: \'a41\', + a5: number, +} | +{ + type: \'a42\', + a5: number, +} | +{ + type: \'a43\', + a5: number, +} | +{ + type: \'a44\', + a5: number, +} | +{ + type: \'a45\', + a5: number, +} | +{ + type: \'a46\', + a5: number, +} | +{ + type: \'a47\', + a5: number, +} | +{ + type: \'a48\', + a5: number, +} | +{ + type: \'a49\', + a5: number, +} | +{ + type: \'a50\', + a5: number, +} | +{ + type: \'a51\', + a6: number, +} | +{ + type: \'a52\', + a6: number, +} | +{ + type: \'a53\', + a6: number, +} | +{ + type: \'a54\', + a6: number, +} | +{ + type: \'a55\', + a6: number, +} | +{ + type: \'a56\', + a6: number, +} | +{ + type: \'a57\', + a6: number, +} | +{ + type: \'a58\', + a6: number, +} | +{ + type: \'a59\', + a6: number, +} | +{ + type: \'a60\', + a6: number, +} | +{ + type: \'a61\', + a7: number, +} | +{ + type: \'a62\', + a7: number, +} | +{ + type: \'a63\', + a7: number, +} | +{ + type: \'a64\', + a7: number, +} | +{ + type: \'a65\', + a7: number, +} | +{ + type: \'a66\', + a7: number, +} | +{ + type: \'a67\', + a7: number, +} | +{ + type: \'a68\', + a7: number, +} | +{ + type: \'a69\', + a7: number, +} | +{ + type: \'a70\', + a7: number, +} | +{ + type: \'a71\', + a8: number, +} | +{ + type: \'a72\', + a8: number, +} | +{ + type: \'a73\', + a8: number, +} | +{ + type: \'a74\', + a8: number, +} | +{ + type: \'a75\', + a8: number, +} | +{ + type: \'a76\', + a8: number, +} | +{ + type: \'a77\', + a8: number, +} | +{ + type: \'a78\', + a8: number, +} | +{ + type: \'a79\', + a8: number, +} | +{ + type: \'a80\', + a8: number, +} | +{ + type: \'a81\', + a9: number, +} | +{ + type: \'a82\', + a9: number, +} | +{ + type: \'a83\', + a9: number, +} | +{ + type: \'a84\', + a9: number, +} | +{ + type: \'a85\', + a9: number, +} | +{ + type: \'a86\', + a9: number, +} | +{ + type: \'a87\', + a9: number, +} | +{ + type: \'a88\', + a9: number, +} | +{ + type: \'a89\', + a9: number, +} | +{ + type: \'a90\', + a9: number, +} | +{ + type: \'a91\', + a10: number, +} | +{ + type: \'a92\', + a10: number, +} | +{ + type: \'a93\', + a10: number, +} | +{ + type: \'a94\', + a10: number, +} | +{ + type: \'a95\', + a10: number, +} | +{ + type: \'a96\', + a10: number, +} | +{ + type: \'a97\', + a10: number, +} | +{ + type: \'a98\', + a10: number, +} | +{ + type: \'a99\', + a10: number, +} | +{ + type: \'a100\', + a10: number, +} | +{ + type: \'a101\', + a11: number, +} | +{ + type: \'a102\', + a11: number, +} | +{ + type: \'a103\', + a11: number, +} | +{ + type: \'a104\', + a11: number, +} | +{ + type: \'a105\', + a11: number, +} | +{ + type: \'a106\', + a11: number, +} | +{ + type: \'a107\', + a11: number, +} | +{ + type: \'a108\', + a11: number, +} | +{ + type: \'a109\', + a11: number, +} | +{ + type: \'a110\', + a11: number, +} | +{ + type: \'a111\', + a12: number, +} | +{ + type: \'a112\', + a12: number, +} | +{ + type: \'a113\', + a12: number, +} | +{ + type: \'a114\', + a12: number, +} | +{ + type: \'a115\', + a12: number, +} | +{ + type: \'a116\', + a12: number, +} | +{ + type: \'a117\', + a12: number, +} | +{ + type: \'a118\', + a12: number, +} | +{ + type: \'a119\', + a12: number, +} | +{ + type: \'a120\', + a12: number, +} | +{ + type: \'a121\', + a13: number, +} | +{ + type: \'a122\', + a13: number, +} | +{ + type: \'a123\', + a13: number, +} | +{ + type: \'a124\', + a13: number, +} | +{ + type: \'a125\', + a13: number, +} | +{ + type: \'a126\', + a13: number, +} | +{ + type: \'a127\', + a13: number, +} | +{ + type: \'a128\', + a13: number, +} | +{ + type: \'a129\', + a13: number, +} | +{ + type: \'a130\', + a13: number, +} | +{ + type: \'a131\', + a14: number, +} | +{ + type: \'a132\', + a14: number, +} | +{ + type: \'a133\', + a14: number, +} | +{ + type: \'a134\', + a14: number, +} | +{ + type: \'a135\', + a14: number, +} | +{ + type: \'a136\', + a14: number, +} | +{ + type: \'a137\', + a14: number, +} | +{ + type: \'a138\', + a14: number, +} | +{ + type: \'a139\', + a14: number, +} | +{ + type: \'a140\', + a14: number, +} | +{ + type: \'a141\', + a15: number, +} | +{ + type: \'a142\', + a15: number, +} | +{ + type: \'a143\', + a15: number, +} | +{ + type: \'a144\', + a15: number, +} | +{ + type: \'a145\', + a15: number, +} | +{ + type: \'a146\', + a15: number, +} | +{ + type: \'a147\', + a15: number, +} | +{ + type: \'a148\', + a15: number, +} | +{ + type: \'a149\', + a15: number, +} | +{ + type: \'a150\', + a15: number, +} | +{ + type: \'a151\', + a16: number, +} | +{ + type: \'a152\', + a16: number, +} | +{ + type: \'a153\', + a16: number, +} | +{ + type: \'a154\', + a16: number, +} | +{ + type: \'a155\', + a16: number, +} | +{ + type: \'a156\', + a16: number, +} | +{ + type: \'a157\', + a16: number, +} | +{ + type: \'a158\', + a16: number, +} | +{ + type: \'a159\', + a16: number, +} | +{ + type: \'a160\', + a16: number, +} | +{ + type: \'a161\', + a17: number, +} | +{ + type: \'a162\', + a17: number, +} | +{ + type: \'a163\', + a17: number, +} | +{ + type: \'a164\', + a17: number, +} | +{ + type: \'a165\', + a17: number, +} | +{ + type: \'a166\', + a17: number, +} | +{ + type: \'a167\', + a17: number, +} | +{ + type: \'a168\', + a17: number, +} | +{ + type: \'a169\', + a17: number, +} | +{ + type: \'a170\', + a17: number, +} | +{ + type: \'a171\', + a18: number, +} | +{ + type: \'a172\', + a18: number, +} | +{ + type: \'a173\', + a18: number, +} | +{ + type: \'a174\', + a18: number, +} | +{ + type: \'a175\', + a18: number, +} | +{ + type: \'a176\', + a18: number, +} | +{ + type: \'a177\', + a18: number, +} | +{ + type: \'a178\', + a18: number, +} | +{ + type: \'a179\', + a18: number, +} | +{ + type: \'a180\', + a18: number, +} | +{ + type: \'a181\', + a19: number, +} | +{ + type: \'a182\', + a19: number, +} | +{ + type: \'a183\', + a19: number, +} | +{ + type: \'a184\', + a19: number, +} | +{ + type: \'a185\', + a19: number, +} | +{ + type: \'a186\', + a19: number, +} | +{ + type: \'a187\', + a19: number, +} | +{ + type: \'a188\', + a19: number, +} | +{ + type: \'a189\', + a19: number, +} | +{ + type: \'a190\', + a19: number, +} | +{ + type: \'a191\', + a20: number, +} | +{ + type: \'a192\', + a20: number, +} | +{ + type: \'a193\', + a20: number, +} | +{ + type: \'a194\', + a20: number, +} | +{ + type: \'a195\', + a20: number, +} | +{ + type: \'a196\', + a20: number, +} | +{ + type: \'a197\', + a20: number, +} | +{ + type: \'a198\', + a20: number, +} | +{ + type: \'a199\', + a20: number, +} | +{ + type: \'a200\', + a20: number, +} | +{ + type: \'a201\', + a21: number, +} | +{ + type: \'a202\', + a21: number, +} | +{ + type: \'a203\', + a21: number, +} | +{ + type: \'a204\', + a21: number, +} | +{ + type: \'a205\', + a21: number, +} | +{ + type: \'a206\', + a21: number, +} | +{ + type: \'a207\', + a21: number, +} | +{ + type: \'a208\', + a21: number, +} | +{ + type: \'a209\', + a21: number, +} | +{ + type: \'a210\', + a21: number, +} | +{ + type: \'a211\', + a22: number, +} | +{ + type: \'a212\', + a22: number, +} | +{ + type: \'a213\', + a22: number, +} | +{ + type: \'a214\', + a22: number, +} | +{ + type: \'a215\', + a22: number, +} | +{ + type: \'a216\', + a22: number, +} | +{ + type: \'a217\', + a22: number, +} | +{ + type: \'a218\', + a22: number, +} | +{ + type: \'a219\', + a22: number, +} | +{ + type: \'a220\', + a22: number, +} | +{ + type: \'a221\', + a23: number, +} | +{ + type: \'a222\', + a23: number, +} | +{ + type: \'a223\', + a23: number, +} | +{ + type: \'a224\', + a23: number, +} | +{ + type: \'a225\', + a23: number, +} | +{ + type: \'a226\', + a23: number, +} | +{ + type: \'a227\', + a23: number, +} | +{ + type: \'a228\', + a23: number, +} | +{ + type: \'a229\', + a23: number, +} | +{ + type: \'a230\', + a23: number, +} | +{ + type: \'a231\', + a24: number, +} | +{ + type: \'a232\', + a24: number, +} | +{ + type: \'a233\', + a24: number, +} | +{ + type: \'a234\', + a24: number, +} | +{ + type: \'a235\', + a24: number, +} | +{ + type: \'a236\', + a24: number, +} | +{ + type: \'a237\', + a24: number, +} | +{ + type: \'a238\', + a24: number, +} | +{ + type: \'a239\', + a24: number, +} | +{ + type: \'a240\', + a24: number, +} | +{ + type: \'a241\', + a25: number, +} | +{ + type: \'a242\', + a25: number, +} | +{ + type: \'a243\', + a25: number, +} | +{ + type: \'a244\', + a25: number, +} | +{ + type: \'a245\', + a25: number, +} | +{ + type: \'a246\', + a25: number, +} | +{ + type: \'a247\', + a25: number, +} | +{ + type: \'a248\', + a25: number, +} | +{ + type: \'a249\', + a25: number, +} | +{ + type: \'a250\', + a25: number, +} | +{ + type: \'a251\', + a26: number, +} | +{ + type: \'a252\', + a26: number, +} | +{ + type: \'a253\', + a26: number, +} | +{ + type: \'a254\', + a26: number, +} | +{ + type: \'a255\', + a26: number, +} | +{ + type: \'a256\', + a26: number, +} | +{ + type: \'a257\', + a26: number, +} | +{ + type: \'a258\', + a26: number, +} | +{ + type: \'a259\', + a26: number, +} | +{ + type: \'a260\', + a26: number, +} | +{ + type: \'a261\', + a27: number, +} | +{ + type: \'a262\', + a27: number, +} | +{ + type: \'a263\', + a27: number, +} | +{ + type: \'a264\', + a27: number, +} | +{ + type: \'a265\', + a27: number, +} | +{ + type: \'a266\', + a27: number, +} | +{ + type: \'a267\', + a27: number, +} | +{ + type: \'a268\', + a27: number, +} | +{ + type: \'a269\', + a27: number, +} | +{ + type: \'a270\', + a27: number, +} | +{ + type: \'a271\', + a28: number, +} | +{ + type: \'a272\', + a28: number, +} | +{ + type: \'a273\', + a28: number, +} | +{ + type: \'a274\', + a28: number, +} | +{ + type: \'a275\', + a28: number, +} | +{ + type: \'a276\', + a28: number, +} | +{ + type: \'a277\', + a28: number, +} | +{ + type: \'a278\', + a28: number, +} | +{ + type: \'a279\', + a28: number, +} | +{ + type: \'a280\', + a28: number, +} | +{ + type: \'a281\', + a29: number, +} | +{ + type: \'a282\', + a29: number, +} | +{ + type: \'a283\', + a29: number, +} | +{ + type: \'a284\', + a29: number, +} | +{ + type: \'a285\', + a29: number, +} | +{ + type: \'a286\', + a29: number, +} | +{ + type: \'a287\', + a29: number, +} | +{ + type: \'a288\', + a29: number, +} | +{ + type: \'a289\', + a29: number, +} | +{ + type: \'a290\', + a29: number, +} | +{ + type: \'a291\', + a30: number, +} | +{ + type: \'a292\', + a30: number, +} | +{ + type: \'a293\', + a30: number, +} | +{ + type: \'a294\', + a30: number, +} | +{ + type: \'a295\', + a30: number, +} | +{ + type: \'a296\', + a30: number, +} | +{ + type: \'a297\', + a30: number, +} | +{ + type: \'a298\', + a30: number, +} | +{ + type: \'a299\', + a30: number, +} | +{ + type: \'a300\', + a30: number, +} | +{ + type: \'a301\', + a31: number, +} | +{ + type: \'a302\', + a31: number, +} | +{ + type: \'a303\', + a31: number, +} | +{ + type: \'a304\', + a31: number, +} | +{ + type: \'a305\', + a31: number, +} | +{ + type: \'a306\', + a31: number, +} | +{ + type: \'a307\', + a31: number, +} | +{ + type: \'a308\', + a31: number, +} | +{ + type: \'a309\', + a31: number, +} | +{ + type: \'a310\', + a31: number, +} | +{ + type: \'a311\', + a32: number, +} | +{ + type: \'a312\', + a32: number, +} | +{ + type: \'a313\', + a32: number, +} | +{ + type: \'a314\', + a32: number, +} | +{ + type: \'a315\', + a32: number, +} | +{ + type: \'a316\', + a32: number, +} | +{ + type: \'a317\', + a32: number, +} | +{ + type: \'a318\', + a32: number, +} | +{ + type: \'a319\', + a32: number, +} | +{ + type: \'a320\', + a32: number, +} | +{ + type: \'a321\', + a33: number, +} | +{ + type: \'a322\', + a33: number, +} | +{ + type: \'a323\', + a33: number, +} | +{ + type: \'a324\', + a33: number, +} | +{ + type: \'a325\', + a33: number, +} | +{ + type: \'a326\', + a33: number, +} | +{ + type: \'a327\', + a33: number, +} | +{ + type: \'a328\', + a33: number, +} | +{ + type: \'a329\', + a33: number, +} | +{ + type: \'a330\', + a33: number, +} | +{ + type: \'a331\', + a34: number, +} | +{ + type: \'a332\', + a34: number, +} | +{ + type: \'a333\', + a34: number, +} | +{ + type: \'a334\', + a34: number, +} | +{ + type: \'a335\', + a34: number, +} | +{ + type: \'a336\', + a34: number, +} | +{ + type: \'a337\', + a34: number, +} | +{ + type: \'a338\', + a34: number, +} | +{ + type: \'a339\', + a34: number, +} | +{ + type: \'a340\', + a34: number, +} | +{ + type: \'a341\', + a35: number, +} | +{ + type: \'a342\', + a35: number, +} | +{ + type: \'a343\', + a35: number, +} | +{ + type: \'a344\', + a35: number, +} | +{ + type: \'a345\', + a35: number, +} | +{ + type: \'a346\', + a35: number, +} | +{ + type: \'a347\', + a35: number, +} | +{ + type: \'a348\', + a35: number, +} | +{ + type: \'a349\', + a35: number, +} | +{ + type: \'a350\', + a35: number, +} | +{ + type: \'a351\', + a36: number, +} | +{ + type: \'a352\', + a36: number, +} | +{ + type: \'a353\', + a36: number, +} | +{ + type: \'a354\', + a36: number, +} | +{ + type: \'a355\', + a36: number, +} | +{ + type: \'a356\', + a36: number, +} | +{ + type: \'a357\', + a36: number, +} | +{ + type: \'a358\', + a36: number, +} | +{ + type: \'a359\', + a36: number, +} | +{ + type: \'a360\', + a36: number, +} | +{ + type: \'a361\', + a37: number, +} | +{ + type: \'a362\', + a37: number, +} | +{ + type: \'a363\', + a37: number, +} | +{ + type: \'a364\', + a37: number, +} | +{ + type: \'a365\', + a37: number, +} | +{ + type: \'a366\', + a37: number, +} | +{ + type: \'a367\', + a37: number, +} | +{ + type: \'a368\', + a37: number, +} | +{ + type: \'a369\', + a37: number, +} | +{ + type: \'a370\', + a37: number, +} | +{ + type: \'a371\', + a38: number, +} | +{ + type: \'a372\', + a38: number, +} | +{ + type: \'a373\', + a38: number, +} | +{ + type: \'a374\', + a38: number, +} | +{ + type: \'a375\', + a38: number, +} | +{ + type: \'a376\', + a38: number, +} | +{ + type: \'a377\', + a38: number, +} | +{ + type: \'a378\', + a38: number, +} | +{ + type: \'a379\', + a38: number, +} | +{ + type: \'a380\', + a38: number, +} | +{ + type: \'a381\', + a39: number, +} | +{ + type: \'a382\', + a39: number, +} | +{ + type: \'a383\', + a39: number, +} | +{ + type: \'a384\', + a39: number, +} | +{ + type: \'a385\', + a39: number, +} | +{ + type: \'a386\', + a39: number, +} | +{ + type: \'a387\', + a39: number, +} | +{ + type: \'a388\', + a39: number, +} | +{ + type: \'a389\', + a39: number, +} | +{ + type: \'a390\', + a39: number, +} | +{ + type: \'a391\', + a40: number, +} | +{ + type: \'a392\', + a40: number, +} | +{ + type: \'a393\', + a40: number, +} | +{ + type: \'a394\', + a40: number, +} | +{ + type: \'a395\', + a40: number, +} | +{ + type: \'a396\', + a40: number, +} | +{ + type: \'a397\', + a40: number, +} | +{ + type: \'a398\', + a40: number, +} | +{ + type: \'a399\', + a40: number, +} | +{ + type: \'a400\', + a40: number, +} | +{ + type: \'a401\', + a41: number, +} | +{ + type: \'a402\', + a41: number, +} | +{ + type: \'a403\', + a41: number, +} | +{ + type: \'a404\', + a41: number, +} | +{ + type: \'a405\', + a41: number, +} | +{ + type: \'a406\', + a41: number, +} | +{ + type: \'a407\', + a41: number, +} | +{ + type: \'a408\', + a41: number, +} | +{ + type: \'a409\', + a41: number, +} | +{ + type: \'a410\', + a41: number, +} | +{ + type: \'a411\', + a42: number, +} | +{ + type: \'a412\', + a42: number, +} | +{ + type: \'a413\', + a42: number, +} | +{ + type: \'a414\', + a42: number, +} | +{ + type: \'a415\', + a42: number, +} | +{ + type: \'a416\', + a42: number, +} | +{ + type: \'a417\', + a42: number, +} | +{ + type: \'a418\', + a42: number, +} | +{ + type: \'a419\', + a42: number, +} | +{ + type: \'a420\', + a42: number, +} | +{ + type: \'a421\', + a43: number, +} | +{ + type: \'a422\', + a43: number, +} | +{ + type: \'a423\', + a43: number, +} | +{ + type: \'a424\', + a43: number, +} | +{ + type: \'a425\', + a43: number, +} | +{ + type: \'a426\', + a43: number, +} | +{ + type: \'a427\', + a43: number, +} | +{ + type: \'a428\', + a43: number, +} | +{ + type: \'a429\', + a43: number, +} | +{ + type: \'a430\', + a43: number, +} | +{ + type: \'a431\', + a44: number, +} | +{ + type: \'a432\', + a44: number, +} | +{ + type: \'a433\', + a44: number, +} | +{ + type: \'a434\', + a44: number, +} | +{ + type: \'a435\', + a44: number, +} | +{ + type: \'a436\', + a44: number, +} | +{ + type: \'a437\', + a44: number, +} | +{ + type: \'a438\', + a44: number, +} | +{ + type: \'a439\', + a44: number, +} | +{ + type: \'a440\', + a44: number, +} | +{ + type: \'a441\', + a45: number, +} | +{ + type: \'a442\', + a45: number, +} | +{ + type: \'a443\', + a45: number, +} | +{ + type: \'a444\', + a45: number, +} | +{ + type: \'a445\', + a45: number, +} | +{ + type: \'a446\', + a45: number, +} | +{ + type: \'a447\', + a45: number, +} | +{ + type: \'a448\', + a45: number, +} | +{ + type: \'a449\', + a45: number, +} | +{ + type: \'a450\', + a45: number, +} | +{ + type: \'a451\', + a46: number, +} | +{ + type: \'a452\', + a46: number, +} | +{ + type: \'a453\', + a46: number, +} | +{ + type: \'a454\', + a46: number, +} | +{ + type: \'a455\', + a46: number, +} | +{ + type: \'a456\', + a46: number, +} | +{ + type: \'a457\', + a46: number, +} | +{ + type: \'a458\', + a46: number, +} | +{ + type: \'a459\', + a46: number, +} | +{ + type: \'a460\', + a46: number, +} | +{ + type: \'a461\', + a47: number, +} | +{ + type: \'a462\', + a47: number, +} | +{ + type: \'a463\', + a47: number, +} | +{ + type: \'a464\', + a47: number, +} | +{ + type: \'a465\', + a47: number, +} | +{ + type: \'a466\', + a47: number, +} | +{ + type: \'a467\', + a47: number, +} | +{ + type: \'a468\', + a47: number, +} | +{ + type: \'a469\', + a47: number, +} | +{ + type: \'a470\', + a47: number, +} | +{ + type: \'a471\', + a48: number, +} | +{ + type: \'a472\', + a48: number, +} | +{ + type: \'a473\', + a48: number, +} | +{ + type: \'a474\', + a48: number, +} | +{ + type: \'a475\', + a48: number, +} | +{ + type: \'a476\', + a48: number, +} | +{ + type: \'a477\', + a48: number, +} | +{ + type: \'a478\', + a48: number, +} | +{ + type: \'a479\', + a48: number, +} | +{ + type: \'a480\', + a48: number, +} | +{ + type: \'a481\', + a49: number, +} | +{ + type: \'a482\', + a49: number, +} | +{ + type: \'a483\', + a49: number, +} | +{ + type: \'a484\', + a49: number, +} | +{ + type: \'a485\', + a49: number, +} | +{ + type: \'a486\', + a49: number, +} | +{ + type: \'a487\', + a49: number, +} | +{ + type: \'a488\', + a49: number, +} | +{ + type: \'a489\', + a49: number, +} | +{ + type: \'a490\', + a49: number, +} | +{ + type: \'a491\', + a50: number, +} | +{ + type: \'a492\', + a50: number, +} | +{ + type: \'a493\', + a50: number, +} | +{ + type: \'a494\', + a50: number, +} | +{ + type: \'a495\', + a50: number, +} | +{ + type: \'a496\', + a50: number, +} | +{ + type: \'a497\', + a50: number, +} | +{ + type: \'a498\', + a50: number, +} | +{ + type: \'a499\', + a50: number, +} | +{ + type: \'a500\', + a50: number, +} | +{ + type: \'a501\', + a51: number, +} | +{ + type: \'a502\', + a51: number, +} | +{ + type: \'a503\', + a51: number, +} | +{ + type: \'a504\', + a51: number, +} | +{ + type: \'a505\', + a51: number, +} | +{ + type: \'a506\', + a51: number, +} | +{ + type: \'a507\', + a51: number, +} | +{ + type: \'a508\', + a51: number, +} | +{ + type: \'a509\', + a51: number, +} | +{ + type: \'a510\', + a51: number, +} | +{ + type: \'a511\', + a52: number, +} | +{ + type: \'a512\', + a52: number, +} | +{ + type: \'a513\', + a52: number, +} | +{ + type: \'a514\', + a52: number, +} | +{ + type: \'a515\', + a52: number, +} | +{ + type: \'a516\', + a52: number, +} | +{ + type: \'a517\', + a52: number, +} | +{ + type: \'a518\', + a52: number, +} | +{ + type: \'a519\', + a52: number, +} | +{ + type: \'a520\', + a52: number, +} | +{ + type: \'a521\', + a53: number, +} | +{ + type: \'a522\', + a53: number, +} | +{ + type: \'a523\', + a53: number, +} | +{ + type: \'a524\', + a53: number, +} | +{ + type: \'a525\', + a53: number, +} | +{ + type: \'a526\', + a53: number, +} | +{ + type: \'a527\', + a53: number, +} | +{ + type: \'a528\', + a53: number, +} | +{ + type: \'a529\', + a53: number, +} | +{ + type: \'a530\', + a53: number, +} | +{ + type: \'a531\', + a54: number, +} | +{ + type: \'a532\', + a54: number, +} | +{ + type: \'a533\', + a54: number, +} | +{ + type: \'a534\', + a54: number, +} | +{ + type: \'a535\', + a54: number, +} | +{ + type: \'a536\', + a54: number, +} | +{ + type: \'a537\', + a54: number, +} | +{ + type: \'a538\', + a54: number, +} | +{ + type: \'a539\', + a54: number, +} | +{ + type: \'a540\', + a54: number, +} | +{ + type: \'a541\', + a55: number, +} | +{ + type: \'a542\', + a55: number, +} | +{ + type: \'a543\', + a55: number, +} | +{ + type: \'a544\', + a55: number, +} | +{ + type: \'a545\', + a55: number, +} | +{ + type: \'a546\', + a55: number, +} | +{ + type: \'a547\', + a55: number, +} | +{ + type: \'a548\', + a55: number, +} | +{ + type: \'a549\', + a55: number, +} | +{ + type: \'a550\', + a55: number, +} | +{ + type: \'a551\', + a56: number, +} | +{ + type: \'a552\', + a56: number, +} | +{ + type: \'a553\', + a56: number, +} | +{ + type: \'a554\', + a56: number, +} | +{ + type: \'a555\', + a56: number, +} | +{ + type: \'a556\', + a56: number, +} | +{ + type: \'a557\', + a56: number, +} | +{ + type: \'a558\', + a56: number, +} | +{ + type: \'a559\', + a56: number, +} | +{ + type: \'a560\', + a56: number, +} | +{ + type: \'a561\', + a57: number, +} | +{ + type: \'a562\', + a57: number, +} | +{ + type: \'a563\', + a57: number, +} | +{ + type: \'a564\', + a57: number, +} | +{ + type: \'a565\', + a57: number, +} | +{ + type: \'a566\', + a57: number, +} | +{ + type: \'a567\', + a57: number, +} | +{ + type: \'a568\', + a57: number, +} | +{ + type: \'a569\', + a57: number, +} | +{ + type: \'a570\', + a57: number, +} | +{ + type: \'a571\', + a58: number, +} | +{ + type: \'a572\', + a58: number, +} | +{ + type: \'a573\', + a58: number, +} | +{ + type: \'a574\', + a58: number, +} | +{ + type: \'a575\', + a58: number, +} | +{ + type: \'a576\', + a58: number, +} | +{ + type: \'a577\', + a58: number, +} | +{ + type: \'a578\', + a58: number, +} | +{ + type: \'a579\', + a58: number, +} | +{ + type: \'a580\', + a58: number, +} | +{ + type: \'a581\', + a59: number, +} | +{ + type: \'a582\', + a59: number, +} | +{ + type: \'a583\', + a59: number, +} | +{ + type: \'a584\', + a59: number, +} | +{ + type: \'a585\', + a59: number, +} | +{ + type: \'a586\', + a59: number, +} | +{ + type: \'a587\', + a59: number, +} | +{ + type: \'a588\', + a59: number, +} | +{ + type: \'a589\', + a59: number, +} | +{ + type: \'a590\', + a59: number, +} | +{ + type: \'a591\', + a60: number, +} | +{ + type: \'a592\', + a60: number, +} | +{ + type: \'a593\', + a60: number, +} | +{ + type: \'a594\', + a60: number, +} | +{ + type: \'a595\', + a60: number, +} | +{ + type: \'a596\', + a60: number, +} | +{ + type: \'a597\', + a60: number, +} | +{ + type: \'a598\', + a60: number, +} | +{ + type: \'a599\', + a60: number, +} | +{ + type: \'a600\', + a60: number, +} | +{ + type: \'a601\', + a61: number, +} | +{ + type: \'a602\', + a61: number, +} | +{ + type: \'a603\', + a61: number, +} | +{ + type: \'a604\', + a61: number, +} | +{ + type: \'a605\', + a61: number, +} | +{ + type: \'a606\', + a61: number, +} | +{ + type: \'a607\', + a61: number, +} | +{ + type: \'a608\', + a61: number, +} | +{ + type: \'a609\', + a61: number, +} | +{ + type: \'a610\', + a61: number, +} | +{ + type: \'a611\', + a62: number, +} | +{ + type: \'a612\', + a62: number, +} | +{ + type: \'a613\', + a62: number, +} | +{ + type: \'a614\', + a62: number, +} | +{ + type: \'a615\', + a62: number, +} | +{ + type: \'a616\', + a62: number, +} | +{ + type: \'a617\', + a62: number, +} | +{ + type: \'a618\', + a62: number, +} | +{ + type: \'a619\', + a62: number, +} | +{ + type: \'a620\', + a62: number, +} | +{ + type: \'a621\', + a63: number, +} | +{ + type: \'a622\', + a63: number, +} | +{ + type: \'a623\', + a63: number, +} | +{ + type: \'a624\', + a63: number, +} | +{ + type: \'a625\', + a63: number, +} | +{ + type: \'a626\', + a63: number, +} | +{ + type: \'a627\', + a63: number, +} | +{ + type: \'a628\', + a63: number, +} | +{ + type: \'a629\', + a63: number, +} | +{ + type: \'a630\', + a63: number, +} | +{ + type: \'a631\', + a64: number, +} | +{ + type: \'a632\', + a64: number, +} | +{ + type: \'a633\', + a64: number, +} | +{ + type: \'a634\', + a64: number, +} | +{ + type: \'a635\', + a64: number, +} | +{ + type: \'a636\', + a64: number, +} | +{ + type: \'a637\', + a64: number, +} | +{ + type: \'a638\', + a64: number, +} | +{ + type: \'a639\', + a64: number, +} | +{ + type: \'a640\', + a64: number, +} | +{ + type: \'a641\', + a65: number, +} | +{ + type: \'a642\', + a65: number, +} | +{ + type: \'a643\', + a65: number, +} | +{ + type: \'a644\', + a65: number, +} | +{ + type: \'a645\', + a65: number, +} | +{ + type: \'a646\', + a65: number, +} | +{ + type: \'a647\', + a65: number, +} | +{ + type: \'a648\', + a65: number, +} | +{ + type: \'a649\', + a65: number, +} | +{ + type: \'a650\', + a65: number, +} | +{ + type: \'a651\', + a66: number, +} | +{ + type: \'a652\', + a66: number, +} | +{ + type: \'a653\', + a66: number, +} | +{ + type: \'a654\', + a66: number, +} | +{ + type: \'a655\', + a66: number, +} | +{ + type: \'a656\', + a66: number, +} | +{ + type: \'a657\', + a66: number, +} | +{ + type: \'a658\', + a66: number, +} | +{ + type: \'a659\', + a66: number, +} | +{ + type: \'a660\', + a66: number, +} | +{ + type: \'a661\', + a67: number, +} | +{ + type: \'a662\', + a67: number, +} | +{ + type: \'a663\', + a67: number, +} | +{ + type: \'a664\', + a67: number, +} | +{ + type: \'a665\', + a67: number, +} | +{ + type: \'a666\', + a67: number, +} | +{ + type: \'a667\', + a67: number, +} | +{ + type: \'a668\', + a67: number, +} | +{ + type: \'a669\', + a67: number, +} | +{ + type: \'a670\', + a67: number, +} | +{ + type: \'a671\', + a68: number, +} | +{ + type: \'a672\', + a68: number, +} | +{ + type: \'a673\', + a68: number, +} | +{ + type: \'a674\', + a68: number, +} | +{ + type: \'a675\', + a68: number, +} | +{ + type: \'a676\', + a68: number, +} | +{ + type: \'a677\', + a68: number, +} | +{ + type: \'a678\', + a68: number, +} | +{ + type: \'a679\', + a68: number, +} | +{ + type: \'a680\', + a68: number, +} | +{ + type: \'a681\', + a69: number, +} | +{ + type: \'a682\', + a69: number, +} | +{ + type: \'a683\', + a69: number, +} | +{ + type: \'a684\', + a69: number, +} | +{ + type: \'a685\', + a69: number, +} | +{ + type: \'a686\', + a69: number, +} | +{ + type: \'a687\', + a69: number, +} | +{ + type: \'a688\', + a69: number, +} | +{ + type: \'a689\', + a69: number, +} | +{ + type: \'a690\', + a69: number, +} | +{ + type: \'a691\', + a70: number, +} | +{ + type: \'a692\', + a70: number, +} | +{ + type: \'a693\', + a70: number, +} | +{ + type: \'a694\', + a70: number, +} | +{ + type: \'a695\', + a70: number, +} | +{ + type: \'a696\', + a70: number, +} | +{ + type: \'a697\', + a70: number, +} | +{ + type: \'a698\', + a70: number, +} | +{ + type: \'a699\', + a70: number, +} | +{ + type: \'a700\', + a70: number, +} | +{ + type: \'a701\', + a71: number, +} | +{ + type: \'a702\', + a71: number, +} | +{ + type: \'a703\', + a71: number, +} | +{ + type: \'a704\', + a71: number, +} | +{ + type: \'a705\', + a71: number, +} | +{ + type: \'a706\', + a71: number, +} | +{ + type: \'a707\', + a71: number, +} | +{ + type: \'a708\', + a71: number, +} | +{ + type: \'a709\', + a71: number, +} | +{ + type: \'a710\', + a71: number, +} | +{ + type: \'a711\', + a72: number, +} | +{ + type: \'a712\', + a72: number, +} | +{ + type: \'a713\', + a72: number, +} | +{ + type: \'a714\', + a72: number, +} | +{ + type: \'a715\', + a72: number, +} | +{ + type: \'a716\', + a72: number, +} | +{ + type: \'a717\', + a72: number, +} | +{ + type: \'a718\', + a72: number, +} | +{ + type: \'a719\', + a72: number, +} | +{ + type: \'a720\', + a72: number, +} | +{ + type: \'a721\', + a73: number, +} | +{ + type: \'a722\', + a73: number, +} | +{ + type: \'a723\', + a73: number, +} | +{ + type: \'a724\', + a73: number, +} | +{ + type: \'a725\', + a73: number, +} | +{ + type: \'a726\', + a73: number, +} | +{ + type: \'a727\', + a73: number, +} | +{ + type: \'a728\', + a73: number, +} | +{ + type: \'a729\', + a73: number, +} | +{ + type: \'a730\', + a73: number, +} | +{ + type: \'a731\', + a74: number, +} | +{ + type: \'a732\', + a74: number, +} | +{ + type: \'a733\', + a74: number, +} | +{ + type: \'a734\', + a74: number, +} | +{ + type: \'a735\', + a74: number, +} | +{ + type: \'a736\', + a74: number, +} | +{ + type: \'a737\', + a74: number, +} | +{ + type: \'a738\', + a74: number, +} | +{ + type: \'a739\', + a74: number, +} | +{ + type: \'a740\', + a74: number, +} | +{ + type: \'a741\', + a75: number, +} | +{ + type: \'a742\', + a75: number, +} | +{ + type: \'a743\', + a75: number, +} | +{ + type: \'a744\', + a75: number, +} | +{ + type: \'a745\', + a75: number, +} | +{ + type: \'a746\', + a75: number, +} | +{ + type: \'a747\', + a75: number, +} | +{ + type: \'a748\', + a75: number, +} | +{ + type: \'a749\', + a75: number, +} | +{ + type: \'a750\', + a75: number, +} | +{ + type: \'a751\', + a76: number, +} | +{ + type: \'a752\', + a76: number, +} | +{ + type: \'a753\', + a76: number, +} | +{ + type: \'a754\', + a76: number, +} | +{ + type: \'a755\', + a76: number, +} | +{ + type: \'a756\', + a76: number, +} | +{ + type: \'a757\', + a76: number, +} | +{ + type: \'a758\', + a76: number, +} | +{ + type: \'a759\', + a76: number, +} | +{ + type: \'a760\', + a76: number, +} | +{ + type: \'a761\', + a77: number, +} | +{ + type: \'a762\', + a77: number, +} | +{ + type: \'a763\', + a77: number, +} | +{ + type: \'a764\', + a77: number, +} | +{ + type: \'a765\', + a77: number, +} | +{ + type: \'a766\', + a77: number, +} | +{ + type: \'a767\', + a77: number, +} | +{ + type: \'a768\', + a77: number, +} | +{ + type: \'a769\', + a77: number, +} | +{ + type: \'a770\', + a77: number, +} | +{ + type: \'a771\', + a78: number, +} | +{ + type: \'a772\', + a78: number, +} | +{ + type: \'a773\', + a78: number, +} | +{ + type: \'a774\', + a78: number, +} | +{ + type: \'a775\', + a78: number, +} | +{ + type: \'a776\', + a78: number, +} | +{ + type: \'a777\', + a78: number, +} | +{ + type: \'a778\', + a78: number, +} | +{ + type: \'a779\', + a78: number, +} | +{ + type: \'a780\', + a78: number, +} | +{ + type: \'a781\', + a79: number, +} | +{ + type: \'a782\', + a79: number, +} | +{ + type: \'a783\', + a79: number, +} | +{ + type: \'a784\', + a79: number, +} | +{ + type: \'a785\', + a79: number, +} | +{ + type: \'a786\', + a79: number, +} | +{ + type: \'a787\', + a79: number, +} | +{ + type: \'a788\', + a79: number, +} | +{ + type: \'a789\', + a79: number, +} | +{ + type: \'a790\', + a79: number, +} | +{ + type: \'a791\', + a80: number, +} | +{ + type: \'a792\', + a80: number, +} | +{ + type: \'a793\', + a80: number, +} | +{ + type: \'a794\', + a80: number, +} | +{ + type: \'a795\', + a80: number, +} | +{ + type: \'a796\', + a80: number, +} | +{ + type: \'a797\', + a80: number, +} | +{ + type: \'a798\', + a80: number, +} | +{ + type: \'a799\', + a80: number, +} | +{ + type: \'a800\', + a80: number, +} | +{ + type: \'a801\', + a81: number, +} | +{ + type: \'a802\', + a81: number, +} | +{ + type: \'a803\', + a81: number, +} | +{ + type: \'a804\', + a81: number, +} | +{ + type: \'a805\', + a81: number, +} | +{ + type: \'a806\', + a81: number, +} | +{ + type: \'a807\', + a81: number, +} | +{ + type: \'a808\', + a81: number, +} | +{ + type: \'a809\', + a81: number, +} | +{ + type: \'a810\', + a81: number, +} | +{ + type: \'a811\', + a82: number, +} | +{ + type: \'a812\', + a82: number, +} | +{ + type: \'a813\', + a82: number, +} | +{ + type: \'a814\', + a82: number, +} | +{ + type: \'a815\', + a82: number, +} | +{ + type: \'a816\', + a82: number, +} | +{ + type: \'a817\', + a82: number, +} | +{ + type: \'a818\', + a82: number, +} | +{ + type: \'a819\', + a82: number, +} | +{ + type: \'a820\', + a82: number, +} | +{ + type: \'a821\', + a83: number, +} | +{ + type: \'a822\', + a83: number, +} | +{ + type: \'a823\', + a83: number, +} | +{ + type: \'a824\', + a83: number, +} | +{ + type: \'a825\', + a83: number, +} | +{ + type: \'a826\', + a83: number, +} | +{ + type: \'a827\', + a83: number, +} | +{ + type: \'a828\', + a83: number, +} | +{ + type: \'a829\', + a83: number, +} | +{ + type: \'a830\', + a83: number, +} | +{ + type: \'a831\', + a84: number, +} | +{ + type: \'a832\', + a84: number, +} | +{ + type: \'a833\', + a84: number, +} | +{ + type: \'a834\', + a84: number, +} | +{ + type: \'a835\', + a84: number, +} | +{ + type: \'a836\', + a84: number, +} | +{ + type: \'a837\', + a84: number, +} | +{ + type: \'a838\', + a84: number, +} | +{ + type: \'a839\', + a84: number, +} | +{ + type: \'a840\', + a84: number, +} | +{ + type: \'a841\', + a85: number, +} | +{ + type: \'a842\', + a85: number, +} | +{ + type: \'a843\', + a85: number, +} | +{ + type: \'a844\', + a85: number, +} | +{ + type: \'a845\', + a85: number, +} | +{ + type: \'a846\', + a85: number, +} | +{ + type: \'a847\', + a85: number, +} | +{ + type: \'a848\', + a85: number, +} | +{ + type: \'a849\', + a85: number, +} | +{ + type: \'a850\', + a85: number, +} | +{ + type: \'a851\', + a86: number, +} | +{ + type: \'a852\', + a86: number, +} | +{ + type: \'a853\', + a86: number, +} | +{ + type: \'a854\', + a86: number, +} | +{ + type: \'a855\', + a86: number, +} | +{ + type: \'a856\', + a86: number, +} | +{ + type: \'a857\', + a86: number, +} | +{ + type: \'a858\', + a86: number, +} | +{ + type: \'a859\', + a86: number, +} | +{ + type: \'a860\', + a86: number, +} | +{ + type: \'a861\', + a87: number, +} | +{ + type: \'a862\', + a87: number, +} | +{ + type: \'a863\', + a87: number, +} | +{ + type: \'a864\', + a87: number, +} | +{ + type: \'a865\', + a87: number, +} | +{ + type: \'a866\', + a87: number, +} | +{ + type: \'a867\', + a87: number, +} | +{ + type: \'a868\', + a87: number, +} | +{ + type: \'a869\', + a87: number, +} | +{ + type: \'a870\', + a87: number, +} | +{ + type: \'a871\', + a88: number, +} | +{ + type: \'a872\', + a88: number, +} | +{ + type: \'a873\', + a88: number, +} | +{ + type: \'a874\', + a88: number, +} | +{ + type: \'a875\', + a88: number, +} | +{ + type: \'a876\', + a88: number, +} | +{ + type: \'a877\', + a88: number, +} | +{ + type: \'a878\', + a88: number, +} | +{ + type: \'a879\', + a88: number, +} | +{ + type: \'a880\', + a88: number, +} | +{ + type: \'a881\', + a89: number, +} | +{ + type: \'a882\', + a89: number, +} | +{ + type: \'a883\', + a89: number, +} | +{ + type: \'a884\', + a89: number, +} | +{ + type: \'a885\', + a89: number, +} | +{ + type: \'a886\', + a89: number, +} | +{ + type: \'a887\', + a89: number, +} | +{ + type: \'a888\', + a89: number, +} | +{ + type: \'a889\', + a89: number, +} | +{ + type: \'a890\', + a89: number, +} | +{ + type: \'a891\', + a90: number, +} | +{ + type: \'a892\', + a90: number, +} | +{ + type: \'a893\', + a90: number, +} | +{ + type: \'a894\', + a90: number, +} | +{ + type: \'a895\', + a90: number, +} | +{ + type: \'a896\', + a90: number, +} | +{ + type: \'a897\', + a90: number, +} | +{ + type: \'a898\', + a90: number, +} | +{ + type: \'a899\', + a90: number, +} | +{ + type: \'a900\', + a90: number, +} | +{ + type: \'a901\', + a91: number, +} | +{ + type: \'a902\', + a91: number, +} | +{ + type: \'a903\', + a91: number, +} | +{ + type: \'a904\', + a91: number, +} | +{ + type: \'a905\', + a91: number, +} | +{ + type: \'a906\', + a91: number, +} | +{ + type: \'a907\', + a91: number, +} | +{ + type: \'a908\', + a91: number, +} | +{ + type: \'a909\', + a91: number, +} | +{ + type: \'a910\', + a91: number, +} | +{ + type: \'a911\', + a92: number, +} | +{ + type: \'a912\', + a92: number, +} | +{ + type: \'a913\', + a92: number, +} | +{ + type: \'a914\', + a92: number, +} | +{ + type: \'a915\', + a92: number, +} | +{ + type: \'a916\', + a92: number, +} | +{ + type: \'a917\', + a92: number, +} | +{ + type: \'a918\', + a92: number, +} | +{ + type: \'a919\', + a92: number, +} | +{ + type: \'a920\', + a92: number, +} | +{ + type: \'a921\', + a93: number, +} | +{ + type: \'a922\', + a93: number, +} | +{ + type: \'a923\', + a93: number, +} | +{ + type: \'a924\', + a93: number, +} | +{ + type: \'a925\', + a93: number, +} | +{ + type: \'a926\', + a93: number, +} | +{ + type: \'a927\', + a93: number, +} | +{ + type: \'a928\', + a93: number, +} | +{ + type: \'a929\', + a93: number, +} | +{ + type: \'a930\', + a93: number, +} | +{ + type: \'a931\', + a94: number, +} | +{ + type: \'a932\', + a94: number, +} | +{ + type: \'a933\', + a94: number, +} | +{ + type: \'a934\', + a94: number, +} | +{ + type: \'a935\', + a94: number, +} | +{ + type: \'a936\', + a94: number, +} | +{ + type: \'a937\', + a94: number, +} | +{ + type: \'a938\', + a94: number, +} | +{ + type: \'a939\', + a94: number, +} | +{ + type: \'a940\', + a94: number, +} | +{ + type: \'a941\', + a95: number, +} | +{ + type: \'a942\', + a95: number, +} | +{ + type: \'a943\', + a95: number, +} | +{ + type: \'a944\', + a95: number, +} | +{ + type: \'a945\', + a95: number, +} | +{ + type: \'a946\', + a95: number, +} | +{ + type: \'a947\', + a95: number, +} | +{ + type: \'a948\', + a95: number, +} | +{ + type: \'a949\', + a95: number, +} | +{ + type: \'a950\', + a95: number, +} | +{ + type: \'a951\', + a96: number, +} | +{ + type: \'a952\', + a96: number, +} | +{ + type: \'a953\', + a96: number, +} | +{ + type: \'a954\', + a96: number, +} | +{ + type: \'a955\', + a96: number, +} | +{ + type: \'a956\', + a96: number, +} | +{ + type: \'a957\', + a96: number, +} | +{ + type: \'a958\', + a96: number, +} | +{ + type: \'a959\', + a96: number, +} | +{ + type: \'a960\', + a96: number, +} | +{ + type: \'a961\', + a97: number, +} | +{ + type: \'a962\', + a97: number, +} | +{ + type: \'a963\', + a97: number, +} | +{ + type: \'a964\', + a97: number, +} | +{ + type: \'a965\', + a97: number, +} | +{ + type: \'a966\', + a97: number, +} | +{ + type: \'a967\', + a97: number, +} | +{ + type: \'a968\', + a97: number, +} | +{ + type: \'a969\', + a97: number, +} | +{ + type: \'a970\', + a97: number, +} | +{ + type: \'a971\', + a98: number, +} | +{ + type: \'a972\', + a98: number, +} | +{ + type: \'a973\', + a98: number, +} | +{ + type: \'a974\', + a98: number, +} | +{ + type: \'a975\', + a98: number, +} | +{ + type: \'a976\', + a98: number, +} | +{ + type: \'a977\', + a98: number, +} | +{ + type: \'a978\', + a98: number, +} | +{ + type: \'a979\', + a98: number, +} | +{ + type: \'a980\', + a98: number, +} | +{ + type: \'a981\', + a99: number, +} | +{ + type: \'a982\', + a99: number, +} | +{ + type: \'a983\', + a99: number, +} | +{ + type: \'a984\', + a99: number, +} | +{ + type: \'a985\', + a99: number, +} | +{ + type: \'a986\', + a99: number, +} | +{ + type: \'a987\', + a99: number, +} | +{ + type: \'a988\', + a99: number, +} | +{ + type: \'a989\', + a99: number, +} | +{ + type: \'a990\', + a99: number, +} | +{ + type: \'a991\', + a100: number, +} | +{ + type: \'a992\', + a100: number, +} | +{ + type: \'a993\', + a100: number, +} | +{ + type: \'a994\', + a100: number, +} | +{ + type: \'a995\', + a100: number, +} | +{ + type: \'a996\', + a100: number, +} | +{ + type: \'a997\', + a100: number, +} | +{ + type: \'a998\', + a100: number, +} | +{ + type: \'a999\', + a100: number, +} | +{ + type: \'a1000\', + a100: number, +}; +function foo(x: TAction): TAction { return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"type A = {a: number}; +type B = {b: number}; +type C = {c: number}; + +type T1 = (A | B) & C; +function f1(x: T1): T1 { return x; } + +type T2 = (A & B) | C; +function f2(x: T2): T2 { return x; } + +type T3 = (A & C) | (B & C); +function f3(x: T3): T3 { return x; } + +type T4 = (A | C) & (B | C); +function f4(x: T4): T4 { return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1407:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/union-intersection/gen_big_disjoint_union.js b/tests/union-intersection/gen_big_disjoint_union.js new file mode 100644 index 000000000000..7dcc0b8126ad --- /dev/null +++ b/tests/union-intersection/gen_big_disjoint_union.js @@ -0,0 +1,4003 @@ +// perf test for big disjoint union with 1000 cases +type TAction = +{ + type: 'a1', + a1: number, +} | +{ + type: 'a2', + a1: number, +} | +{ + type: 'a3', + a1: number, +} | +{ + type: 'a4', + a1: number, +} | +{ + type: 'a5', + a1: number, +} | +{ + type: 'a6', + a1: number, +} | +{ + type: 'a7', + a1: number, +} | +{ + type: 'a8', + a1: number, +} | +{ + type: 'a9', + a1: number, +} | +{ + type: 'a10', + a1: number, +} | +{ + type: 'a11', + a2: number, +} | +{ + type: 'a12', + a2: number, +} | +{ + type: 'a13', + a2: number, +} | +{ + type: 'a14', + a2: number, +} | +{ + type: 'a15', + a2: number, +} | +{ + type: 'a16', + a2: number, +} | +{ + type: 'a17', + a2: number, +} | +{ + type: 'a18', + a2: number, +} | +{ + type: 'a19', + a2: number, +} | +{ + type: 'a20', + a2: number, +} | +{ + type: 'a21', + a3: number, +} | +{ + type: 'a22', + a3: number, +} | +{ + type: 'a23', + a3: number, +} | +{ + type: 'a24', + a3: number, +} | +{ + type: 'a25', + a3: number, +} | +{ + type: 'a26', + a3: number, +} | +{ + type: 'a27', + a3: number, +} | +{ + type: 'a28', + a3: number, +} | +{ + type: 'a29', + a3: number, +} | +{ + type: 'a30', + a3: number, +} | +{ + type: 'a31', + a4: number, +} | +{ + type: 'a32', + a4: number, +} | +{ + type: 'a33', + a4: number, +} | +{ + type: 'a34', + a4: number, +} | +{ + type: 'a35', + a4: number, +} | +{ + type: 'a36', + a4: number, +} | +{ + type: 'a37', + a4: number, +} | +{ + type: 'a38', + a4: number, +} | +{ + type: 'a39', + a4: number, +} | +{ + type: 'a40', + a4: number, +} | +{ + type: 'a41', + a5: number, +} | +{ + type: 'a42', + a5: number, +} | +{ + type: 'a43', + a5: number, +} | +{ + type: 'a44', + a5: number, +} | +{ + type: 'a45', + a5: number, +} | +{ + type: 'a46', + a5: number, +} | +{ + type: 'a47', + a5: number, +} | +{ + type: 'a48', + a5: number, +} | +{ + type: 'a49', + a5: number, +} | +{ + type: 'a50', + a5: number, +} | +{ + type: 'a51', + a6: number, +} | +{ + type: 'a52', + a6: number, +} | +{ + type: 'a53', + a6: number, +} | +{ + type: 'a54', + a6: number, +} | +{ + type: 'a55', + a6: number, +} | +{ + type: 'a56', + a6: number, +} | +{ + type: 'a57', + a6: number, +} | +{ + type: 'a58', + a6: number, +} | +{ + type: 'a59', + a6: number, +} | +{ + type: 'a60', + a6: number, +} | +{ + type: 'a61', + a7: number, +} | +{ + type: 'a62', + a7: number, +} | +{ + type: 'a63', + a7: number, +} | +{ + type: 'a64', + a7: number, +} | +{ + type: 'a65', + a7: number, +} | +{ + type: 'a66', + a7: number, +} | +{ + type: 'a67', + a7: number, +} | +{ + type: 'a68', + a7: number, +} | +{ + type: 'a69', + a7: number, +} | +{ + type: 'a70', + a7: number, +} | +{ + type: 'a71', + a8: number, +} | +{ + type: 'a72', + a8: number, +} | +{ + type: 'a73', + a8: number, +} | +{ + type: 'a74', + a8: number, +} | +{ + type: 'a75', + a8: number, +} | +{ + type: 'a76', + a8: number, +} | +{ + type: 'a77', + a8: number, +} | +{ + type: 'a78', + a8: number, +} | +{ + type: 'a79', + a8: number, +} | +{ + type: 'a80', + a8: number, +} | +{ + type: 'a81', + a9: number, +} | +{ + type: 'a82', + a9: number, +} | +{ + type: 'a83', + a9: number, +} | +{ + type: 'a84', + a9: number, +} | +{ + type: 'a85', + a9: number, +} | +{ + type: 'a86', + a9: number, +} | +{ + type: 'a87', + a9: number, +} | +{ + type: 'a88', + a9: number, +} | +{ + type: 'a89', + a9: number, +} | +{ + type: 'a90', + a9: number, +} | +{ + type: 'a91', + a10: number, +} | +{ + type: 'a92', + a10: number, +} | +{ + type: 'a93', + a10: number, +} | +{ + type: 'a94', + a10: number, +} | +{ + type: 'a95', + a10: number, +} | +{ + type: 'a96', + a10: number, +} | +{ + type: 'a97', + a10: number, +} | +{ + type: 'a98', + a10: number, +} | +{ + type: 'a99', + a10: number, +} | +{ + type: 'a100', + a10: number, +} | +{ + type: 'a101', + a11: number, +} | +{ + type: 'a102', + a11: number, +} | +{ + type: 'a103', + a11: number, +} | +{ + type: 'a104', + a11: number, +} | +{ + type: 'a105', + a11: number, +} | +{ + type: 'a106', + a11: number, +} | +{ + type: 'a107', + a11: number, +} | +{ + type: 'a108', + a11: number, +} | +{ + type: 'a109', + a11: number, +} | +{ + type: 'a110', + a11: number, +} | +{ + type: 'a111', + a12: number, +} | +{ + type: 'a112', + a12: number, +} | +{ + type: 'a113', + a12: number, +} | +{ + type: 'a114', + a12: number, +} | +{ + type: 'a115', + a12: number, +} | +{ + type: 'a116', + a12: number, +} | +{ + type: 'a117', + a12: number, +} | +{ + type: 'a118', + a12: number, +} | +{ + type: 'a119', + a12: number, +} | +{ + type: 'a120', + a12: number, +} | +{ + type: 'a121', + a13: number, +} | +{ + type: 'a122', + a13: number, +} | +{ + type: 'a123', + a13: number, +} | +{ + type: 'a124', + a13: number, +} | +{ + type: 'a125', + a13: number, +} | +{ + type: 'a126', + a13: number, +} | +{ + type: 'a127', + a13: number, +} | +{ + type: 'a128', + a13: number, +} | +{ + type: 'a129', + a13: number, +} | +{ + type: 'a130', + a13: number, +} | +{ + type: 'a131', + a14: number, +} | +{ + type: 'a132', + a14: number, +} | +{ + type: 'a133', + a14: number, +} | +{ + type: 'a134', + a14: number, +} | +{ + type: 'a135', + a14: number, +} | +{ + type: 'a136', + a14: number, +} | +{ + type: 'a137', + a14: number, +} | +{ + type: 'a138', + a14: number, +} | +{ + type: 'a139', + a14: number, +} | +{ + type: 'a140', + a14: number, +} | +{ + type: 'a141', + a15: number, +} | +{ + type: 'a142', + a15: number, +} | +{ + type: 'a143', + a15: number, +} | +{ + type: 'a144', + a15: number, +} | +{ + type: 'a145', + a15: number, +} | +{ + type: 'a146', + a15: number, +} | +{ + type: 'a147', + a15: number, +} | +{ + type: 'a148', + a15: number, +} | +{ + type: 'a149', + a15: number, +} | +{ + type: 'a150', + a15: number, +} | +{ + type: 'a151', + a16: number, +} | +{ + type: 'a152', + a16: number, +} | +{ + type: 'a153', + a16: number, +} | +{ + type: 'a154', + a16: number, +} | +{ + type: 'a155', + a16: number, +} | +{ + type: 'a156', + a16: number, +} | +{ + type: 'a157', + a16: number, +} | +{ + type: 'a158', + a16: number, +} | +{ + type: 'a159', + a16: number, +} | +{ + type: 'a160', + a16: number, +} | +{ + type: 'a161', + a17: number, +} | +{ + type: 'a162', + a17: number, +} | +{ + type: 'a163', + a17: number, +} | +{ + type: 'a164', + a17: number, +} | +{ + type: 'a165', + a17: number, +} | +{ + type: 'a166', + a17: number, +} | +{ + type: 'a167', + a17: number, +} | +{ + type: 'a168', + a17: number, +} | +{ + type: 'a169', + a17: number, +} | +{ + type: 'a170', + a17: number, +} | +{ + type: 'a171', + a18: number, +} | +{ + type: 'a172', + a18: number, +} | +{ + type: 'a173', + a18: number, +} | +{ + type: 'a174', + a18: number, +} | +{ + type: 'a175', + a18: number, +} | +{ + type: 'a176', + a18: number, +} | +{ + type: 'a177', + a18: number, +} | +{ + type: 'a178', + a18: number, +} | +{ + type: 'a179', + a18: number, +} | +{ + type: 'a180', + a18: number, +} | +{ + type: 'a181', + a19: number, +} | +{ + type: 'a182', + a19: number, +} | +{ + type: 'a183', + a19: number, +} | +{ + type: 'a184', + a19: number, +} | +{ + type: 'a185', + a19: number, +} | +{ + type: 'a186', + a19: number, +} | +{ + type: 'a187', + a19: number, +} | +{ + type: 'a188', + a19: number, +} | +{ + type: 'a189', + a19: number, +} | +{ + type: 'a190', + a19: number, +} | +{ + type: 'a191', + a20: number, +} | +{ + type: 'a192', + a20: number, +} | +{ + type: 'a193', + a20: number, +} | +{ + type: 'a194', + a20: number, +} | +{ + type: 'a195', + a20: number, +} | +{ + type: 'a196', + a20: number, +} | +{ + type: 'a197', + a20: number, +} | +{ + type: 'a198', + a20: number, +} | +{ + type: 'a199', + a20: number, +} | +{ + type: 'a200', + a20: number, +} | +{ + type: 'a201', + a21: number, +} | +{ + type: 'a202', + a21: number, +} | +{ + type: 'a203', + a21: number, +} | +{ + type: 'a204', + a21: number, +} | +{ + type: 'a205', + a21: number, +} | +{ + type: 'a206', + a21: number, +} | +{ + type: 'a207', + a21: number, +} | +{ + type: 'a208', + a21: number, +} | +{ + type: 'a209', + a21: number, +} | +{ + type: 'a210', + a21: number, +} | +{ + type: 'a211', + a22: number, +} | +{ + type: 'a212', + a22: number, +} | +{ + type: 'a213', + a22: number, +} | +{ + type: 'a214', + a22: number, +} | +{ + type: 'a215', + a22: number, +} | +{ + type: 'a216', + a22: number, +} | +{ + type: 'a217', + a22: number, +} | +{ + type: 'a218', + a22: number, +} | +{ + type: 'a219', + a22: number, +} | +{ + type: 'a220', + a22: number, +} | +{ + type: 'a221', + a23: number, +} | +{ + type: 'a222', + a23: number, +} | +{ + type: 'a223', + a23: number, +} | +{ + type: 'a224', + a23: number, +} | +{ + type: 'a225', + a23: number, +} | +{ + type: 'a226', + a23: number, +} | +{ + type: 'a227', + a23: number, +} | +{ + type: 'a228', + a23: number, +} | +{ + type: 'a229', + a23: number, +} | +{ + type: 'a230', + a23: number, +} | +{ + type: 'a231', + a24: number, +} | +{ + type: 'a232', + a24: number, +} | +{ + type: 'a233', + a24: number, +} | +{ + type: 'a234', + a24: number, +} | +{ + type: 'a235', + a24: number, +} | +{ + type: 'a236', + a24: number, +} | +{ + type: 'a237', + a24: number, +} | +{ + type: 'a238', + a24: number, +} | +{ + type: 'a239', + a24: number, +} | +{ + type: 'a240', + a24: number, +} | +{ + type: 'a241', + a25: number, +} | +{ + type: 'a242', + a25: number, +} | +{ + type: 'a243', + a25: number, +} | +{ + type: 'a244', + a25: number, +} | +{ + type: 'a245', + a25: number, +} | +{ + type: 'a246', + a25: number, +} | +{ + type: 'a247', + a25: number, +} | +{ + type: 'a248', + a25: number, +} | +{ + type: 'a249', + a25: number, +} | +{ + type: 'a250', + a25: number, +} | +{ + type: 'a251', + a26: number, +} | +{ + type: 'a252', + a26: number, +} | +{ + type: 'a253', + a26: number, +} | +{ + type: 'a254', + a26: number, +} | +{ + type: 'a255', + a26: number, +} | +{ + type: 'a256', + a26: number, +} | +{ + type: 'a257', + a26: number, +} | +{ + type: 'a258', + a26: number, +} | +{ + type: 'a259', + a26: number, +} | +{ + type: 'a260', + a26: number, +} | +{ + type: 'a261', + a27: number, +} | +{ + type: 'a262', + a27: number, +} | +{ + type: 'a263', + a27: number, +} | +{ + type: 'a264', + a27: number, +} | +{ + type: 'a265', + a27: number, +} | +{ + type: 'a266', + a27: number, +} | +{ + type: 'a267', + a27: number, +} | +{ + type: 'a268', + a27: number, +} | +{ + type: 'a269', + a27: number, +} | +{ + type: 'a270', + a27: number, +} | +{ + type: 'a271', + a28: number, +} | +{ + type: 'a272', + a28: number, +} | +{ + type: 'a273', + a28: number, +} | +{ + type: 'a274', + a28: number, +} | +{ + type: 'a275', + a28: number, +} | +{ + type: 'a276', + a28: number, +} | +{ + type: 'a277', + a28: number, +} | +{ + type: 'a278', + a28: number, +} | +{ + type: 'a279', + a28: number, +} | +{ + type: 'a280', + a28: number, +} | +{ + type: 'a281', + a29: number, +} | +{ + type: 'a282', + a29: number, +} | +{ + type: 'a283', + a29: number, +} | +{ + type: 'a284', + a29: number, +} | +{ + type: 'a285', + a29: number, +} | +{ + type: 'a286', + a29: number, +} | +{ + type: 'a287', + a29: number, +} | +{ + type: 'a288', + a29: number, +} | +{ + type: 'a289', + a29: number, +} | +{ + type: 'a290', + a29: number, +} | +{ + type: 'a291', + a30: number, +} | +{ + type: 'a292', + a30: number, +} | +{ + type: 'a293', + a30: number, +} | +{ + type: 'a294', + a30: number, +} | +{ + type: 'a295', + a30: number, +} | +{ + type: 'a296', + a30: number, +} | +{ + type: 'a297', + a30: number, +} | +{ + type: 'a298', + a30: number, +} | +{ + type: 'a299', + a30: number, +} | +{ + type: 'a300', + a30: number, +} | +{ + type: 'a301', + a31: number, +} | +{ + type: 'a302', + a31: number, +} | +{ + type: 'a303', + a31: number, +} | +{ + type: 'a304', + a31: number, +} | +{ + type: 'a305', + a31: number, +} | +{ + type: 'a306', + a31: number, +} | +{ + type: 'a307', + a31: number, +} | +{ + type: 'a308', + a31: number, +} | +{ + type: 'a309', + a31: number, +} | +{ + type: 'a310', + a31: number, +} | +{ + type: 'a311', + a32: number, +} | +{ + type: 'a312', + a32: number, +} | +{ + type: 'a313', + a32: number, +} | +{ + type: 'a314', + a32: number, +} | +{ + type: 'a315', + a32: number, +} | +{ + type: 'a316', + a32: number, +} | +{ + type: 'a317', + a32: number, +} | +{ + type: 'a318', + a32: number, +} | +{ + type: 'a319', + a32: number, +} | +{ + type: 'a320', + a32: number, +} | +{ + type: 'a321', + a33: number, +} | +{ + type: 'a322', + a33: number, +} | +{ + type: 'a323', + a33: number, +} | +{ + type: 'a324', + a33: number, +} | +{ + type: 'a325', + a33: number, +} | +{ + type: 'a326', + a33: number, +} | +{ + type: 'a327', + a33: number, +} | +{ + type: 'a328', + a33: number, +} | +{ + type: 'a329', + a33: number, +} | +{ + type: 'a330', + a33: number, +} | +{ + type: 'a331', + a34: number, +} | +{ + type: 'a332', + a34: number, +} | +{ + type: 'a333', + a34: number, +} | +{ + type: 'a334', + a34: number, +} | +{ + type: 'a335', + a34: number, +} | +{ + type: 'a336', + a34: number, +} | +{ + type: 'a337', + a34: number, +} | +{ + type: 'a338', + a34: number, +} | +{ + type: 'a339', + a34: number, +} | +{ + type: 'a340', + a34: number, +} | +{ + type: 'a341', + a35: number, +} | +{ + type: 'a342', + a35: number, +} | +{ + type: 'a343', + a35: number, +} | +{ + type: 'a344', + a35: number, +} | +{ + type: 'a345', + a35: number, +} | +{ + type: 'a346', + a35: number, +} | +{ + type: 'a347', + a35: number, +} | +{ + type: 'a348', + a35: number, +} | +{ + type: 'a349', + a35: number, +} | +{ + type: 'a350', + a35: number, +} | +{ + type: 'a351', + a36: number, +} | +{ + type: 'a352', + a36: number, +} | +{ + type: 'a353', + a36: number, +} | +{ + type: 'a354', + a36: number, +} | +{ + type: 'a355', + a36: number, +} | +{ + type: 'a356', + a36: number, +} | +{ + type: 'a357', + a36: number, +} | +{ + type: 'a358', + a36: number, +} | +{ + type: 'a359', + a36: number, +} | +{ + type: 'a360', + a36: number, +} | +{ + type: 'a361', + a37: number, +} | +{ + type: 'a362', + a37: number, +} | +{ + type: 'a363', + a37: number, +} | +{ + type: 'a364', + a37: number, +} | +{ + type: 'a365', + a37: number, +} | +{ + type: 'a366', + a37: number, +} | +{ + type: 'a367', + a37: number, +} | +{ + type: 'a368', + a37: number, +} | +{ + type: 'a369', + a37: number, +} | +{ + type: 'a370', + a37: number, +} | +{ + type: 'a371', + a38: number, +} | +{ + type: 'a372', + a38: number, +} | +{ + type: 'a373', + a38: number, +} | +{ + type: 'a374', + a38: number, +} | +{ + type: 'a375', + a38: number, +} | +{ + type: 'a376', + a38: number, +} | +{ + type: 'a377', + a38: number, +} | +{ + type: 'a378', + a38: number, +} | +{ + type: 'a379', + a38: number, +} | +{ + type: 'a380', + a38: number, +} | +{ + type: 'a381', + a39: number, +} | +{ + type: 'a382', + a39: number, +} | +{ + type: 'a383', + a39: number, +} | +{ + type: 'a384', + a39: number, +} | +{ + type: 'a385', + a39: number, +} | +{ + type: 'a386', + a39: number, +} | +{ + type: 'a387', + a39: number, +} | +{ + type: 'a388', + a39: number, +} | +{ + type: 'a389', + a39: number, +} | +{ + type: 'a390', + a39: number, +} | +{ + type: 'a391', + a40: number, +} | +{ + type: 'a392', + a40: number, +} | +{ + type: 'a393', + a40: number, +} | +{ + type: 'a394', + a40: number, +} | +{ + type: 'a395', + a40: number, +} | +{ + type: 'a396', + a40: number, +} | +{ + type: 'a397', + a40: number, +} | +{ + type: 'a398', + a40: number, +} | +{ + type: 'a399', + a40: number, +} | +{ + type: 'a400', + a40: number, +} | +{ + type: 'a401', + a41: number, +} | +{ + type: 'a402', + a41: number, +} | +{ + type: 'a403', + a41: number, +} | +{ + type: 'a404', + a41: number, +} | +{ + type: 'a405', + a41: number, +} | +{ + type: 'a406', + a41: number, +} | +{ + type: 'a407', + a41: number, +} | +{ + type: 'a408', + a41: number, +} | +{ + type: 'a409', + a41: number, +} | +{ + type: 'a410', + a41: number, +} | +{ + type: 'a411', + a42: number, +} | +{ + type: 'a412', + a42: number, +} | +{ + type: 'a413', + a42: number, +} | +{ + type: 'a414', + a42: number, +} | +{ + type: 'a415', + a42: number, +} | +{ + type: 'a416', + a42: number, +} | +{ + type: 'a417', + a42: number, +} | +{ + type: 'a418', + a42: number, +} | +{ + type: 'a419', + a42: number, +} | +{ + type: 'a420', + a42: number, +} | +{ + type: 'a421', + a43: number, +} | +{ + type: 'a422', + a43: number, +} | +{ + type: 'a423', + a43: number, +} | +{ + type: 'a424', + a43: number, +} | +{ + type: 'a425', + a43: number, +} | +{ + type: 'a426', + a43: number, +} | +{ + type: 'a427', + a43: number, +} | +{ + type: 'a428', + a43: number, +} | +{ + type: 'a429', + a43: number, +} | +{ + type: 'a430', + a43: number, +} | +{ + type: 'a431', + a44: number, +} | +{ + type: 'a432', + a44: number, +} | +{ + type: 'a433', + a44: number, +} | +{ + type: 'a434', + a44: number, +} | +{ + type: 'a435', + a44: number, +} | +{ + type: 'a436', + a44: number, +} | +{ + type: 'a437', + a44: number, +} | +{ + type: 'a438', + a44: number, +} | +{ + type: 'a439', + a44: number, +} | +{ + type: 'a440', + a44: number, +} | +{ + type: 'a441', + a45: number, +} | +{ + type: 'a442', + a45: number, +} | +{ + type: 'a443', + a45: number, +} | +{ + type: 'a444', + a45: number, +} | +{ + type: 'a445', + a45: number, +} | +{ + type: 'a446', + a45: number, +} | +{ + type: 'a447', + a45: number, +} | +{ + type: 'a448', + a45: number, +} | +{ + type: 'a449', + a45: number, +} | +{ + type: 'a450', + a45: number, +} | +{ + type: 'a451', + a46: number, +} | +{ + type: 'a452', + a46: number, +} | +{ + type: 'a453', + a46: number, +} | +{ + type: 'a454', + a46: number, +} | +{ + type: 'a455', + a46: number, +} | +{ + type: 'a456', + a46: number, +} | +{ + type: 'a457', + a46: number, +} | +{ + type: 'a458', + a46: number, +} | +{ + type: 'a459', + a46: number, +} | +{ + type: 'a460', + a46: number, +} | +{ + type: 'a461', + a47: number, +} | +{ + type: 'a462', + a47: number, +} | +{ + type: 'a463', + a47: number, +} | +{ + type: 'a464', + a47: number, +} | +{ + type: 'a465', + a47: number, +} | +{ + type: 'a466', + a47: number, +} | +{ + type: 'a467', + a47: number, +} | +{ + type: 'a468', + a47: number, +} | +{ + type: 'a469', + a47: number, +} | +{ + type: 'a470', + a47: number, +} | +{ + type: 'a471', + a48: number, +} | +{ + type: 'a472', + a48: number, +} | +{ + type: 'a473', + a48: number, +} | +{ + type: 'a474', + a48: number, +} | +{ + type: 'a475', + a48: number, +} | +{ + type: 'a476', + a48: number, +} | +{ + type: 'a477', + a48: number, +} | +{ + type: 'a478', + a48: number, +} | +{ + type: 'a479', + a48: number, +} | +{ + type: 'a480', + a48: number, +} | +{ + type: 'a481', + a49: number, +} | +{ + type: 'a482', + a49: number, +} | +{ + type: 'a483', + a49: number, +} | +{ + type: 'a484', + a49: number, +} | +{ + type: 'a485', + a49: number, +} | +{ + type: 'a486', + a49: number, +} | +{ + type: 'a487', + a49: number, +} | +{ + type: 'a488', + a49: number, +} | +{ + type: 'a489', + a49: number, +} | +{ + type: 'a490', + a49: number, +} | +{ + type: 'a491', + a50: number, +} | +{ + type: 'a492', + a50: number, +} | +{ + type: 'a493', + a50: number, +} | +{ + type: 'a494', + a50: number, +} | +{ + type: 'a495', + a50: number, +} | +{ + type: 'a496', + a50: number, +} | +{ + type: 'a497', + a50: number, +} | +{ + type: 'a498', + a50: number, +} | +{ + type: 'a499', + a50: number, +} | +{ + type: 'a500', + a50: number, +} | +{ + type: 'a501', + a51: number, +} | +{ + type: 'a502', + a51: number, +} | +{ + type: 'a503', + a51: number, +} | +{ + type: 'a504', + a51: number, +} | +{ + type: 'a505', + a51: number, +} | +{ + type: 'a506', + a51: number, +} | +{ + type: 'a507', + a51: number, +} | +{ + type: 'a508', + a51: number, +} | +{ + type: 'a509', + a51: number, +} | +{ + type: 'a510', + a51: number, +} | +{ + type: 'a511', + a52: number, +} | +{ + type: 'a512', + a52: number, +} | +{ + type: 'a513', + a52: number, +} | +{ + type: 'a514', + a52: number, +} | +{ + type: 'a515', + a52: number, +} | +{ + type: 'a516', + a52: number, +} | +{ + type: 'a517', + a52: number, +} | +{ + type: 'a518', + a52: number, +} | +{ + type: 'a519', + a52: number, +} | +{ + type: 'a520', + a52: number, +} | +{ + type: 'a521', + a53: number, +} | +{ + type: 'a522', + a53: number, +} | +{ + type: 'a523', + a53: number, +} | +{ + type: 'a524', + a53: number, +} | +{ + type: 'a525', + a53: number, +} | +{ + type: 'a526', + a53: number, +} | +{ + type: 'a527', + a53: number, +} | +{ + type: 'a528', + a53: number, +} | +{ + type: 'a529', + a53: number, +} | +{ + type: 'a530', + a53: number, +} | +{ + type: 'a531', + a54: number, +} | +{ + type: 'a532', + a54: number, +} | +{ + type: 'a533', + a54: number, +} | +{ + type: 'a534', + a54: number, +} | +{ + type: 'a535', + a54: number, +} | +{ + type: 'a536', + a54: number, +} | +{ + type: 'a537', + a54: number, +} | +{ + type: 'a538', + a54: number, +} | +{ + type: 'a539', + a54: number, +} | +{ + type: 'a540', + a54: number, +} | +{ + type: 'a541', + a55: number, +} | +{ + type: 'a542', + a55: number, +} | +{ + type: 'a543', + a55: number, +} | +{ + type: 'a544', + a55: number, +} | +{ + type: 'a545', + a55: number, +} | +{ + type: 'a546', + a55: number, +} | +{ + type: 'a547', + a55: number, +} | +{ + type: 'a548', + a55: number, +} | +{ + type: 'a549', + a55: number, +} | +{ + type: 'a550', + a55: number, +} | +{ + type: 'a551', + a56: number, +} | +{ + type: 'a552', + a56: number, +} | +{ + type: 'a553', + a56: number, +} | +{ + type: 'a554', + a56: number, +} | +{ + type: 'a555', + a56: number, +} | +{ + type: 'a556', + a56: number, +} | +{ + type: 'a557', + a56: number, +} | +{ + type: 'a558', + a56: number, +} | +{ + type: 'a559', + a56: number, +} | +{ + type: 'a560', + a56: number, +} | +{ + type: 'a561', + a57: number, +} | +{ + type: 'a562', + a57: number, +} | +{ + type: 'a563', + a57: number, +} | +{ + type: 'a564', + a57: number, +} | +{ + type: 'a565', + a57: number, +} | +{ + type: 'a566', + a57: number, +} | +{ + type: 'a567', + a57: number, +} | +{ + type: 'a568', + a57: number, +} | +{ + type: 'a569', + a57: number, +} | +{ + type: 'a570', + a57: number, +} | +{ + type: 'a571', + a58: number, +} | +{ + type: 'a572', + a58: number, +} | +{ + type: 'a573', + a58: number, +} | +{ + type: 'a574', + a58: number, +} | +{ + type: 'a575', + a58: number, +} | +{ + type: 'a576', + a58: number, +} | +{ + type: 'a577', + a58: number, +} | +{ + type: 'a578', + a58: number, +} | +{ + type: 'a579', + a58: number, +} | +{ + type: 'a580', + a58: number, +} | +{ + type: 'a581', + a59: number, +} | +{ + type: 'a582', + a59: number, +} | +{ + type: 'a583', + a59: number, +} | +{ + type: 'a584', + a59: number, +} | +{ + type: 'a585', + a59: number, +} | +{ + type: 'a586', + a59: number, +} | +{ + type: 'a587', + a59: number, +} | +{ + type: 'a588', + a59: number, +} | +{ + type: 'a589', + a59: number, +} | +{ + type: 'a590', + a59: number, +} | +{ + type: 'a591', + a60: number, +} | +{ + type: 'a592', + a60: number, +} | +{ + type: 'a593', + a60: number, +} | +{ + type: 'a594', + a60: number, +} | +{ + type: 'a595', + a60: number, +} | +{ + type: 'a596', + a60: number, +} | +{ + type: 'a597', + a60: number, +} | +{ + type: 'a598', + a60: number, +} | +{ + type: 'a599', + a60: number, +} | +{ + type: 'a600', + a60: number, +} | +{ + type: 'a601', + a61: number, +} | +{ + type: 'a602', + a61: number, +} | +{ + type: 'a603', + a61: number, +} | +{ + type: 'a604', + a61: number, +} | +{ + type: 'a605', + a61: number, +} | +{ + type: 'a606', + a61: number, +} | +{ + type: 'a607', + a61: number, +} | +{ + type: 'a608', + a61: number, +} | +{ + type: 'a609', + a61: number, +} | +{ + type: 'a610', + a61: number, +} | +{ + type: 'a611', + a62: number, +} | +{ + type: 'a612', + a62: number, +} | +{ + type: 'a613', + a62: number, +} | +{ + type: 'a614', + a62: number, +} | +{ + type: 'a615', + a62: number, +} | +{ + type: 'a616', + a62: number, +} | +{ + type: 'a617', + a62: number, +} | +{ + type: 'a618', + a62: number, +} | +{ + type: 'a619', + a62: number, +} | +{ + type: 'a620', + a62: number, +} | +{ + type: 'a621', + a63: number, +} | +{ + type: 'a622', + a63: number, +} | +{ + type: 'a623', + a63: number, +} | +{ + type: 'a624', + a63: number, +} | +{ + type: 'a625', + a63: number, +} | +{ + type: 'a626', + a63: number, +} | +{ + type: 'a627', + a63: number, +} | +{ + type: 'a628', + a63: number, +} | +{ + type: 'a629', + a63: number, +} | +{ + type: 'a630', + a63: number, +} | +{ + type: 'a631', + a64: number, +} | +{ + type: 'a632', + a64: number, +} | +{ + type: 'a633', + a64: number, +} | +{ + type: 'a634', + a64: number, +} | +{ + type: 'a635', + a64: number, +} | +{ + type: 'a636', + a64: number, +} | +{ + type: 'a637', + a64: number, +} | +{ + type: 'a638', + a64: number, +} | +{ + type: 'a639', + a64: number, +} | +{ + type: 'a640', + a64: number, +} | +{ + type: 'a641', + a65: number, +} | +{ + type: 'a642', + a65: number, +} | +{ + type: 'a643', + a65: number, +} | +{ + type: 'a644', + a65: number, +} | +{ + type: 'a645', + a65: number, +} | +{ + type: 'a646', + a65: number, +} | +{ + type: 'a647', + a65: number, +} | +{ + type: 'a648', + a65: number, +} | +{ + type: 'a649', + a65: number, +} | +{ + type: 'a650', + a65: number, +} | +{ + type: 'a651', + a66: number, +} | +{ + type: 'a652', + a66: number, +} | +{ + type: 'a653', + a66: number, +} | +{ + type: 'a654', + a66: number, +} | +{ + type: 'a655', + a66: number, +} | +{ + type: 'a656', + a66: number, +} | +{ + type: 'a657', + a66: number, +} | +{ + type: 'a658', + a66: number, +} | +{ + type: 'a659', + a66: number, +} | +{ + type: 'a660', + a66: number, +} | +{ + type: 'a661', + a67: number, +} | +{ + type: 'a662', + a67: number, +} | +{ + type: 'a663', + a67: number, +} | +{ + type: 'a664', + a67: number, +} | +{ + type: 'a665', + a67: number, +} | +{ + type: 'a666', + a67: number, +} | +{ + type: 'a667', + a67: number, +} | +{ + type: 'a668', + a67: number, +} | +{ + type: 'a669', + a67: number, +} | +{ + type: 'a670', + a67: number, +} | +{ + type: 'a671', + a68: number, +} | +{ + type: 'a672', + a68: number, +} | +{ + type: 'a673', + a68: number, +} | +{ + type: 'a674', + a68: number, +} | +{ + type: 'a675', + a68: number, +} | +{ + type: 'a676', + a68: number, +} | +{ + type: 'a677', + a68: number, +} | +{ + type: 'a678', + a68: number, +} | +{ + type: 'a679', + a68: number, +} | +{ + type: 'a680', + a68: number, +} | +{ + type: 'a681', + a69: number, +} | +{ + type: 'a682', + a69: number, +} | +{ + type: 'a683', + a69: number, +} | +{ + type: 'a684', + a69: number, +} | +{ + type: 'a685', + a69: number, +} | +{ + type: 'a686', + a69: number, +} | +{ + type: 'a687', + a69: number, +} | +{ + type: 'a688', + a69: number, +} | +{ + type: 'a689', + a69: number, +} | +{ + type: 'a690', + a69: number, +} | +{ + type: 'a691', + a70: number, +} | +{ + type: 'a692', + a70: number, +} | +{ + type: 'a693', + a70: number, +} | +{ + type: 'a694', + a70: number, +} | +{ + type: 'a695', + a70: number, +} | +{ + type: 'a696', + a70: number, +} | +{ + type: 'a697', + a70: number, +} | +{ + type: 'a698', + a70: number, +} | +{ + type: 'a699', + a70: number, +} | +{ + type: 'a700', + a70: number, +} | +{ + type: 'a701', + a71: number, +} | +{ + type: 'a702', + a71: number, +} | +{ + type: 'a703', + a71: number, +} | +{ + type: 'a704', + a71: number, +} | +{ + type: 'a705', + a71: number, +} | +{ + type: 'a706', + a71: number, +} | +{ + type: 'a707', + a71: number, +} | +{ + type: 'a708', + a71: number, +} | +{ + type: 'a709', + a71: number, +} | +{ + type: 'a710', + a71: number, +} | +{ + type: 'a711', + a72: number, +} | +{ + type: 'a712', + a72: number, +} | +{ + type: 'a713', + a72: number, +} | +{ + type: 'a714', + a72: number, +} | +{ + type: 'a715', + a72: number, +} | +{ + type: 'a716', + a72: number, +} | +{ + type: 'a717', + a72: number, +} | +{ + type: 'a718', + a72: number, +} | +{ + type: 'a719', + a72: number, +} | +{ + type: 'a720', + a72: number, +} | +{ + type: 'a721', + a73: number, +} | +{ + type: 'a722', + a73: number, +} | +{ + type: 'a723', + a73: number, +} | +{ + type: 'a724', + a73: number, +} | +{ + type: 'a725', + a73: number, +} | +{ + type: 'a726', + a73: number, +} | +{ + type: 'a727', + a73: number, +} | +{ + type: 'a728', + a73: number, +} | +{ + type: 'a729', + a73: number, +} | +{ + type: 'a730', + a73: number, +} | +{ + type: 'a731', + a74: number, +} | +{ + type: 'a732', + a74: number, +} | +{ + type: 'a733', + a74: number, +} | +{ + type: 'a734', + a74: number, +} | +{ + type: 'a735', + a74: number, +} | +{ + type: 'a736', + a74: number, +} | +{ + type: 'a737', + a74: number, +} | +{ + type: 'a738', + a74: number, +} | +{ + type: 'a739', + a74: number, +} | +{ + type: 'a740', + a74: number, +} | +{ + type: 'a741', + a75: number, +} | +{ + type: 'a742', + a75: number, +} | +{ + type: 'a743', + a75: number, +} | +{ + type: 'a744', + a75: number, +} | +{ + type: 'a745', + a75: number, +} | +{ + type: 'a746', + a75: number, +} | +{ + type: 'a747', + a75: number, +} | +{ + type: 'a748', + a75: number, +} | +{ + type: 'a749', + a75: number, +} | +{ + type: 'a750', + a75: number, +} | +{ + type: 'a751', + a76: number, +} | +{ + type: 'a752', + a76: number, +} | +{ + type: 'a753', + a76: number, +} | +{ + type: 'a754', + a76: number, +} | +{ + type: 'a755', + a76: number, +} | +{ + type: 'a756', + a76: number, +} | +{ + type: 'a757', + a76: number, +} | +{ + type: 'a758', + a76: number, +} | +{ + type: 'a759', + a76: number, +} | +{ + type: 'a760', + a76: number, +} | +{ + type: 'a761', + a77: number, +} | +{ + type: 'a762', + a77: number, +} | +{ + type: 'a763', + a77: number, +} | +{ + type: 'a764', + a77: number, +} | +{ + type: 'a765', + a77: number, +} | +{ + type: 'a766', + a77: number, +} | +{ + type: 'a767', + a77: number, +} | +{ + type: 'a768', + a77: number, +} | +{ + type: 'a769', + a77: number, +} | +{ + type: 'a770', + a77: number, +} | +{ + type: 'a771', + a78: number, +} | +{ + type: 'a772', + a78: number, +} | +{ + type: 'a773', + a78: number, +} | +{ + type: 'a774', + a78: number, +} | +{ + type: 'a775', + a78: number, +} | +{ + type: 'a776', + a78: number, +} | +{ + type: 'a777', + a78: number, +} | +{ + type: 'a778', + a78: number, +} | +{ + type: 'a779', + a78: number, +} | +{ + type: 'a780', + a78: number, +} | +{ + type: 'a781', + a79: number, +} | +{ + type: 'a782', + a79: number, +} | +{ + type: 'a783', + a79: number, +} | +{ + type: 'a784', + a79: number, +} | +{ + type: 'a785', + a79: number, +} | +{ + type: 'a786', + a79: number, +} | +{ + type: 'a787', + a79: number, +} | +{ + type: 'a788', + a79: number, +} | +{ + type: 'a789', + a79: number, +} | +{ + type: 'a790', + a79: number, +} | +{ + type: 'a791', + a80: number, +} | +{ + type: 'a792', + a80: number, +} | +{ + type: 'a793', + a80: number, +} | +{ + type: 'a794', + a80: number, +} | +{ + type: 'a795', + a80: number, +} | +{ + type: 'a796', + a80: number, +} | +{ + type: 'a797', + a80: number, +} | +{ + type: 'a798', + a80: number, +} | +{ + type: 'a799', + a80: number, +} | +{ + type: 'a800', + a80: number, +} | +{ + type: 'a801', + a81: number, +} | +{ + type: 'a802', + a81: number, +} | +{ + type: 'a803', + a81: number, +} | +{ + type: 'a804', + a81: number, +} | +{ + type: 'a805', + a81: number, +} | +{ + type: 'a806', + a81: number, +} | +{ + type: 'a807', + a81: number, +} | +{ + type: 'a808', + a81: number, +} | +{ + type: 'a809', + a81: number, +} | +{ + type: 'a810', + a81: number, +} | +{ + type: 'a811', + a82: number, +} | +{ + type: 'a812', + a82: number, +} | +{ + type: 'a813', + a82: number, +} | +{ + type: 'a814', + a82: number, +} | +{ + type: 'a815', + a82: number, +} | +{ + type: 'a816', + a82: number, +} | +{ + type: 'a817', + a82: number, +} | +{ + type: 'a818', + a82: number, +} | +{ + type: 'a819', + a82: number, +} | +{ + type: 'a820', + a82: number, +} | +{ + type: 'a821', + a83: number, +} | +{ + type: 'a822', + a83: number, +} | +{ + type: 'a823', + a83: number, +} | +{ + type: 'a824', + a83: number, +} | +{ + type: 'a825', + a83: number, +} | +{ + type: 'a826', + a83: number, +} | +{ + type: 'a827', + a83: number, +} | +{ + type: 'a828', + a83: number, +} | +{ + type: 'a829', + a83: number, +} | +{ + type: 'a830', + a83: number, +} | +{ + type: 'a831', + a84: number, +} | +{ + type: 'a832', + a84: number, +} | +{ + type: 'a833', + a84: number, +} | +{ + type: 'a834', + a84: number, +} | +{ + type: 'a835', + a84: number, +} | +{ + type: 'a836', + a84: number, +} | +{ + type: 'a837', + a84: number, +} | +{ + type: 'a838', + a84: number, +} | +{ + type: 'a839', + a84: number, +} | +{ + type: 'a840', + a84: number, +} | +{ + type: 'a841', + a85: number, +} | +{ + type: 'a842', + a85: number, +} | +{ + type: 'a843', + a85: number, +} | +{ + type: 'a844', + a85: number, +} | +{ + type: 'a845', + a85: number, +} | +{ + type: 'a846', + a85: number, +} | +{ + type: 'a847', + a85: number, +} | +{ + type: 'a848', + a85: number, +} | +{ + type: 'a849', + a85: number, +} | +{ + type: 'a850', + a85: number, +} | +{ + type: 'a851', + a86: number, +} | +{ + type: 'a852', + a86: number, +} | +{ + type: 'a853', + a86: number, +} | +{ + type: 'a854', + a86: number, +} | +{ + type: 'a855', + a86: number, +} | +{ + type: 'a856', + a86: number, +} | +{ + type: 'a857', + a86: number, +} | +{ + type: 'a858', + a86: number, +} | +{ + type: 'a859', + a86: number, +} | +{ + type: 'a860', + a86: number, +} | +{ + type: 'a861', + a87: number, +} | +{ + type: 'a862', + a87: number, +} | +{ + type: 'a863', + a87: number, +} | +{ + type: 'a864', + a87: number, +} | +{ + type: 'a865', + a87: number, +} | +{ + type: 'a866', + a87: number, +} | +{ + type: 'a867', + a87: number, +} | +{ + type: 'a868', + a87: number, +} | +{ + type: 'a869', + a87: number, +} | +{ + type: 'a870', + a87: number, +} | +{ + type: 'a871', + a88: number, +} | +{ + type: 'a872', + a88: number, +} | +{ + type: 'a873', + a88: number, +} | +{ + type: 'a874', + a88: number, +} | +{ + type: 'a875', + a88: number, +} | +{ + type: 'a876', + a88: number, +} | +{ + type: 'a877', + a88: number, +} | +{ + type: 'a878', + a88: number, +} | +{ + type: 'a879', + a88: number, +} | +{ + type: 'a880', + a88: number, +} | +{ + type: 'a881', + a89: number, +} | +{ + type: 'a882', + a89: number, +} | +{ + type: 'a883', + a89: number, +} | +{ + type: 'a884', + a89: number, +} | +{ + type: 'a885', + a89: number, +} | +{ + type: 'a886', + a89: number, +} | +{ + type: 'a887', + a89: number, +} | +{ + type: 'a888', + a89: number, +} | +{ + type: 'a889', + a89: number, +} | +{ + type: 'a890', + a89: number, +} | +{ + type: 'a891', + a90: number, +} | +{ + type: 'a892', + a90: number, +} | +{ + type: 'a893', + a90: number, +} | +{ + type: 'a894', + a90: number, +} | +{ + type: 'a895', + a90: number, +} | +{ + type: 'a896', + a90: number, +} | +{ + type: 'a897', + a90: number, +} | +{ + type: 'a898', + a90: number, +} | +{ + type: 'a899', + a90: number, +} | +{ + type: 'a900', + a90: number, +} | +{ + type: 'a901', + a91: number, +} | +{ + type: 'a902', + a91: number, +} | +{ + type: 'a903', + a91: number, +} | +{ + type: 'a904', + a91: number, +} | +{ + type: 'a905', + a91: number, +} | +{ + type: 'a906', + a91: number, +} | +{ + type: 'a907', + a91: number, +} | +{ + type: 'a908', + a91: number, +} | +{ + type: 'a909', + a91: number, +} | +{ + type: 'a910', + a91: number, +} | +{ + type: 'a911', + a92: number, +} | +{ + type: 'a912', + a92: number, +} | +{ + type: 'a913', + a92: number, +} | +{ + type: 'a914', + a92: number, +} | +{ + type: 'a915', + a92: number, +} | +{ + type: 'a916', + a92: number, +} | +{ + type: 'a917', + a92: number, +} | +{ + type: 'a918', + a92: number, +} | +{ + type: 'a919', + a92: number, +} | +{ + type: 'a920', + a92: number, +} | +{ + type: 'a921', + a93: number, +} | +{ + type: 'a922', + a93: number, +} | +{ + type: 'a923', + a93: number, +} | +{ + type: 'a924', + a93: number, +} | +{ + type: 'a925', + a93: number, +} | +{ + type: 'a926', + a93: number, +} | +{ + type: 'a927', + a93: number, +} | +{ + type: 'a928', + a93: number, +} | +{ + type: 'a929', + a93: number, +} | +{ + type: 'a930', + a93: number, +} | +{ + type: 'a931', + a94: number, +} | +{ + type: 'a932', + a94: number, +} | +{ + type: 'a933', + a94: number, +} | +{ + type: 'a934', + a94: number, +} | +{ + type: 'a935', + a94: number, +} | +{ + type: 'a936', + a94: number, +} | +{ + type: 'a937', + a94: number, +} | +{ + type: 'a938', + a94: number, +} | +{ + type: 'a939', + a94: number, +} | +{ + type: 'a940', + a94: number, +} | +{ + type: 'a941', + a95: number, +} | +{ + type: 'a942', + a95: number, +} | +{ + type: 'a943', + a95: number, +} | +{ + type: 'a944', + a95: number, +} | +{ + type: 'a945', + a95: number, +} | +{ + type: 'a946', + a95: number, +} | +{ + type: 'a947', + a95: number, +} | +{ + type: 'a948', + a95: number, +} | +{ + type: 'a949', + a95: number, +} | +{ + type: 'a950', + a95: number, +} | +{ + type: 'a951', + a96: number, +} | +{ + type: 'a952', + a96: number, +} | +{ + type: 'a953', + a96: number, +} | +{ + type: 'a954', + a96: number, +} | +{ + type: 'a955', + a96: number, +} | +{ + type: 'a956', + a96: number, +} | +{ + type: 'a957', + a96: number, +} | +{ + type: 'a958', + a96: number, +} | +{ + type: 'a959', + a96: number, +} | +{ + type: 'a960', + a96: number, +} | +{ + type: 'a961', + a97: number, +} | +{ + type: 'a962', + a97: number, +} | +{ + type: 'a963', + a97: number, +} | +{ + type: 'a964', + a97: number, +} | +{ + type: 'a965', + a97: number, +} | +{ + type: 'a966', + a97: number, +} | +{ + type: 'a967', + a97: number, +} | +{ + type: 'a968', + a97: number, +} | +{ + type: 'a969', + a97: number, +} | +{ + type: 'a970', + a97: number, +} | +{ + type: 'a971', + a98: number, +} | +{ + type: 'a972', + a98: number, +} | +{ + type: 'a973', + a98: number, +} | +{ + type: 'a974', + a98: number, +} | +{ + type: 'a975', + a98: number, +} | +{ + type: 'a976', + a98: number, +} | +{ + type: 'a977', + a98: number, +} | +{ + type: 'a978', + a98: number, +} | +{ + type: 'a979', + a98: number, +} | +{ + type: 'a980', + a98: number, +} | +{ + type: 'a981', + a99: number, +} | +{ + type: 'a982', + a99: number, +} | +{ + type: 'a983', + a99: number, +} | +{ + type: 'a984', + a99: number, +} | +{ + type: 'a985', + a99: number, +} | +{ + type: 'a986', + a99: number, +} | +{ + type: 'a987', + a99: number, +} | +{ + type: 'a988', + a99: number, +} | +{ + type: 'a989', + a99: number, +} | +{ + type: 'a990', + a99: number, +} | +{ + type: 'a991', + a100: number, +} | +{ + type: 'a992', + a100: number, +} | +{ + type: 'a993', + a100: number, +} | +{ + type: 'a994', + a100: number, +} | +{ + type: 'a995', + a100: number, +} | +{ + type: 'a996', + a100: number, +} | +{ + type: 'a997', + a100: number, +} | +{ + type: 'a998', + a100: number, +} | +{ + type: 'a999', + a100: number, +} | +{ + type: 'a1000', + a100: number, +}; +function foo(x: TAction): TAction { return x; } diff --git a/tests/union-intersection/jsfmt.spec.js b/tests/union-intersection/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/union-intersection/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/union-intersection/test.js b/tests/union-intersection/test.js new file mode 100644 index 000000000000..83655a3be56d --- /dev/null +++ b/tests/union-intersection/test.js @@ -0,0 +1,15 @@ +type A = {a: number}; +type B = {b: number}; +type C = {c: number}; + +type T1 = (A | B) & C; +function f1(x: T1): T1 { return x; } + +type T2 = (A & B) | C; +function f2(x: T2): T2 { return x; } + +type T3 = (A & C) | (B & C); +function f3(x: T3): T3 { return x; } + +type T4 = (A | C) & (B | C); +function f4(x: T4): T4 { return x; } diff --git a/tests/union/__snapshots__/jsfmt.spec.js.snap b/tests/union/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..11f75a60dcfe --- /dev/null +++ b/tests/union/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,5533 @@ +exports[`test fields.js 1`] = ` +"class C { + x: ?number|string; + constructor() { + this.x = null; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test fields2.js 1`] = ` +"class C { } + +class D { + content: string|C; + copyContent(content: C): string|C { + this.content = content; + return this.content; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-17.js 1`] = ` +"/* @flow */ + +type T = + {type: \"a\"; a: number} | + {type: \"b\"; b: string}; + +var l: Array = [ + {type: \"a\", a: 1}, + {type: \"a\", a: 2}, + {type: \"a\", a: 3}, + {type: \"a\", a: 4}, + {type: \"b\", b: \"monkey\"}, + {type: \"b\", b: \"gorilla\"}, + {type: \"b\", b: \"giraffe\"}, + {type: \"b\", b: \"penguin\"}, +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-198.js 1`] = ` +"var p = new Promise(function(resolve, reject) { + resolve(5); +}) + .then(function(num) { + return num.toFixed(); + }) + .then(function(str) { + // This should fail because str is string, not number + return str.toFixed(); + }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var p = new Promise( + function(resolve, reject) { + resolve(5); + } +).then( + function(num) { + return num.toFixed(); + } +).then( + function(str) { + // This should fail because str is string, not number + return str.toFixed(); + } +); + +" +`; + +exports[`test issue-256.js 1`] = ` +"declare class Myclass { + myfun(myarray: Array): any; +} +declare var myclass: Myclass; + +myclass.myfun([\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", function (ar) {}]) +myclass.myfun([\"1\", \"2\", \"3\", \"4\", \"5\", \"6\", \"7\", function (ar) {}]) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-323.js 1`] = ` +"var Foo = require(\"./issue-323-lib\"); +var foo = new Foo(); +var foostr: Foo | string = foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-323-lib.js 1`] = ` +"/* @flow */ +class Foo {} +module.exports = Foo; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +class Foo {} +module.exports = Foo; + +" +`; + +exports[`test issue-324.js 1`] = ` +"/* @flow */ +class Foo{}; +class Bar{}; + +var foostr: Foo | string = new Foo(); +var barstr: Bar | string = new Bar(); + +foostr = barstr; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-325.js 1`] = ` +"class Tag { + constructor() { + var a1: Array = []; + var a2: Array = a1; + } +} + +type Node = Tag_ | string; +class Tag_ { + constructor() { + var a1: Array = [new Tag_]; + var a2: Array = a1; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-326.js 1`] = ` +"var numberAndStringArr:Array = [1,2]; +var stringArr:Array = [\'a\',\'b\']; + +var result = numberAndStringArr.concat(stringArr); // no error +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-582.js 1`] = ` +"/*** + * nested unions + * @flow + */ + +// inline +var nested1: (\'foo\' | \'bar\') | \'baz\' = \'baz\'; + +// through tvars +type FooBar = \'foo\' | \'bar\'; +type Baz = \'baz\'; +type FooBarBaz = FooBar | Baz; + +var nested2: FooBarBaz = \'baz\'; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-963.js 1`] = ` +"/*** + * unions with embedded intersections + * @flow + */ + +type t1 = { + p1 : number +}; + +type t2 = { + p2: number +} + +type t3 = { + p3 : number +} + +type intersected = t1 & t2; +type union = intersected | t3; +type union2 = t3 | intersected; + +const u1 : union = { + p3 : 3 +}; + +const u2 : union = { + p1 : 1, + p2 : 2 +}; + +const u3 : union2 = { + p1 : 1, + p2 : 2 +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test.js 1`] = ` +"var C = require(\'test-lib\'); + +// TODO: spurious error! (replacing C with number makes the error go away) +// type Foo = Array | Array; +type Foo = Array; // workaround +var x:Array = []; +var y:Array = []; +function foo(x:Foo) {} +foo(x); +foo(y); + +// TODO: spurious error! (replacing C with number makes the error go away) +// type Bar = (() => C) | (() => string); +type Bar = () => (C | string); // workaround + +function f() { return \"\"; } +function bar(x:Bar) { } +bar(f); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test-lib.js 1`] = ` +"/* @providesModule test-lib */ + +class C { } +module.exports = C; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule test-lib */ +class C {} +module.exports = C; + +" +`; + +exports[`test type-app.js 1`] = ` +"/** + * @flow + */ + +class LocalClass {} + +var a: LocalClass | number = 123; + +// Iterator is defined in a lib file, so the speculative algorithm for the +// union type would incorrectly succeed for Iterator. Only later during +// the merge would we fine the error, but it would be too late. The diff that +// introduces this test fixes this such that the speculative algorithm is +// correctly delayed upon encountering a non-concrete TypeAppT +var b: Iterator | number = 123; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1172:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test union.js 1`] = ` +"function bar(x: Document | string): void { } +bar(0); + +class C { } +class D { } +function CD(b) { + var E = b? C: D; + var c:C = new E(); // error, since E could be D, and D is not a subtype of C + function qux(e: E) { } // this annotation is an error: is it C, or is it D? + function qux2(e: C | D) { } // OK + qux2(new C); +} + +declare class F { + foo(x: number):void; + foo(x: string):void; +} +function corge(b) { + var x = b ? \"\" : 0; + new F().foo(x); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test yuge.js 1`] = ` +"/** + * great big union used as type annotation will be flowed into itself. + * List.mem check avoids pathology, as long as singletons aren\'t converted. + * This is a band-aid, though: see second case. + * @flow + */ +\'use strict\'; + +class SecurityCheckupTypedLogger { + _data: Data; + + setError(value: ErrorCode) { + this._data[\'error\'] = value; + } + + // Bug: right now, any incompatible type coming into a huge + // union might blow the recursion limit. + // TODO real solution is to specialize union reps for obvious cases, + // e.g. (base type, list in decl order, set). Of course we could do + // something quick to get the union size off the Ocaml call stack, + // but not sure it\'s worth doing that before the real solution. + ohThatsNotSoGood() { + (\"\": ErrorCode); // also, error pos omits this line completely + } +} + +type ErrorCode = +0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 | +9 | +10 | +11 | +12 | +13 | +14 | +15 | +16 | +17 | +18 | +19 | +20 | +21 | +22 | +23 | +24 | +25 | +26 | +27 | +28 | +29 | +30 | +31 | +32 | +33 | +34 | +35 | +36 | +37 | +38 | +39 | +40 | +41 | +42 | +43 | +44 | +45 | +46 | +47 | +48 | +49 | +50 | +51 | +52 | +53 | +54 | +55 | +56 | +57 | +58 | +59 | +60 | +61 | +62 | +63 | +64 | +65 | +66 | +67 | +68 | +69 | +70 | +71 | +72 | +73 | +74 | +75 | +76 | +77 | +78 | +79 | +80 | +81 | +82 | +83 | +84 | +85 | +86 | +87 | +88 | +89 | +90 | +91 | +92 | +93 | +94 | +95 | +96 | +97 | +98 | +99 | +100 | +101 | +102 | +103 | +104 | +105 | +106 | +107 | +108 | +109 | +110 | +111 | +112 | +113 | +114 | +115 | +116 | +117 | +118 | +119 | +120 | +121 | +122 | +123 | +124 | +125 | +126 | +127 | +128 | +129 | +130 | +131 | +132 | +133 | +134 | +135 | +136 | +137 | +138 | +139 | +140 | +141 | +142 | +143 | +144 | +145 | +146 | +147 | +148 | +149 | +150 | +151 | +152 | +153 | +154 | +155 | +156 | +157 | +158 | +159 | +160 | +161 | +162 | +163 | +164 | +165 | +166 | +167 | +168 | +169 | +170 | +171 | +172 | +173 | +174 | +175 | +176 | +177 | +178 | +179 | +180 | +181 | +182 | +183 | +184 | +185 | +186 | +187 | +188 | +189 | +190 | +191 | +192 | +193 | +194 | +195 | +196 | +197 | +198 | +199 | +200 | +201 | +202 | +203 | +204 | +205 | +206 | +207 | +208 | +209 | +210 | +211 | +212 | +213 | +214 | +215 | +216 | +217 | +218 | +219 | +220 | +221 | +222 | +223 | +224 | +225 | +226 | +227 | +228 | +229 | +230 | +231 | +232 | +233 | +234 | +235 | +236 | +237 | +238 | +239 | +240 | +241 | +242 | +243 | +244 | +245 | +246 | +247 | +248 | +249 | +250 | +251 | +252 | +253 | +254 | +255 | +256 | +257 | +258 | +259 | +260 | +261 | +262 | +263 | +264 | +265 | +266 | +267 | +268 | +269 | +270 | +271 | +272 | +273 | +274 | +275 | +276 | +277 | +278 | +279 | +280 | +281 | +282 | +283 | +284 | +285 | +286 | +287 | +288 | +289 | +290 | +291 | +292 | +293 | +294 | +295 | +296 | +297 | +298 | +299 | +300 | +301 | +302 | +303 | +304 | +305 | +306 | +307 | +308 | +309 | +310 | +311 | +312 | +313 | +314 | +315 | +316 | +317 | +318 | +319 | +320 | +321 | +322 | +323 | +324 | +325 | +326 | +327 | +328 | +329 | +330 | +331 | +332 | +333 | +334 | +335 | +336 | +337 | +338 | +339 | +340 | +341 | +342 | +343 | +344 | +345 | +346 | +347 | +348 | +349 | +350 | +351 | +352 | +353 | +354 | +355 | +356 | +357 | +358 | +359 | +360 | +361 | +362 | +363 | +364 | +365 | +366 | +367 | +368 | +369 | +370 | +371 | +372 | +373 | +374 | +375 | +376 | +377 | +378 | +379 | +380 | +381 | +382 | +383 | +384 | +385 | +386 | +387 | +388 | +389 | +390 | +391 | +392 | +393 | +394 | +395 | +396 | +397 | +398 | +399 | +400 | +401 | +402 | +403 | +404 | +405 | +406 | +407 | +408 | +409 | +410 | +411 | +412 | +413 | +414 | +415 | +416 | +417 | +418 | +419 | +420 | +421 | +422 | +423 | +424 | +425 | +426 | +427 | +428 | +429 | +430 | +431 | +432 | +433 | +434 | +435 | +436 | +437 | +438 | +439 | +440 | +441 | +442 | +443 | +444 | +445 | +446 | +447 | +448 | +449 | +450 | +451 | +452 | +453 | +454 | +455 | +456 | +457 | +458 | +459 | +460 | +461 | +462 | +463 | +464 | +465 | +466 | +467 | +468 | +469 | +470 | +471 | +472 | +473 | +474 | +475 | +476 | +477 | +478 | +479 | +480 | +481 | +482 | +483 | +484 | +485 | +486 | +487 | +488 | +489 | +490 | +491 | +492 | +493 | +494 | +495 | +496 | +497 | +498 | +499 | +500 | +501 | +502 | +503 | +504 | +505 | +506 | +507 | +508 | +509 | +510 | +511 | +512 | +513 | +514 | +515 | +516 | +517 | +518 | +519 | +520 | +521 | +522 | +523 | +524 | +525 | +526 | +527 | +528 | +529 | +530 | +531 | +532 | +533 | +534 | +535 | +536 | +537 | +538 | +539 | +540 | +541 | +542 | +543 | +544 | +545 | +546 | +547 | +548 | +549 | +550 | +551 | +552 | +553 | +554 | +555 | +556 | +557 | +558 | +559 | +560 | +561 | +562 | +563 | +564 | +565 | +566 | +567 | +568 | +569 | +570 | +571 | +572 | +573 | +574 | +575 | +576 | +577 | +578 | +579 | +580 | +581 | +582 | +583 | +584 | +585 | +586 | +587 | +588 | +589 | +590 | +591 | +592 | +593 | +594 | +595 | +596 | +597 | +598 | +599 | +600 | +601 | +602 | +603 | +604 | +605 | +606 | +607 | +608 | +609 | +610 | +611 | +612 | +613 | +614 | +615 | +616 | +617 | +618 | +619 | +620 | +621 | +622 | +623 | +624 | +625 | +626 | +627 | +628 | +629 | +630 | +631 | +632 | +633 | +634 | +635 | +636 | +637 | +638 | +639 | +640 | +641 | +642 | +643 | +644 | +645 | +646 | +647 | +648 | +649 | +650 | +651 | +652 | +653 | +654 | +655 | +656 | +657 | +658 | +659 | +660 | +661 | +662 | +663 | +664 | +665 | +666 | +667 | +668 | +669 | +670 | +671 | +672 | +673 | +674 | +675 | +676 | +677 | +678 | +679 | +680 | +681 | +682 | +683 | +684 | +685 | +686 | +687 | +688 | +689 | +690 | +691 | +692 | +693 | +694 | +695 | +696 | +697 | +698 | +699 | +700 | +701 | +702 | +703 | +704 | +705 | +706 | +707 | +708 | +709 | +710 | +711 | +712 | +713 | +714 | +715 | +716 | +717 | +718 | +719 | +720 | +721 | +722 | +723 | +724 | +725 | +726 | +727 | +728 | +729 | +730 | +731 | +732 | +733 | +734 | +735 | +736 | +737 | +738 | +739 | +740 | +741 | +742 | +743 | +744 | +745 | +746 | +747 | +748 | +749 | +750 | +751 | +752 | +753 | +754 | +755 | +756 | +757 | +758 | +759 | +760 | +761 | +762 | +763 | +764 | +765 | +766 | +767 | +768 | +769 | +770 | +771 | +772 | +773 | +774 | +775 | +776 | +777 | +778 | +779 | +780 | +781 | +782 | +783 | +784 | +785 | +786 | +787 | +788 | +789 | +790 | +791 | +792 | +793 | +794 | +795 | +796 | +797 | +798 | +799 | +800 | +801 | +802 | +803 | +804 | +805 | +806 | +807 | +808 | +809 | +810 | +811 | +812 | +813 | +814 | +815 | +816 | +817 | +818 | +819 | +820 | +821 | +822 | +823 | +824 | +825 | +826 | +827 | +828 | +829 | +830 | +831 | +832 | +833 | +834 | +835 | +836 | +837 | +838 | +839 | +840 | +841 | +842 | +843 | +844 | +845 | +846 | +847 | +848 | +849 | +850 | +851 | +852 | +853 | +854 | +855 | +856 | +857 | +858 | +859 | +860 | +861 | +862 | +863 | +864 | +865 | +866 | +867 | +868 | +869 | +870 | +871 | +872 | +873 | +874 | +875 | +876 | +877 | +878 | +879 | +880 | +881 | +882 | +883 | +884 | +885 | +886 | +887 | +888 | +889 | +890 | +891 | +892 | +893 | +894 | +895 | +896 | +897 | +898 | +899 | +900 | +901 | +902 | +903 | +904 | +905 | +906 | +907 | +908 | +909 | +910 | +911 | +912 | +913 | +914 | +915 | +916 | +917 | +918 | +919 | +920 | +921 | +922 | +923 | +924 | +925 | +926 | +927 | +928 | +929 | +930 | +931 | +932 | +933 | +934 | +935 | +936 | +937 | +938 | +939 | +940 | +941 | +942 | +943 | +944 | +945 | +946 | +947 | +948 | +949 | +950 | +951 | +952 | +953 | +954 | +955 | +956 | +957 | +958 | +959 | +960 | +961 | +962 | +963 | +964 | +965 | +966 | +967 | +968 | +969 | +970 | +971 | +972 | +973 | +974 | +975 | +976 | +977 | +978 | +979 | +980 | +981 | +982 | +983 | +984 | +985 | +986 | +987 | +988 | +989 | +990 | +991 | +992 | +993 | +994 | +995 | +996 | +997 | +998 | +999 | +1000 | +1001 | +1002 | +1003 | +1004 | +1005 | +1006 | +1007 | +1008 | +1009 | +1010 | +1011 | +1012 | +1013 | +1014 | +1015 | +1016 | +1017 | +1018 | +1019 | +1020 | +1021 | +1022 | +1023 | +1024 | +1025 | +1026 | +1027 | +1028 | +1029 | +1030 | +1031 | +1032 | +1033 | +1034 | +1035 | +1036 | +1037 | +1038 | +1039 | +1040 | +1041 | +1042 | +1043 | +1044 | +1045 | +1046 | +1047 | +1048 | +1049 | +1050 | +1051 | +1052 | +1053 | +1054 | +1055 | +1056 | +1057 | +1058 | +1059 | +1060 | +1061 | +1062 | +1063 | +1064 | +1065 | +1066 | +1067 | +1068 | +1069 | +1070 | +1071 | +1072 | +1073 | +1074 | +1075 | +1076 | +1077 | +1078 | +1079 | +1080 | +1081 | +1082 | +1083 | +1084 | +1085 | +1086 | +1087 | +1088 | +1089 | +1090 | +1091 | +1092 | +1093 | +1094 | +1095 | +1096 | +1097 | +1098 | +1099 | +1100 | +1101 | +1102 | +1103 | +1104 | +1105 | +1106 | +1107 | +1108 | +1109 | +1110 | +1111 | +1112 | +1113 | +1114 | +1115 | +1116 | +1117 | +1118 | +1119 | +1120 | +1121 | +1122 | +1123 | +1124 | +1125 | +1126 | +1127 | +1128 | +1129 | +1130 | +1131 | +1132 | +1133 | +1134 | +1135 | +1136 | +1137 | +1138 | +1139 | +1140 | +1141 | +1142 | +1143 | +1144 | +1145 | +1146 | +1147 | +1148 | +1149 | +1150 | +1151 | +1152 | +1153 | +1154 | +1155 | +1156 | +1157 | +1158 | +1159 | +1160 | +1161 | +1162 | +1163 | +1164 | +1165 | +1166 | +1167 | +1168 | +1169 | +1170 | +1171 | +1172 | +1173 | +1174 | +1175 | +1176 | +1177 | +1178 | +1179 | +1180 | +1181 | +1182 | +1183 | +1184 | +1185 | +1186 | +1187 | +1188 | +1189 | +1190 | +1191 | +1192 | +1193 | +1194 | +1195 | +1196 | +1197 | +1198 | +1199 | +1200 | +1201 | +1202 | +1203 | +1204 | +1205 | +1206 | +1207 | +1208 | +1209 | +1210 | +1211 | +1212 | +1213 | +1214 | +1215 | +1216 | +1217 | +1218 | +1219 | +1220 | +1221 | +1222 | +1223 | +1224 | +1225 | +1226 | +1227 | +1228 | +1229 | +1230 | +1231 | +1232 | +1233 | +1234 | +1235 | +1236 | +1237 | +1238 | +1239 | +1240 | +1241 | +1242 | +1243 | +1244 | +1245 | +1246 | +1247 | +1248 | +1249 | +1250 | +1251 | +1252 | +1253 | +1254 | +1255 | +1256 | +1257 | +1258 | +1259 | +1260 | +1261 | +1262 | +1263 | +1264 | +1265 | +1266 | +1267 | +1268 | +1269 | +1270 | +1271 | +1272 | +1273 | +1274 | +1275 | +1276 | +1277 | +1278 | +1279 | +1280 | +1281 | +1282 | +1283 | +1284 | +1285 | +1286 | +1287 | +1288 | +1289 | +1290 | +1291 | +1292 | +1293 | +1294 | +1295 | +1296 | +1297 | +1298 | +1299 | +1300 | +1301 | +1302 | +1303 | +1304 | +1305 | +1306 | +1307 | +1308 | +1309 | +1310 | +1311 | +1312 | +1313 | +1314 | +1315 | +1316 | +1317 | +1318 | +1319 | +1320 | +1321 | +1322 | +1323 | +1324 | +1325 | +1326 | +1327 | +1328 | +1329 | +1330 | +1331 | +1332 | +1333 | +1334 | +1335 | +1336 | +1337 | +1338 | +1339 | +1340 | +1341 | +1342 | +1343 | +1344 | +1345 | +1346 | +1347 | +1348 | +1349 | +1350 | +1351 | +1352 | +1353 | +1354 | +1355 | +1356 | +1357 | +1358 | +1359 | +1360 | +1361 | +1362 | +1363 | +1364 | +1365 | +1366 | +1367 | +1368 | +1369 | +1370 | +1371 | +1372 | +1373 | +1374 | +1375 | +1376 | +1377 | +1378 | +1379 | +1380 | +1381 | +1382 | +1383 | +1384 | +1385 | +1386 | +1387 | +1388 | +1389 | +1390 | +1391 | +1392 | +1393 | +1394 | +1395 | +1396 | +1397 | +1398 | +1399 | +1400 | +1401 | +1402 | +1403 | +1404 | +1405 | +1406 | +1407 | +1408 | +1409 | +1410 | +1411 | +1412 | +1413 | +1414 | +1415 | +1416 | +1417 | +1418 | +1419 | +1420 | +1421 | +1422 | +1423 | +1424 | +1425 | +1426 | +1427 | +1428 | +1429 | +1430 | +1431 | +1432 | +1433 | +1434 | +1435 | +1436 | +1437 | +1438 | +1439 | +1440 | +1441 | +1442 | +1443 | +1444 | +1445 | +1446 | +1447 | +1448 | +1449 | +1450 | +1451 | +1452 | +1453 | +1454 | +1455 | +1456 | +1457 | +1458 | +1459 | +1460 | +1461 | +1462 | +1463 | +1464 | +1465 | +1466 | +1467 | +1468 | +1469 | +1470 | +1471 | +1472 | +1473 | +1474 | +1475 | +1476 | +1477 | +1478 | +1479 | +1480 | +1481 | +1482 | +1483 | +1484 | +1485 | +1486 | +1487 | +1488 | +1489 | +1490 | +1491 | +1492 | +1493 | +1494 | +1495 | +1496 | +1497 | +1498 | +1499 | +1500 | +1501 | +1502 | +1503 | +1504 | +1505 | +1506 | +1507 | +1508 | +1509 | +1510 | +1511 | +1512 | +1513 | +1514 | +1515 | +1516 | +1517 | +1518 | +1519 | +1520 | +1521 | +1522 | +1523 | +1524 | +1525 | +1526 | +1527 | +1528 | +1529 | +1530 | +1531 | +1532 | +1533 | +1534 | +1535 | +1536 | +1537 | +1538 | +1539 | +1540 | +1541 | +1542 | +1543 | +1544 | +1545 | +1546 | +1547 | +1548 | +1549 | +1550 | +1551 | +1552 | +1553 | +1554 | +1555 | +1556 | +1557 | +1558 | +1559 | +1560 | +1561 | +1562 | +1563 | +1564 | +1565 | +1566 | +1567 | +1568 | +1569 | +1570 | +1571 | +1572 | +1573 | +1574 | +1575 | +1576 | +1577 | +1578 | +1579 | +1580 | +1581 | +1582 | +1583 | +1584 | +1585 | +1586 | +1587 | +1588 | +1589 | +1590 | +1591 | +1592 | +1593 | +1594 | +1595 | +1596 | +1597 | +1598 | +1599 | +1600 | +1601 | +1602 | +1603 | +1604 | +1605 | +1606 | +1607 | +1608 | +1609 | +1610 | +1611 | +1612 | +1613 | +1614 | +1615 | +1616 | +1617 | +1618 | +1619 | +1620 | +1621 | +1622 | +1623 | +1624 | +1625 | +1626 | +1627 | +1628 | +1629 | +1630 | +1631 | +1632 | +1633 | +1634 | +1635 | +1636 | +1637 | +1638 | +1639 | +1640 | +1641 | +1642 | +1643 | +1644 | +1645 | +1646 | +1647 | +1648 | +1649 | +1650 | +1651 | +1652 | +1653 | +1654 | +1655 | +1656 | +1657 | +1658 | +1659 | +1660 | +1661 | +1662 | +1663 | +1664 | +1665 | +1666 | +1667 | +1668 | +1669 | +1670 | +1671 | +1672 | +1673 | +1674 | +1675 | +1676 | +1677 | +1678 | +1679 | +1680 | +1681 | +1682 | +1683 | +1684 | +1685 | +1686 | +1687 | +1688 | +1689 | +1690 | +1691 | +1692 | +1693 | +1694 | +1695 | +1696 | +1697 | +1698 | +1699 | +1700 | +1701 | +1702 | +1703 | +1704 | +1705 | +1706 | +1707 | +1708 | +1709 | +1710 | +1711 | +1712 | +1713 | +1714 | +1715 | +1716 | +1717 | +1718 | +1719 | +1720 | +1721 | +1722 | +1723 | +1724 | +1725 | +1726 | +1727 | +1728 | +1729 | +1730 | +1731 | +1732 | +1733 | +1734 | +1735 | +1736 | +1737 | +1738 | +1739 | +1740 | +1741 | +1742 | +1743 | +1744 | +1745 | +1746 | +1747 | +1748 | +1749 | +1750 | +1751 | +1752 | +1753 | +1754 | +1755 | +1756 | +1757 | +1758 | +1759 | +1760 | +1761 | +1762 | +1763 | +1764 | +1765 | +1766 | +1767 | +1768 | +1769 | +1770 | +1771 | +1772 | +1773 | +1774 | +1775 | +1776 | +1777 | +1778 | +1779 | +1780 | +1781 | +1782 | +1783 | +1784 | +1785 | +1786 | +1787 | +1788 | +1789 | +1790 | +1791 | +1792 | +1793 | +1794 | +1795 | +1796 | +1797 | +1798 | +1799 | +1800 | +1801 | +1802 | +1803 | +1804 | +1805 | +1806 | +1807 | +1808 | +1809 | +1810 | +1811 | +1812 | +1813 | +1814 | +1815 | +1816 | +1817 | +1818 | +1819 | +1820 | +1821 | +1822 | +1823 | +1824 | +1825 | +1826 | +1827 | +1828 | +1829 | +1830 | +1831 | +1832 | +1833 | +1834 | +1835 | +1836 | +1837 | +1838 | +1839 | +1840 | +1841 | +1842 | +1843 | +1844 | +1845 | +1846 | +1847 | +1848 | +1849 | +1850 | +1851 | +1852 | +1853 | +1854 | +1855 | +1856 | +1857 | +1858 | +1859 | +1860 | +1861 | +1862 | +1863 | +1864 | +1865 | +1866 | +1867 | +1868 | +1869 | +1870 | +1871 | +1872 | +1873 | +1874 | +1875 | +1876 | +1877 | +1878 | +1879 | +1880 | +1881 | +1882 | +1883 | +1884 | +1885 | +1886 | +1887 | +1888 | +1889 | +1890 | +1891 | +1892 | +1893 | +1894 | +1895 | +1896 | +1897 | +1898 | +1899 | +1900 | +1901 | +1902 | +1903 | +1904 | +1905 | +1906 | +1907 | +1908 | +1909 | +1910 | +1911 | +1912 | +1913 | +1914 | +1915 | +1916 | +1917 | +1918 | +1919 | +1920 | +1921 | +1922 | +1923 | +1924 | +1925 | +1926 | +1927 | +1928 | +1929 | +1930 | +1931 | +1932 | +1933 | +1934 | +1935 | +1936 | +1937 | +1938 | +1939 | +1940 | +1941 | +1942 | +1943 | +1944 | +1945 | +1946 | +1947 | +1948 | +1949 | +1950 | +1951 | +1952 | +1953 | +1954 | +1955 | +1956 | +1957 | +1958 | +1959 | +1960 | +1961 | +1962 | +1963 | +1964 | +1965 | +1966 | +1967 | +1968 | +1969 | +1970 | +1971 | +1972 | +1973 | +1974 | +1975 | +1976 | +1977 | +1978 | +1979 | +1980 | +1981 | +1982 | +1983 | +1984 | +1985 | +1986 | +1987 | +1988 | +1989 | +1990 | +1991 | +1992 | +1993 | +1994 | +1995 | +1996 | +1997 | +1998 | +1999 | +2000 | +2001 | +2002 | +2003 | +2004 | +2005 | +2006 | +2007 | +2008 | +2009 | +2010 | +2011 | +2012 | +2013 | +2014 | +2015 | +2016 | +2017 | +2018 | +2019 | +2020 | +2021 | +2022 | +2023 | +2024 | +2025 | +2026 | +2027 | +2028 | +2029 | +2030 | +2031 | +2032 | +2033 | +2034 | +2035 | +2036 | +2037 | +2038 | +2039 | +2040 | +2041 | +2042 | +2043 | +2044 | +2045 | +2046 | +2047 | +2048 | +2049 | +2050 | +2051 | +2052 | +2053 | +2054 | +2055 | +2056 | +2057 | +2058 | +2059 | +2060 | +2061 | +2062 | +2063 | +2064 | +2065 | +2066 | +2067 | +2068 | +2069 | +2070 | +2071 | +2072 | +2073 | +2074 | +2075 | +2076 | +2077 | +2078 | +2079 | +2080 | +2081 | +2082 | +2083 | +2084 | +2085 | +2086 | +2087 | +2088 | +2089 | +2090 | +2091 | +2092 | +2093 | +2094 | +2095 | +2096 | +2097 | +2098 | +2099 | +2100 | +2101 | +2102 | +2103 | +2104 | +2105 | +2106 | +2107 | +2108 | +2109 | +2110 | +2111 | +2112 | +2113 | +2114 | +2115 | +2116 | +2117 | +2118 | +2119 | +2120 | +2121 | +2122 | +2123 | +2124 | +2125 | +2126 | +2127 | +2128 | +2129 | +2130 | +2131 | +2132 | +2133 | +2134 | +2135 | +2136 | +2137 | +2138 | +2139 | +2140 | +2141 | +2142 | +2143 | +2144 | +2145 | +2146 | +2147 | +2148 | +2149 | +2150 | +2151 | +2152 | +2153 | +2154 | +2155 | +2156 | +2157 | +2158 | +2159 | +2160 | +2161 | +2162 | +2163 | +2164 | +2165 | +2166 | +2167 | +2168 | +2169 | +2170 | +2171 | +2172 | +2173 | +2174 | +2175 | +2176 | +2177 | +2178 | +2179 | +2180 | +2181 | +2182 | +2183 | +2184 | +2185 | +2186 | +2187 | +2188 | +2189 | +2190 | +2191 | +2192 | +2193 | +2194 | +2195 | +2196 | +2197 | +2198 | +2199 | +2200 | +2201 | +2202 | +2203 | +2204 | +2205 | +2206 | +2207 | +2208 | +2209 | +2210 | +2211 | +2212 | +2213 | +2214 | +2215 | +2216 | +2217 | +2218 | +2219 | +2220 | +2221 | +2222 | +2223 | +2224 | +2225 | +2226 | +2227 | +2228 | +2229 | +2230 | +2231 | +2232 | +2233 | +2234 | +2235 | +2236 | +2237 | +2238 | +2239 | +2240 | +2241 | +2242 | +2243 | +2244 | +2245 | +2246 | +2247 | +2248 | +2249 | +2250 | +2251 | +2252 | +2253 | +2254 | +2255 | +2256 | +2257 | +2258 | +2259 | +2260 | +2261 | +2262 | +2263 | +2264 | +2265 | +2266 | +2267 | +2268 | +2269 | +2270 | +2271 | +2272 | +2273 | +2274 | +2275 | +2276 | +2277 | +2278 | +2279 | +2280 | +2281 | +2282 | +2283 | +2284 | +2285 | +2286 | +2287 | +2288 | +2289 | +2290 | +2291 | +2292 | +2293 | +2294 | +2295 | +2296 | +2297 | +2298 | +2299 | +2300 | +2301 | +2302 | +2303 | +2304 | +2305 | +2306 | +2307 | +2308 | +2309 | +2310 | +2311 | +2312 | +2313 | +2314 | +2315 | +2316 | +2317 | +2318 | +2319 | +2320 | +2321 | +2322 | +2323 | +2324 | +2325 | +2326 | +2327 | +2328 | +2329 | +2330 | +2331 | +2332 | +2333 | +2334 | +2335 | +2336 | +2337 | +2338 | +2339 | +2340 | +2341 | +2342 | +2343 | +2344 | +2345 | +2346 | +2347 | +2348 | +2349 | +2350 | +2351 | +2352 | +2353 | +2354 | +2355 | +2356 | +2357 | +2358 | +2359 | +2360 | +2361 | +2362 | +2363 | +2364 | +2365 | +2366 | +2367 | +2368 | +2369 | +2370 | +2371 | +2372 | +2373 | +2374 | +2375 | +2376 | +2377 | +2378 | +2379 | +2380 | +2381 | +2382 | +2383 | +2384 | +2385 | +2386 | +2387 | +2388 | +2389 | +2390 | +2391 | +2392 | +2393 | +2394 | +2395 | +2396 | +2397 | +2398 | +2399 | +2400 | +2401 | +2402 | +2403 | +2404 | +2405 | +2406 | +2407 | +2408 | +2409 | +2410 | +2411 | +2412 | +2413 | +2414 | +2415 | +2416 | +2417 | +2418 | +2419 | +2420 | +2421 | +2422 | +2423 | +2424 | +2425 | +2426 | +2427 | +2428 | +2429 | +2430 | +2431 | +2432 | +2433 | +2434 | +2435 | +2436 | +2437 | +2438 | +2439 | +2440 | +2441 | +2442 | +2443 | +2444 | +2445 | +2446 | +2447 | +2448 | +2449 | +2450 | +2451 | +2452 | +2453 | +2454 | +2455 | +2456 | +2457 | +2458 | +2459 | +2460 | +2461 | +2462 | +2463 | +2464 | +2465 | +2466 | +2467 | +2468 | +2469 | +2470 | +2471 | +2472 | +2473 | +2474 | +2475 | +2476 | +2477 | +2478 | +2479 | +2480 | +2481 | +2482 | +2483 | +2484 | +2485 | +2486 | +2487 | +2488 | +2489 | +2490 | +2491 | +2492 | +2493 | +2494 | +2495 | +2496 | +2497 | +2498 | +2499 | +2500 | +2501 | +2502 | +2503 | +2504 | +2505 | +2506 | +2507 | +2508 | +2509 | +2510 | +2511 | +2512 | +2513 | +2514 | +2515 | +2516 | +2517 | +2518 | +2519 | +2520 | +2521 | +2522 | +2523 | +2524 | +2525 | +2526 | +2527 | +2528 | +2529 | +2530 | +2531 | +2532 | +2533 | +2534 | +2535 | +2536 | +2537 | +2538 | +2539 | +2540 | +2541 | +2542 | +2543 | +2544 | +2545 | +2546 | +2547 | +2548 | +2549 | +2550 | +2551 | +2552 | +2553 | +2554 | +2555 | +2556 | +2557 | +2558 | +2559 | +2560 | +2561 | +2562 | +2563 | +2564 | +2565 | +2566 | +2567 | +2568 | +2569 | +2570 | +2571 | +2572 | +2573 | +2574 | +2575 | +2576 | +2577 | +2578 | +2579 | +2580 | +2581 | +2582 | +2583 | +2584 | +2585 | +2586 | +2587 | +2588 | +2589 | +2590 | +2591 | +2592 | +2593 | +2594 | +2595 | +2596 | +2597 | +2598 | +2599 | +2600 | +2601 | +2602 | +2603 | +2604 | +2605 | +2606 | +2607 | +2608 | +2609 | +2610 | +2611 | +2612 | +2613 | +2614 | +2615 | +2616 | +2617 | +2618 | +2619 | +2620 | +2621 | +2622 | +2623 | +2624 | +2625 | +2626 | +2627 | +2628 | +2629 | +2630 | +2631 | +2632 | +2633 | +2634 | +2635 | +2636 | +2637 | +2638 | +2639 | +2640 | +2641 | +2642 | +2643 | +2644 | +2645 | +2646 | +2647 | +2648 | +2649 | +2650 | +2651 | +2652 | +2653 | +2654 | +2655 | +2656 | +2657 | +2658 | +2659 | +2660 | +2661 | +2662 | +2663 | +2664 | +2665 | +2666 | +2667 | +2668 | +2669 | +2670 | +2671 | +2672 | +2673 | +2674 | +2675 | +2676 | +2677 | +2678 | +2679 | +2680 | +2681 | +2682 | +2683 | +2684 | +2685 | +2686 | +2687 | +2688 | +2689 | +2690 | +2691 | +2692 | +2693 | +2694 | +2695 | +2696 | +2697 | +2698 | +2699 | +2700 | +2701 | +2702 | +2703 | +2704 | +2705 | +2706 | +2707 | +2708 | +2709 | +2710 | +2711 | +2712 | +2713 | +2714 | +2715 | +2716 | +2717 | +2718 | +2719 | +2720 | +2721 | +2722 | +2723 | +2724 | +2725 | +2726 | +2727 | +2728 | +2729 | +2730 | +2731 | +2732 | +2733 | +2734 | +2735 | +2736 | +2737 | +2738 | +2739 | +2740 | +2741 | +2742 | +2743 | +2744 | +2745 | +2746 | +2747 | +2748 | +2749 | +2750 | +2751 | +2752 | +2753 | +2754 | +2755 | +2756 | +2757 | +2758 | +2759 | +2760 | +2761 | +2762 | +2763 | +2764 | +2765 | +2766 | +2767 | +2768 | +2769 | +2770 | +2771 | +2772 | +2773 | +2774 | +2775 | +2776 | +2777 | +2778 | +2779 | +2780 | +2781 | +2782 | +2783 | +2784 | +2785 | +2786 | +2787 | +2788 | +2789 | +2790 | +2791 | +2792 | +2793 | +2794 | +2795 | +2796 | +2797 | +2798 | +2799 | +2800 | +2801 | +2802 | +2803 | +2804 | +2805 | +2806 | +2807 | +2808 | +2809 | +2810 | +2811 | +2812 | +2813 | +2814 | +2815 | +2816 | +2817 | +2818 | +2819 | +2820 | +2821 | +2822 | +2823 | +2824 | +2825 | +2826 | +2827 | +2828 | +2829 | +2830 | +2831 | +2832 | +2833 | +2834 | +2835 | +2836 | +2837 | +2838 | +2839 | +2840 | +2841 | +2842 | +2843 | +2844 | +2845 | +2846 | +2847 | +2848 | +2849 | +2850 | +2851 | +2852 | +2853 | +2854 | +2855 | +2856 | +2857 | +2858 | +2859 | +2860 | +2861 | +2862 | +2863 | +2864 | +2865 | +2866 | +2867 | +2868 | +2869 | +2870 | +2871 | +2872 | +2873 | +2874 | +2875 | +2876 | +2877 | +2878 | +2879 | +2880 | +2881 | +2882 | +2883 | +2884 | +2885 | +2886 | +2887 | +2888 | +2889 | +2890 | +2891 | +2892 | +2893 | +2894 | +2895 | +2896 | +2897 | +2898 | +2899 | +2900 | +2901 | +2902 | +2903 | +2904 | +2905 | +2906 | +2907 | +2908 | +2909 | +2910 | +2911 | +2912 | +2913 | +2914 | +2915 | +2916 | +2917 | +2918 | +2919 | +2920 | +2921 | +2922 | +2923 | +2924 | +2925 | +2926 | +2927 | +2928 | +2929 | +2930 | +2931 | +2932 | +2933 | +2934 | +2935 | +2936 | +2937 | +2938 | +2939 | +2940 | +2941 | +2942 | +2943 | +2944 | +2945 | +2946 | +2947 | +2948 | +2949 | +2950 | +2951 | +2952 | +2953 | +2954 | +2955 | +2956 | +2957 | +2958 | +2959 | +2960 | +2961 | +2962 | +2963 | +2964 | +2965 | +2966 | +2967 | +2968 | +2969 | +2970 | +2971 | +2972 | +2973 | +2974 | +2975 | +2976 | +2977 | +2978 | +2979 | +2980 | +2981 | +2982 | +2983 | +2984 | +2985 | +2986 | +2987 | +2988 | +2989 | +2990 | +2991 | +2992 | +2993 | +2994 | +2995 | +2996 | +2997 | +2998 | +2999 | +3000 | +3001 | +3002 | +3003 | +3004 | +3005 | +3006 | +3007 | +3008 | +3009 | +3010 | +3011 | +3012 | +3013 | +3014 | +3015 | +3016 | +3017 | +3018 | +3019 | +3020 | +3021 | +3022 | +3023 | +3024 | +3025 | +3026 | +3027 | +3028 | +3029 | +3030 | +3031 | +3032 | +3033 | +3034 | +3035 | +3036 | +3037 | +3038 | +3039 | +3040 | +3041 | +3042 | +3043 | +3044 | +3045 | +3046 | +3047 | +3048 | +3049 | +3050 | +3051 | +3052 | +3053 | +3054 | +3055 | +3056 | +3057 | +3058 | +3059 | +3060 | +3061 | +3062 | +3063 | +3064 | +3065 | +3066 | +3067 | +3068 | +3069 | +3070 | +3071 | +3072 | +3073 | +3074 | +3075 | +3076 | +3077 | +3078 | +3079 | +3080 | +3081 | +3082 | +3083 | +3084 | +3085 | +3086 | +3087 | +3088 | +3089 | +3090 | +3091 | +3092 | +3093 | +3094 | +3095 | +3096 | +3097 | +3098 | +3099 | +3100 | +3101 | +3102 | +3103 | +3104 | +3105 | +3106 | +3107 | +3108 | +3109 | +3110 | +3111 | +3112 | +3113 | +3114 | +3115 | +3116 | +3117 | +3118 | +3119 | +3120 | +3121 | +3122 | +3123 | +3124 | +3125 | +3126 | +3127 | +3128 | +3129 | +3130 | +3131 | +3132 | +3133 | +3134 | +3135 | +3136 | +3137 | +3138 | +3139 | +3140 | +3141 | +3142 | +3143 | +3144 | +3145 | +3146 | +3147 | +3148 | +3149 | +3150 | +3151 | +3152 | +3153 | +3154 | +3155 | +3156 | +3157 | +3158 | +3159 | +3160 | +3161 | +3162 | +3163 | +3164 | +3165 | +3166 | +3167 | +3168 | +3169 | +3170 | +3171 | +3172 | +3173 | +3174 | +3175 | +3176 | +3177 | +3178 | +3179 | +3180 | +3181 | +3182 | +3183 | +3184 | +3185 | +3186 | +3187 | +3188 | +3189 | +3190 | +3191 | +3192 | +3193 | +3194 | +3195 | +3196 | +3197 | +3198 | +3199 | +3200 | +3201 | +3202 | +3203 | +3204 | +3205 | +3206 | +3207 | +3208 | +3209 | +3210 | +3211 | +3212 | +3213 | +3214 | +3215 | +3216 | +3217 | +3218 | +3219 | +3220 | +3221 | +3222 | +3223 | +3224 | +3225 | +3226 | +3227 | +3228 | +3229 | +3230 | +3231 | +3232 | +3233 | +3234 | +3235 | +3236 | +3237 | +3238 | +3239 | +3240 | +3241 | +3242 | +3243 | +3244 | +3245 | +3246 | +3247 | +3248 | +3249 | +3250 | +3251 | +3252 | +3253 | +3254 | +3255 | +3256 | +3257 | +3258 | +3259 | +3260 | +3261 | +3262 | +3263 | +3264 | +3265 | +3266 | +3267 | +3268 | +3269 | +3270 | +3271 | +3272 | +3273 | +3274 | +3275 | +3276 | +3277 | +3278 | +3279 | +3280 | +3281 | +3282 | +3283 | +3284 | +3285 | +3286 | +3287 | +3288 | +3289 | +3290 | +3291 | +3292 | +3293 | +3294 | +3295 | +3296 | +3297 | +3298 | +3299 | +3300 | +3301 | +3302 | +3303 | +3304 | +3305 | +3306 | +3307 | +3308 | +3309 | +3310 | +3311 | +3312 | +3313 | +3314 | +3315 | +3316 | +3317 | +3318 | +3319 | +3320 | +3321 | +3322 | +3323 | +3324 | +3325 | +3326 | +3327 | +3328 | +3329 | +3330 | +3331 | +3332 | +3333 | +3334 | +3335 | +3336 | +3337 | +3338 | +3339 | +3340 | +3341 | +3342 | +3343 | +3344 | +3345 | +3346 | +3347 | +3348 | +3349 | +3350 | +3351 | +3352 | +3353 | +3354 | +3355 | +3356 | +3357 | +3358 | +3359 | +3360 | +3361 | +3362 | +3363 | +3364 | +3365 | +3366 | +3367 | +3368 | +3369 | +3370 | +3371 | +3372 | +3373 | +3374 | +3375 | +3376 | +3377 | +3378 | +3379 | +3380 | +3381 | +3382 | +3383 | +3384 | +3385 | +3386 | +3387 | +3388 | +3389 | +3390 | +3391 | +3392 | +3393 | +3394 | +3395 | +3396 | +3397 | +3398 | +3399 | +3400 | +3401 | +3402 | +3403 | +3404 | +3405 | +3406 | +3407 | +3408 | +3409 | +3410 | +3411 | +3412 | +3413 | +3414 | +3415 | +3416 | +3417 | +3418 | +3419 | +3420 | +3421 | +3422 | +3423 | +3424 | +3425 | +3426 | +3427 | +3428 | +3429 | +3430 | +3431 | +3432 | +3433 | +3434 | +3435 | +3436 | +3437 | +3438 | +3439 | +3440 | +3441 | +3442 | +3443 | +3444 | +3445 | +3446 | +3447 | +3448 | +3449 | +3450 | +3451 | +3452 | +3453 | +3454 | +3455 | +3456 | +3457 | +3458 | +3459 | +3460 | +3461 | +3462 | +3463 | +3464 | +3465 | +3466 | +3467 | +3468 | +3469 | +3470 | +3471 | +3472 | +3473 | +3474 | +3475 | +3476 | +3477 | +3478 | +3479 | +3480 | +3481 | +3482 | +3483 | +3484 | +3485 | +3486 | +3487 | +3488 | +3489 | +3490 | +3491 | +3492 | +3493 | +3494 | +3495 | +3496 | +3497 | +3498 | +3499 | +3500 | +3501 | +3502 | +3503 | +3504 | +3505 | +3506 | +3507 | +3508 | +3509 | +3510 | +3511 | +3512 | +3513 | +3514 | +3515 | +3516 | +3517 | +3518 | +3519 | +3520 | +3521 | +3522 | +3523 | +3524 | +3525 | +3526 | +3527 | +3528 | +3529 | +3530 | +3531 | +3532 | +3533 | +3534 | +3535 | +3536 | +3537 | +3538 | +3539 | +3540 | +3541 | +3542 | +3543 | +3544 | +3545 | +3546 | +3547 | +3548 | +3549 | +3550 | +3551 | +3552 | +3553 | +3554 | +3555 | +3556 | +3557 | +3558 | +3559 | +3560 | +3561 | +3562 | +3563 | +3564 | +3565 | +3566 | +3567 | +3568 | +3569 | +3570 | +3571 | +3572 | +3573 | +3574 | +3575 | +3576 | +3577 | +3578 | +3579 | +3580 | +3581 | +3582 | +3583 | +3584 | +3585 | +3586 | +3587 | +3588 | +3589 | +3590 | +3591 | +3592 | +3593 | +3594 | +3595 | +3596 | +3597 | +3598 | +3599 | +3600 | +3601 | +3602 | +3603 | +3604 | +3605 | +3606 | +3607 | +3608 | +3609 | +3610 | +3611 | +3612 | +3613 | +3614 | +3615 | +3616 | +3617 | +3618 | +3619 | +3620 | +3621 | +3622 | +3623 | +3624 | +3625 | +3626 | +3627 | +3628 | +3629 | +3630 | +3631 | +3632 | +3633 | +3634 | +3635 | +3636 | +3637 | +3638 | +3639 | +3640 | +3641 | +3642 | +3643 | +3644 | +3645 | +3646 | +3647 | +3648 | +3649 | +3650 | +3651 | +3652 | +3653 | +3654 | +3655 | +3656 | +3657 | +3658 | +3659 | +3660 | +3661 | +3662 | +3663 | +3664 | +3665 | +3666 | +3667 | +3668 | +3669 | +3670 | +3671 | +3672 | +3673 | +3674 | +3675 | +3676 | +3677 | +3678 | +3679 | +3680 | +3681 | +3682 | +3683 | +3684 | +3685 | +3686 | +3687 | +3688 | +3689 | +3690 | +3691 | +3692 | +3693 | +3694 | +3695 | +3696 | +3697 | +3698 | +3699 | +3700 | +3701 | +3702 | +3703 | +3704 | +3705 | +3706 | +3707 | +3708 | +3709 | +3710 | +3711 | +3712 | +3713 | +3714 | +3715 | +3716 | +3717 | +3718 | +3719 | +3720 | +3721 | +3722 | +3723 | +3724 | +3725 | +3726 | +3727 | +3728 | +3729 | +3730 | +3731 | +3732 | +3733 | +3734 | +3735 | +3736 | +3737 | +3738 | +3739 | +3740 | +3741 | +3742 | +3743 | +3744 | +3745 | +3746 | +3747 | +3748 | +3749 | +3750 | +3751 | +3752 | +3753 | +3754 | +3755 | +3756 | +3757 | +3758 | +3759 | +3760 | +3761 | +3762 | +3763 | +3764 | +3765 | +3766 | +3767 | +3768 | +3769 | +3770 | +3771 | +3772 | +3773 | +3774 | +3775 | +3776 | +3777 | +3778 | +3779 | +3780 | +3781 | +3782 | +3783 | +3784 | +3785 | +3786 | +3787 | +3788 | +3789 | +3790 | +3791 | +3792 | +3793 | +3794 | +3795 | +3796 | +3797 | +3798 | +3799 | +3800 | +3801 | +3802 | +3803 | +3804 | +3805 | +3806 | +3807 | +3808 | +3809 | +3810 | +3811 | +3812 | +3813 | +3814 | +3815 | +3816 | +3817 | +3818 | +3819 | +3820 | +3821 | +3822 | +3823 | +3824 | +3825 | +3826 | +3827 | +3828 | +3829 | +3830 | +3831 | +3832 | +3833 | +3834 | +3835 | +3836 | +3837 | +3838 | +3839 | +3840 | +3841 | +3842 | +3843 | +3844 | +3845 | +3846 | +3847 | +3848 | +3849 | +3850 | +3851 | +3852 | +3853 | +3854 | +3855 | +3856 | +3857 | +3858 | +3859 | +3860 | +3861 | +3862 | +3863 | +3864 | +3865 | +3866 | +3867 | +3868 | +3869 | +3870 | +3871 | +3872 | +3873 | +3874 | +3875 | +3876 | +3877 | +3878 | +3879 | +3880 | +3881 | +3882 | +3883 | +3884 | +3885 | +3886 | +3887 | +3888 | +3889 | +3890 | +3891 | +3892 | +3893 | +3894 | +3895 | +3896 | +3897 | +3898 | +3899 | +3900 | +3901 | +3902 | +3903 | +3904 | +3905 | +3906 | +3907 | +3908 | +3909 | +3910 | +3911 | +3912 | +3913 | +3914 | +3915 | +3916 | +3917 | +3918 | +3919 | +3920 | +3921 | +3922 | +3923 | +3924 | +3925 | +3926 | +3927 | +3928 | +3929 | +3930 | +3931 | +3932 | +3933 | +3934 | +3935 | +3936 | +3937 | +3938 | +3939 | +3940 | +3941 | +3942 | +3943 | +3944 | +3945 | +3946 | +3947 | +3948 | +3949 | +3950 | +3951 | +3952 | +3953 | +3954 | +3955 | +3956 | +3957 | +3958 | +3959 | +3960 | +3961 | +3962 | +3963 | +3964 | +3965 | +3966 | +3967 | +3968 | +3969 | +3970 | +3971 | +3972 | +3973 | +3974 | +3975 | +3976 | +3977 | +3978 | +3979 | +3980 | +3981 | +3982 | +3983 | +3984 | +3985 | +3986 | +3987 | +3988 | +3989 | +3990 | +3991 | +3992 | +3993 | +3994 | +3995 | +3996 | +3997 | +3998 | +3999 | +4000 | +4001 | +4002 | +4003 | +4004 | +4005 | +4006 | +4007 | +4008 | +4009 | +4010 | +4011 | +4012 | +4013 | +4014 | +4015 | +4016 | +4017 | +4018 | +4019 | +4020 | +4021 | +4022 | +4023 | +4024 | +4025 | +4026 | +4027 | +4028 | +4029 | +4030 | +4031 | +4032 | +4033 | +4034 | +4035 | +4036 | +4037 | +4038 | +4039 | +4040 | +4041 | +4042 | +4043 | +4044 | +4045 | +4046 | +4047 | +4048 | +4049 | +4050 | +4051 | +4052 | +4053 | +4054 | +4055 | +4056 | +4057 | +4058 | +4059 | +4060 | +4061 | +4062 | +4063 | +4064 | +4065 | +4066 | +4067 | +4068 | +4069 | +4070 | +4071 | +4072 | +4073 | +4074 | +4075 | +4076 | +4077 | +4078 | +4079 | +4080 | +4081 | +4082 | +4083 | +4084 | +4085 | +4086 | +4087 | +4088 | +4089 | +4090 | +4091 | +4092 | +4093 | +4094 | +4095 | +4096 | +4097 | +4098 | +4099 | +4100 | +4101 | +4102 | +4103 | +4104 | +4105 | +4106 | +4107 | +4108 | +4109 | +4110 | +4111 | +4112 | +4113 | +4114 | +4115 | +4116 | +4117 | +4118 | +4119 | +4120 | +4121 | +4122 | +4123 | +4124 | +4125 | +4126 | +4127 | +4128 | +4129 | +4130 | +4131 | +4132 | +4133 | +4134 | +4135 | +4136 | +4137 | +4138 | +4139 | +4140 | +4141 | +4142 | +4143 | +4144 | +4145 | +4146 | +4147 | +4148 | +4149 | +4150 | +4151 | +4152 | +4153 | +4154 | +4155 | +4156 | +4157 | +4158 | +4159 | +4160 | +4161 | +4162 | +4163 | +4164 | +4165 | +4166 | +4167 | +4168 | +4169 | +4170 | +4171 | +4172 | +4173 | +4174 | +4175 | +4176 | +4177 | +4178 | +4179 | +4180 | +4181 | +4182 | +4183 | +4184 | +4185 | +4186 | +4187 | +4188 | +4189 | +4190 | +4191 | +4192 | +4193 | +4194 | +4195 | +4196 | +4197 | +4198 | +4199 | +4200 | +4201 | +4202 | +4203 | +4204 | +4205 | +4206 | +4207 | +4208 | +4209 | +4210 | +4211 | +4212 | +4213 | +4214 | +4215 | +4216 | +4217 | +4218 | +4219 | +4220 | +4221 | +4222 | +4223 | +4224 | +4225 | +4226 | +4227 | +4228 | +4229 | +4230 | +4231 | +4232 | +4233 | +4234 | +4235 | +4236 | +4237 | +4238 | +4239 | +4240 | +4241 | +4242 | +4243 | +4244 | +4245 | +4246 | +4247 | +4248 | +4249 | +4250 | +4251 | +4252 | +4253 | +4254 | +4255 | +4256 | +4257 | +4258 | +4259 | +4260 | +4261 | +4262 | +4263 | +4264 | +4265 | +4266 | +4267 | +4268 | +4269 | +4270 | +4271 | +4272 | +4273 | +4274 | +4275 | +4276 | +4277 | +4278 | +4279 | +4280 | +4281 | +4282 | +4283 | +4284 | +4285 | +4286 | +4287 | +4288 | +4289 | +4290 | +4291 | +4292 | +4293 | +4294 | +4295 | +4296 | +4297 | +4298 | +4299 | +4300 | +4301 | +4302 | +4303 | +4304 | +4305 | +4306 | +4307 | +4308 | +4309 | +4310 | +4311 | +4312 | +4313 | +4314 | +4315 | +4316 | +4317 | +4318 | +4319 | +4320 | +4321 | +4322 | +4323 | +4324 | +4325 | +4326 | +4327 | +4328 | +4329 | +4330 | +4331 | +4332 | +4333 | +4334 | +4335 | +4336 | +4337 | +4338 | +4339 | +4340 | +4341 | +4342 | +4343 | +4344 | +4345 | +4346 | +4347 | +4348 | +4349 | +4350 | +4351 | +4352 | +4353 | +4354 | +4355 | +4356 | +4357 | +4358 | +4359 | +4360 | +4361 | +4362 | +4363 | +4364 | +4365 | +4366 | +4367 | +4368 | +4369 | +4370 | +4371 | +4372 | +4373 | +4374 | +4375 | +4376 | +4377 | +4378 | +4379 | +4380 | +4381 | +4382 | +4383 | +4384 | +4385 | +4386 | +4387 | +4388 | +4389 | +4390 | +4391 | +4392 | +4393 | +4394 | +4395 | +4396 | +4397 | +4398 | +4399 | +4400 | +4401 | +4402 | +4403 | +4404 | +4405 | +4406 | +4407 | +4408 | +4409 | +4410 | +4411 | +4412 | +4413 | +4414 | +4415 | +4416 | +4417 | +4418 | +4419 | +4420 | +4421 | +4422 | +4423 | +4424 | +4425 | +4426 | +4427 | +4428 | +4429 | +4430 | +4431 | +4432 | +4433 | +4434 | +4435 | +4436 | +4437 | +4438 | +4439 | +4440 | +4441 | +4442 | +4443 | +4444 | +4445 | +4446 | +4447 | +4448 | +4449 | +4450 | +4451 | +4452 | +4453 | +4454 | +4455 | +4456 | +4457 | +4458 | +4459 | +4460 | +4461 | +4462 | +4463 | +4464 | +4465 | +4466 | +4467 | +4468 | +4469 | +4470 | +4471 | +4472 | +4473 | +4474 | +4475 | +4476 | +4477 | +4478 | +4479 | +4480 | +4481 | +4482 | +4483 | +4484 | +4485 | +4486 | +4487 | +4488 | +4489 | +4490 | +4491 | +4492 | +4493 | +4494 | +4495 | +4496 | +4497 | +4498 | +4499 | +4500 | +4501 | +4502 | +4503 | +4504 | +4505 | +4506 | +4507 | +4508 | +4509 | +4510 | +4511 | +4512 | +4513 | +4514 | +4515 | +4516 | +4517 | +4518 | +4519 | +4520 | +4521 | +4522 | +4523 | +4524 | +4525 | +4526 | +4527 | +4528 | +4529 | +4530 | +4531 | +4532 | +4533 | +4534 | +4535 | +4536 | +4537 | +4538 | +4539 | +4540 | +4541 | +4542 | +4543 | +4544 | +4545 | +4546 | +4547 | +4548 | +4549 | +4550 | +4551 | +4552 | +4553 | +4554 | +4555 | +4556 | +4557 | +4558 | +4559 | +4560 | +4561 | +4562 | +4563 | +4564 | +4565 | +4566 | +4567 | +4568 | +4569 | +4570 | +4571 | +4572 | +4573 | +4574 | +4575 | +4576 | +4577 | +4578 | +4579 | +4580 | +4581 | +4582 | +4583 | +4584 | +4585 | +4586 | +4587 | +4588 | +4589 | +4590 | +4591 | +4592 | +4593 | +4594 | +4595 | +4596 | +4597 | +4598 | +4599 | +4600 | +4601 | +4602 | +4603 | +4604 | +4605 | +4606 | +4607 | +4608 | +4609 | +4610 | +4611 | +4612 | +4613 | +4614 | +4615 | +4616 | +4617 | +4618 | +4619 | +4620 | +4621 | +4622 | +4623 | +4624 | +4625 | +4626 | +4627 | +4628 | +4629 | +4630 | +4631 | +4632 | +4633 | +4634 | +4635 | +4636 | +4637 | +4638 | +4639 | +4640 | +4641 | +4642 | +4643 | +4644 | +4645 | +4646 | +4647 | +4648 | +4649 | +4650 | +4651 | +4652 | +4653 | +4654 | +4655 | +4656 | +4657 | +4658 | +4659 | +4660 | +4661 | +4662 | +4663 | +4664 | +4665 | +4666 | +4667 | +4668 | +4669 | +4670 | +4671 | +4672 | +4673 | +4674 | +4675 | +4676 | +4677 | +4678 | +4679 | +4680 | +4681 | +4682 | +4683 | +4684 | +4685 | +4686 | +4687 | +4688 | +4689 | +4690 | +4691 | +4692 | +4693 | +4694 | +4695 | +4696 | +4697 | +4698 | +4699 | +4700 | +4701 | +4702 | +4703 | +4704 | +4705 | +4706 | +4707 | +4708 | +4709 | +4710 | +4711 | +4712 | +4713 | +4714 | +4715 | +4716 | +4717 | +4718 | +4719 | +4720 | +4721 | +4722 | +4723 | +4724 | +4725 | +4726 | +4727 | +4728 | +4729 | +4730 | +4731 | +4732 | +4733 | +4734 | +4735 | +4736 | +4737 | +4738 | +4739 | +4740 | +4741 | +4742 | +4743 | +4744 | +4745 | +4746 | +4747 | +4748 | +4749 | +4750 | +4751 | +4752 | +4753 | +4754 | +4755 | +4756 | +4757 | +4758 | +4759 | +4760 | +4761 | +4762 | +4763 | +4764 | +4765 | +4766 | +4767 | +4768 | +4769 | +4770 | +4771 | +4772 | +4773 | +4774 | +4775 | +4776 | +4777 | +4778 | +4779 | +4780 | +4781 | +4782 | +4783 | +4784 | +4785 | +4786 | +4787 | +4788 | +4789 | +4790 | +4791 | +4792 | +4793 | +4794 | +4795 | +4796 | +4797 | +4798 | +4799 | +4800 | +4801 | +4802 | +4803 | +4804 | +4805 | +4806 | +4807 | +4808 | +4809 | +4810 | +4811 | +4812 | +4813 | +4814 | +4815 | +4816 | +4817 | +4818 | +4819 | +4820 | +4821 | +4822 | +4823 | +4824 | +4825 | +4826 | +4827 | +4828 | +4829 | +4830 | +4831 | +4832 | +4833 | +4834 | +4835 | +4836 | +4837 | +4838 | +4839 | +4840 | +4841 | +4842 | +4843 | +4844 | +4845 | +4846 | +4847 | +4848 | +4849 | +4850 | +4851 | +4852 | +4853 | +4854 | +4855 | +4856 | +4857 | +4858 | +4859 | +4860 | +4861 | +4862 | +4863 | +4864 | +4865 | +4866 | +4867 | +4868 | +4869 | +4870 | +4871 | +4872 | +4873 | +4874 | +4875 | +4876 | +4877 | +4878 | +4879 | +4880 | +4881 | +4882 | +4883 | +4884 | +4885 | +4886 | +4887 | +4888 | +4889 | +4890 | +4891 | +4892 | +4893 | +4894 | +4895 | +4896 | +4897 | +4898 | +4899 | +4900 | +4901 | +4902 | +4903 | +4904 | +4905 | +4906 | +4907 | +4908 | +4909 | +4910 | +4911 | +4912 | +4913 | +4914 | +4915 | +4916 | +4917 | +4918 | +4919 | +4920 | +4921 | +4922 | +4923 | +4924 | +4925 | +4926 | +4927 | +4928 | +4929 | +4930 | +4931 | +4932 | +4933 | +4934 | +4935 | +4936 | +4937 | +4938 | +4939 | +4940 | +4941 | +4942 | +4943 | +4944 | +4945 | +4946 | +4947 | +4948 | +4949 | +4950 | +4951 | +4952 | +4953 | +4954 | +4955 | +4956 | +4957 | +4958 | +4959 | +4960 | +4961 | +4962 | +4963 | +4964 | +4965 | +4966 | +4967 | +4968 | +4969 | +4970 | +4971 | +4972 | +4973 | +4974 | +4975 | +4976 | +4977 | +4978 | +4979 | +4980 | +4981 | +4982 | +4983 | +4984 | +4985 | +4986 | +4987 | +4988 | +4989 | +4990 | +4991 | +4992 | +4993 | +4994 | +4995 | +4996 | +4997 | +4998 | +4999; + +type Data = { + error?: ErrorCode, +}; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/ast-types/lib/types.js:60 + throw new Error(str + \" does not match type \" + this); + ^ + +Error: {type: NumericLiteralTypeAnnotation, start: 843, end: 844, loc: [object Object], value: 0, extra: [object Object]} does not match type Printable + at Type.Tp.assert (/node_modules/ast-types/lib/types.js:60:19) + at genericPrintNoParens (/src/printer.js:221:24) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) +" +`; diff --git a/tests/union/fields.js b/tests/union/fields.js new file mode 100644 index 000000000000..f3bb77b06f98 --- /dev/null +++ b/tests/union/fields.js @@ -0,0 +1,6 @@ +class C { + x: ?number|string; + constructor() { + this.x = null; + } +} diff --git a/tests/union/fields2.js b/tests/union/fields2.js new file mode 100644 index 000000000000..b065e17fddb2 --- /dev/null +++ b/tests/union/fields2.js @@ -0,0 +1,9 @@ +class C { } + +class D { + content: string|C; + copyContent(content: C): string|C { + this.content = content; + return this.content; + } +} diff --git a/tests/union/issue-17.js b/tests/union/issue-17.js new file mode 100644 index 000000000000..18c6dc49571c --- /dev/null +++ b/tests/union/issue-17.js @@ -0,0 +1,16 @@ +/* @flow */ + +type T = + {type: "a"; a: number} | + {type: "b"; b: string}; + +var l: Array = [ + {type: "a", a: 1}, + {type: "a", a: 2}, + {type: "a", a: 3}, + {type: "a", a: 4}, + {type: "b", b: "monkey"}, + {type: "b", b: "gorilla"}, + {type: "b", b: "giraffe"}, + {type: "b", b: "penguin"}, +]; diff --git a/tests/union/issue-198.js b/tests/union/issue-198.js new file mode 100644 index 000000000000..72072f498088 --- /dev/null +++ b/tests/union/issue-198.js @@ -0,0 +1,10 @@ +var p = new Promise(function(resolve, reject) { + resolve(5); +}) + .then(function(num) { + return num.toFixed(); + }) + .then(function(str) { + // This should fail because str is string, not number + return str.toFixed(); + }); diff --git a/tests/union/issue-256.js b/tests/union/issue-256.js new file mode 100644 index 000000000000..5fc84c9519be --- /dev/null +++ b/tests/union/issue-256.js @@ -0,0 +1,7 @@ +declare class Myclass { + myfun(myarray: Array): any; +} +declare var myclass: Myclass; + +myclass.myfun(["1", "2", "3", "4", "5", "6", function (ar) {}]) +myclass.myfun(["1", "2", "3", "4", "5", "6", "7", function (ar) {}]) diff --git a/tests/union/issue-323-lib.js b/tests/union/issue-323-lib.js new file mode 100644 index 000000000000..8d0e73801568 --- /dev/null +++ b/tests/union/issue-323-lib.js @@ -0,0 +1,3 @@ +/* @flow */ +class Foo {} +module.exports = Foo; diff --git a/tests/union/issue-323.js b/tests/union/issue-323.js new file mode 100644 index 000000000000..f5216b84e06c --- /dev/null +++ b/tests/union/issue-323.js @@ -0,0 +1,3 @@ +var Foo = require("./issue-323-lib"); +var foo = new Foo(); +var foostr: Foo | string = foo; diff --git a/tests/union/issue-324.js b/tests/union/issue-324.js new file mode 100644 index 000000000000..a18cf7a8482f --- /dev/null +++ b/tests/union/issue-324.js @@ -0,0 +1,8 @@ +/* @flow */ +class Foo{}; +class Bar{}; + +var foostr: Foo | string = new Foo(); +var barstr: Bar | string = new Bar(); + +foostr = barstr; diff --git a/tests/union/issue-325.js b/tests/union/issue-325.js new file mode 100644 index 000000000000..7fefbc251caa --- /dev/null +++ b/tests/union/issue-325.js @@ -0,0 +1,14 @@ +class Tag { + constructor() { + var a1: Array = []; + var a2: Array = a1; + } +} + +type Node = Tag_ | string; +class Tag_ { + constructor() { + var a1: Array = [new Tag_]; + var a2: Array = a1; + } +} diff --git a/tests/union/issue-326.js b/tests/union/issue-326.js new file mode 100644 index 000000000000..d3de6e5f9616 --- /dev/null +++ b/tests/union/issue-326.js @@ -0,0 +1,4 @@ +var numberAndStringArr:Array = [1,2]; +var stringArr:Array = ['a','b']; + +var result = numberAndStringArr.concat(stringArr); // no error diff --git a/tests/union/issue-582.js b/tests/union/issue-582.js new file mode 100644 index 000000000000..1793a84226dd --- /dev/null +++ b/tests/union/issue-582.js @@ -0,0 +1,14 @@ +/*** + * nested unions + * @flow + */ + +// inline +var nested1: ('foo' | 'bar') | 'baz' = 'baz'; + +// through tvars +type FooBar = 'foo' | 'bar'; +type Baz = 'baz'; +type FooBarBaz = FooBar | Baz; + +var nested2: FooBarBaz = 'baz'; diff --git a/tests/union/issue-963.js b/tests/union/issue-963.js new file mode 100644 index 000000000000..b4803c6da641 --- /dev/null +++ b/tests/union/issue-963.js @@ -0,0 +1,34 @@ +/*** + * unions with embedded intersections + * @flow + */ + +type t1 = { + p1 : number +}; + +type t2 = { + p2: number +} + +type t3 = { + p3 : number +} + +type intersected = t1 & t2; +type union = intersected | t3; +type union2 = t3 | intersected; + +const u1 : union = { + p3 : 3 +}; + +const u2 : union = { + p1 : 1, + p2 : 2 +}; + +const u3 : union2 = { + p1 : 1, + p2 : 2 +}; diff --git a/tests/union/jsfmt.spec.js b/tests/union/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/union/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/union/test-lib.js b/tests/union/test-lib.js new file mode 100644 index 000000000000..e994d2afd4dd --- /dev/null +++ b/tests/union/test-lib.js @@ -0,0 +1,4 @@ +/* @providesModule test-lib */ + +class C { } +module.exports = C; diff --git a/tests/union/test.js b/tests/union/test.js new file mode 100644 index 000000000000..5acbee01e223 --- /dev/null +++ b/tests/union/test.js @@ -0,0 +1,18 @@ +var C = require('test-lib'); + +// TODO: spurious error! (replacing C with number makes the error go away) +// type Foo = Array | Array; +type Foo = Array; // workaround +var x:Array = []; +var y:Array = []; +function foo(x:Foo) {} +foo(x); +foo(y); + +// TODO: spurious error! (replacing C with number makes the error go away) +// type Bar = (() => C) | (() => string); +type Bar = () => (C | string); // workaround + +function f() { return ""; } +function bar(x:Bar) { } +bar(f); diff --git a/tests/union/type-app.js b/tests/union/type-app.js new file mode 100644 index 000000000000..21b4feffd7e7 --- /dev/null +++ b/tests/union/type-app.js @@ -0,0 +1,14 @@ +/** + * @flow + */ + +class LocalClass {} + +var a: LocalClass | number = 123; + +// Iterator is defined in a lib file, so the speculative algorithm for the +// union type would incorrectly succeed for Iterator. Only later during +// the merge would we fine the error, but it would be too late. The diff that +// introduces this test fixes this such that the speculative algorithm is +// correctly delayed upon encountering a non-concrete TypeAppT +var b: Iterator | number = 123; diff --git a/tests/union/union.js b/tests/union/union.js new file mode 100644 index 000000000000..1aa068b024de --- /dev/null +++ b/tests/union/union.js @@ -0,0 +1,21 @@ +function bar(x: Document | string): void { } +bar(0); + +class C { } +class D { } +function CD(b) { + var E = b? C: D; + var c:C = new E(); // error, since E could be D, and D is not a subtype of C + function qux(e: E) { } // this annotation is an error: is it C, or is it D? + function qux2(e: C | D) { } // OK + qux2(new C); +} + +declare class F { + foo(x: number):void; + foo(x: string):void; +} +function corge(b) { + var x = b ? "" : 0; + new F().foo(x); +} diff --git a/tests/union/yuge.js b/tests/union/yuge.js new file mode 100644 index 000000000000..ad2028252900 --- /dev/null +++ b/tests/union/yuge.js @@ -0,0 +1,5031 @@ +/** + * great big union used as type annotation will be flowed into itself. + * List.mem check avoids pathology, as long as singletons aren't converted. + * This is a band-aid, though: see second case. + * @flow + */ +'use strict'; + +class SecurityCheckupTypedLogger { + _data: Data; + + setError(value: ErrorCode) { + this._data['error'] = value; + } + + // Bug: right now, any incompatible type coming into a huge + // union might blow the recursion limit. + // TODO real solution is to specialize union reps for obvious cases, + // e.g. (base type, list in decl order, set). Of course we could do + // something quick to get the union size off the Ocaml call stack, + // but not sure it's worth doing that before the real solution. + ohThatsNotSoGood() { + ("": ErrorCode); // also, error pos omits this line completely + } +} + +type ErrorCode = +0 | +1 | +2 | +3 | +4 | +5 | +6 | +7 | +8 | +9 | +10 | +11 | +12 | +13 | +14 | +15 | +16 | +17 | +18 | +19 | +20 | +21 | +22 | +23 | +24 | +25 | +26 | +27 | +28 | +29 | +30 | +31 | +32 | +33 | +34 | +35 | +36 | +37 | +38 | +39 | +40 | +41 | +42 | +43 | +44 | +45 | +46 | +47 | +48 | +49 | +50 | +51 | +52 | +53 | +54 | +55 | +56 | +57 | +58 | +59 | +60 | +61 | +62 | +63 | +64 | +65 | +66 | +67 | +68 | +69 | +70 | +71 | +72 | +73 | +74 | +75 | +76 | +77 | +78 | +79 | +80 | +81 | +82 | +83 | +84 | +85 | +86 | +87 | +88 | +89 | +90 | +91 | +92 | +93 | +94 | +95 | +96 | +97 | +98 | +99 | +100 | +101 | +102 | +103 | +104 | +105 | +106 | +107 | +108 | +109 | +110 | +111 | +112 | +113 | +114 | +115 | +116 | +117 | +118 | +119 | +120 | +121 | +122 | +123 | +124 | +125 | +126 | +127 | +128 | +129 | +130 | +131 | +132 | +133 | +134 | +135 | +136 | +137 | +138 | +139 | +140 | +141 | +142 | +143 | +144 | +145 | +146 | +147 | +148 | +149 | +150 | +151 | +152 | +153 | +154 | +155 | +156 | +157 | +158 | +159 | +160 | +161 | +162 | +163 | +164 | +165 | +166 | +167 | +168 | +169 | +170 | +171 | +172 | +173 | +174 | +175 | +176 | +177 | +178 | +179 | +180 | +181 | +182 | +183 | +184 | +185 | +186 | +187 | +188 | +189 | +190 | +191 | +192 | +193 | +194 | +195 | +196 | +197 | +198 | +199 | +200 | +201 | +202 | +203 | +204 | +205 | +206 | +207 | +208 | +209 | +210 | +211 | +212 | +213 | +214 | +215 | +216 | +217 | +218 | +219 | +220 | +221 | +222 | +223 | +224 | +225 | +226 | +227 | +228 | +229 | +230 | +231 | +232 | +233 | +234 | +235 | +236 | +237 | +238 | +239 | +240 | +241 | +242 | +243 | +244 | +245 | +246 | +247 | +248 | +249 | +250 | +251 | +252 | +253 | +254 | +255 | +256 | +257 | +258 | +259 | +260 | +261 | +262 | +263 | +264 | +265 | +266 | +267 | +268 | +269 | +270 | +271 | +272 | +273 | +274 | +275 | +276 | +277 | +278 | +279 | +280 | +281 | +282 | +283 | +284 | +285 | +286 | +287 | +288 | +289 | +290 | +291 | +292 | +293 | +294 | +295 | +296 | +297 | +298 | +299 | +300 | +301 | +302 | +303 | +304 | +305 | +306 | +307 | +308 | +309 | +310 | +311 | +312 | +313 | +314 | +315 | +316 | +317 | +318 | +319 | +320 | +321 | +322 | +323 | +324 | +325 | +326 | +327 | +328 | +329 | +330 | +331 | +332 | +333 | +334 | +335 | +336 | +337 | +338 | +339 | +340 | +341 | +342 | +343 | +344 | +345 | +346 | +347 | +348 | +349 | +350 | +351 | +352 | +353 | +354 | +355 | +356 | +357 | +358 | +359 | +360 | +361 | +362 | +363 | +364 | +365 | +366 | +367 | +368 | +369 | +370 | +371 | +372 | +373 | +374 | +375 | +376 | +377 | +378 | +379 | +380 | +381 | +382 | +383 | +384 | +385 | +386 | +387 | +388 | +389 | +390 | +391 | +392 | +393 | +394 | +395 | +396 | +397 | +398 | +399 | +400 | +401 | +402 | +403 | +404 | +405 | +406 | +407 | +408 | +409 | +410 | +411 | +412 | +413 | +414 | +415 | +416 | +417 | +418 | +419 | +420 | +421 | +422 | +423 | +424 | +425 | +426 | +427 | +428 | +429 | +430 | +431 | +432 | +433 | +434 | +435 | +436 | +437 | +438 | +439 | +440 | +441 | +442 | +443 | +444 | +445 | +446 | +447 | +448 | +449 | +450 | +451 | +452 | +453 | +454 | +455 | +456 | +457 | +458 | +459 | +460 | +461 | +462 | +463 | +464 | +465 | +466 | +467 | +468 | +469 | +470 | +471 | +472 | +473 | +474 | +475 | +476 | +477 | +478 | +479 | +480 | +481 | +482 | +483 | +484 | +485 | +486 | +487 | +488 | +489 | +490 | +491 | +492 | +493 | +494 | +495 | +496 | +497 | +498 | +499 | +500 | +501 | +502 | +503 | +504 | +505 | +506 | +507 | +508 | +509 | +510 | +511 | +512 | +513 | +514 | +515 | +516 | +517 | +518 | +519 | +520 | +521 | +522 | +523 | +524 | +525 | +526 | +527 | +528 | +529 | +530 | +531 | +532 | +533 | +534 | +535 | +536 | +537 | +538 | +539 | +540 | +541 | +542 | +543 | +544 | +545 | +546 | +547 | +548 | +549 | +550 | +551 | +552 | +553 | +554 | +555 | +556 | +557 | +558 | +559 | +560 | +561 | +562 | +563 | +564 | +565 | +566 | +567 | +568 | +569 | +570 | +571 | +572 | +573 | +574 | +575 | +576 | +577 | +578 | +579 | +580 | +581 | +582 | +583 | +584 | +585 | +586 | +587 | +588 | +589 | +590 | +591 | +592 | +593 | +594 | +595 | +596 | +597 | +598 | +599 | +600 | +601 | +602 | +603 | +604 | +605 | +606 | +607 | +608 | +609 | +610 | +611 | +612 | +613 | +614 | +615 | +616 | +617 | +618 | +619 | +620 | +621 | +622 | +623 | +624 | +625 | +626 | +627 | +628 | +629 | +630 | +631 | +632 | +633 | +634 | +635 | +636 | +637 | +638 | +639 | +640 | +641 | +642 | +643 | +644 | +645 | +646 | +647 | +648 | +649 | +650 | +651 | +652 | +653 | +654 | +655 | +656 | +657 | +658 | +659 | +660 | +661 | +662 | +663 | +664 | +665 | +666 | +667 | +668 | +669 | +670 | +671 | +672 | +673 | +674 | +675 | +676 | +677 | +678 | +679 | +680 | +681 | +682 | +683 | +684 | +685 | +686 | +687 | +688 | +689 | +690 | +691 | +692 | +693 | +694 | +695 | +696 | +697 | +698 | +699 | +700 | +701 | +702 | +703 | +704 | +705 | +706 | +707 | +708 | +709 | +710 | +711 | +712 | +713 | +714 | +715 | +716 | +717 | +718 | +719 | +720 | +721 | +722 | +723 | +724 | +725 | +726 | +727 | +728 | +729 | +730 | +731 | +732 | +733 | +734 | +735 | +736 | +737 | +738 | +739 | +740 | +741 | +742 | +743 | +744 | +745 | +746 | +747 | +748 | +749 | +750 | +751 | +752 | +753 | +754 | +755 | +756 | +757 | +758 | +759 | +760 | +761 | +762 | +763 | +764 | +765 | +766 | +767 | +768 | +769 | +770 | +771 | +772 | +773 | +774 | +775 | +776 | +777 | +778 | +779 | +780 | +781 | +782 | +783 | +784 | +785 | +786 | +787 | +788 | +789 | +790 | +791 | +792 | +793 | +794 | +795 | +796 | +797 | +798 | +799 | +800 | +801 | +802 | +803 | +804 | +805 | +806 | +807 | +808 | +809 | +810 | +811 | +812 | +813 | +814 | +815 | +816 | +817 | +818 | +819 | +820 | +821 | +822 | +823 | +824 | +825 | +826 | +827 | +828 | +829 | +830 | +831 | +832 | +833 | +834 | +835 | +836 | +837 | +838 | +839 | +840 | +841 | +842 | +843 | +844 | +845 | +846 | +847 | +848 | +849 | +850 | +851 | +852 | +853 | +854 | +855 | +856 | +857 | +858 | +859 | +860 | +861 | +862 | +863 | +864 | +865 | +866 | +867 | +868 | +869 | +870 | +871 | +872 | +873 | +874 | +875 | +876 | +877 | +878 | +879 | +880 | +881 | +882 | +883 | +884 | +885 | +886 | +887 | +888 | +889 | +890 | +891 | +892 | +893 | +894 | +895 | +896 | +897 | +898 | +899 | +900 | +901 | +902 | +903 | +904 | +905 | +906 | +907 | +908 | +909 | +910 | +911 | +912 | +913 | +914 | +915 | +916 | +917 | +918 | +919 | +920 | +921 | +922 | +923 | +924 | +925 | +926 | +927 | +928 | +929 | +930 | +931 | +932 | +933 | +934 | +935 | +936 | +937 | +938 | +939 | +940 | +941 | +942 | +943 | +944 | +945 | +946 | +947 | +948 | +949 | +950 | +951 | +952 | +953 | +954 | +955 | +956 | +957 | +958 | +959 | +960 | +961 | +962 | +963 | +964 | +965 | +966 | +967 | +968 | +969 | +970 | +971 | +972 | +973 | +974 | +975 | +976 | +977 | +978 | +979 | +980 | +981 | +982 | +983 | +984 | +985 | +986 | +987 | +988 | +989 | +990 | +991 | +992 | +993 | +994 | +995 | +996 | +997 | +998 | +999 | +1000 | +1001 | +1002 | +1003 | +1004 | +1005 | +1006 | +1007 | +1008 | +1009 | +1010 | +1011 | +1012 | +1013 | +1014 | +1015 | +1016 | +1017 | +1018 | +1019 | +1020 | +1021 | +1022 | +1023 | +1024 | +1025 | +1026 | +1027 | +1028 | +1029 | +1030 | +1031 | +1032 | +1033 | +1034 | +1035 | +1036 | +1037 | +1038 | +1039 | +1040 | +1041 | +1042 | +1043 | +1044 | +1045 | +1046 | +1047 | +1048 | +1049 | +1050 | +1051 | +1052 | +1053 | +1054 | +1055 | +1056 | +1057 | +1058 | +1059 | +1060 | +1061 | +1062 | +1063 | +1064 | +1065 | +1066 | +1067 | +1068 | +1069 | +1070 | +1071 | +1072 | +1073 | +1074 | +1075 | +1076 | +1077 | +1078 | +1079 | +1080 | +1081 | +1082 | +1083 | +1084 | +1085 | +1086 | +1087 | +1088 | +1089 | +1090 | +1091 | +1092 | +1093 | +1094 | +1095 | +1096 | +1097 | +1098 | +1099 | +1100 | +1101 | +1102 | +1103 | +1104 | +1105 | +1106 | +1107 | +1108 | +1109 | +1110 | +1111 | +1112 | +1113 | +1114 | +1115 | +1116 | +1117 | +1118 | +1119 | +1120 | +1121 | +1122 | +1123 | +1124 | +1125 | +1126 | +1127 | +1128 | +1129 | +1130 | +1131 | +1132 | +1133 | +1134 | +1135 | +1136 | +1137 | +1138 | +1139 | +1140 | +1141 | +1142 | +1143 | +1144 | +1145 | +1146 | +1147 | +1148 | +1149 | +1150 | +1151 | +1152 | +1153 | +1154 | +1155 | +1156 | +1157 | +1158 | +1159 | +1160 | +1161 | +1162 | +1163 | +1164 | +1165 | +1166 | +1167 | +1168 | +1169 | +1170 | +1171 | +1172 | +1173 | +1174 | +1175 | +1176 | +1177 | +1178 | +1179 | +1180 | +1181 | +1182 | +1183 | +1184 | +1185 | +1186 | +1187 | +1188 | +1189 | +1190 | +1191 | +1192 | +1193 | +1194 | +1195 | +1196 | +1197 | +1198 | +1199 | +1200 | +1201 | +1202 | +1203 | +1204 | +1205 | +1206 | +1207 | +1208 | +1209 | +1210 | +1211 | +1212 | +1213 | +1214 | +1215 | +1216 | +1217 | +1218 | +1219 | +1220 | +1221 | +1222 | +1223 | +1224 | +1225 | +1226 | +1227 | +1228 | +1229 | +1230 | +1231 | +1232 | +1233 | +1234 | +1235 | +1236 | +1237 | +1238 | +1239 | +1240 | +1241 | +1242 | +1243 | +1244 | +1245 | +1246 | +1247 | +1248 | +1249 | +1250 | +1251 | +1252 | +1253 | +1254 | +1255 | +1256 | +1257 | +1258 | +1259 | +1260 | +1261 | +1262 | +1263 | +1264 | +1265 | +1266 | +1267 | +1268 | +1269 | +1270 | +1271 | +1272 | +1273 | +1274 | +1275 | +1276 | +1277 | +1278 | +1279 | +1280 | +1281 | +1282 | +1283 | +1284 | +1285 | +1286 | +1287 | +1288 | +1289 | +1290 | +1291 | +1292 | +1293 | +1294 | +1295 | +1296 | +1297 | +1298 | +1299 | +1300 | +1301 | +1302 | +1303 | +1304 | +1305 | +1306 | +1307 | +1308 | +1309 | +1310 | +1311 | +1312 | +1313 | +1314 | +1315 | +1316 | +1317 | +1318 | +1319 | +1320 | +1321 | +1322 | +1323 | +1324 | +1325 | +1326 | +1327 | +1328 | +1329 | +1330 | +1331 | +1332 | +1333 | +1334 | +1335 | +1336 | +1337 | +1338 | +1339 | +1340 | +1341 | +1342 | +1343 | +1344 | +1345 | +1346 | +1347 | +1348 | +1349 | +1350 | +1351 | +1352 | +1353 | +1354 | +1355 | +1356 | +1357 | +1358 | +1359 | +1360 | +1361 | +1362 | +1363 | +1364 | +1365 | +1366 | +1367 | +1368 | +1369 | +1370 | +1371 | +1372 | +1373 | +1374 | +1375 | +1376 | +1377 | +1378 | +1379 | +1380 | +1381 | +1382 | +1383 | +1384 | +1385 | +1386 | +1387 | +1388 | +1389 | +1390 | +1391 | +1392 | +1393 | +1394 | +1395 | +1396 | +1397 | +1398 | +1399 | +1400 | +1401 | +1402 | +1403 | +1404 | +1405 | +1406 | +1407 | +1408 | +1409 | +1410 | +1411 | +1412 | +1413 | +1414 | +1415 | +1416 | +1417 | +1418 | +1419 | +1420 | +1421 | +1422 | +1423 | +1424 | +1425 | +1426 | +1427 | +1428 | +1429 | +1430 | +1431 | +1432 | +1433 | +1434 | +1435 | +1436 | +1437 | +1438 | +1439 | +1440 | +1441 | +1442 | +1443 | +1444 | +1445 | +1446 | +1447 | +1448 | +1449 | +1450 | +1451 | +1452 | +1453 | +1454 | +1455 | +1456 | +1457 | +1458 | +1459 | +1460 | +1461 | +1462 | +1463 | +1464 | +1465 | +1466 | +1467 | +1468 | +1469 | +1470 | +1471 | +1472 | +1473 | +1474 | +1475 | +1476 | +1477 | +1478 | +1479 | +1480 | +1481 | +1482 | +1483 | +1484 | +1485 | +1486 | +1487 | +1488 | +1489 | +1490 | +1491 | +1492 | +1493 | +1494 | +1495 | +1496 | +1497 | +1498 | +1499 | +1500 | +1501 | +1502 | +1503 | +1504 | +1505 | +1506 | +1507 | +1508 | +1509 | +1510 | +1511 | +1512 | +1513 | +1514 | +1515 | +1516 | +1517 | +1518 | +1519 | +1520 | +1521 | +1522 | +1523 | +1524 | +1525 | +1526 | +1527 | +1528 | +1529 | +1530 | +1531 | +1532 | +1533 | +1534 | +1535 | +1536 | +1537 | +1538 | +1539 | +1540 | +1541 | +1542 | +1543 | +1544 | +1545 | +1546 | +1547 | +1548 | +1549 | +1550 | +1551 | +1552 | +1553 | +1554 | +1555 | +1556 | +1557 | +1558 | +1559 | +1560 | +1561 | +1562 | +1563 | +1564 | +1565 | +1566 | +1567 | +1568 | +1569 | +1570 | +1571 | +1572 | +1573 | +1574 | +1575 | +1576 | +1577 | +1578 | +1579 | +1580 | +1581 | +1582 | +1583 | +1584 | +1585 | +1586 | +1587 | +1588 | +1589 | +1590 | +1591 | +1592 | +1593 | +1594 | +1595 | +1596 | +1597 | +1598 | +1599 | +1600 | +1601 | +1602 | +1603 | +1604 | +1605 | +1606 | +1607 | +1608 | +1609 | +1610 | +1611 | +1612 | +1613 | +1614 | +1615 | +1616 | +1617 | +1618 | +1619 | +1620 | +1621 | +1622 | +1623 | +1624 | +1625 | +1626 | +1627 | +1628 | +1629 | +1630 | +1631 | +1632 | +1633 | +1634 | +1635 | +1636 | +1637 | +1638 | +1639 | +1640 | +1641 | +1642 | +1643 | +1644 | +1645 | +1646 | +1647 | +1648 | +1649 | +1650 | +1651 | +1652 | +1653 | +1654 | +1655 | +1656 | +1657 | +1658 | +1659 | +1660 | +1661 | +1662 | +1663 | +1664 | +1665 | +1666 | +1667 | +1668 | +1669 | +1670 | +1671 | +1672 | +1673 | +1674 | +1675 | +1676 | +1677 | +1678 | +1679 | +1680 | +1681 | +1682 | +1683 | +1684 | +1685 | +1686 | +1687 | +1688 | +1689 | +1690 | +1691 | +1692 | +1693 | +1694 | +1695 | +1696 | +1697 | +1698 | +1699 | +1700 | +1701 | +1702 | +1703 | +1704 | +1705 | +1706 | +1707 | +1708 | +1709 | +1710 | +1711 | +1712 | +1713 | +1714 | +1715 | +1716 | +1717 | +1718 | +1719 | +1720 | +1721 | +1722 | +1723 | +1724 | +1725 | +1726 | +1727 | +1728 | +1729 | +1730 | +1731 | +1732 | +1733 | +1734 | +1735 | +1736 | +1737 | +1738 | +1739 | +1740 | +1741 | +1742 | +1743 | +1744 | +1745 | +1746 | +1747 | +1748 | +1749 | +1750 | +1751 | +1752 | +1753 | +1754 | +1755 | +1756 | +1757 | +1758 | +1759 | +1760 | +1761 | +1762 | +1763 | +1764 | +1765 | +1766 | +1767 | +1768 | +1769 | +1770 | +1771 | +1772 | +1773 | +1774 | +1775 | +1776 | +1777 | +1778 | +1779 | +1780 | +1781 | +1782 | +1783 | +1784 | +1785 | +1786 | +1787 | +1788 | +1789 | +1790 | +1791 | +1792 | +1793 | +1794 | +1795 | +1796 | +1797 | +1798 | +1799 | +1800 | +1801 | +1802 | +1803 | +1804 | +1805 | +1806 | +1807 | +1808 | +1809 | +1810 | +1811 | +1812 | +1813 | +1814 | +1815 | +1816 | +1817 | +1818 | +1819 | +1820 | +1821 | +1822 | +1823 | +1824 | +1825 | +1826 | +1827 | +1828 | +1829 | +1830 | +1831 | +1832 | +1833 | +1834 | +1835 | +1836 | +1837 | +1838 | +1839 | +1840 | +1841 | +1842 | +1843 | +1844 | +1845 | +1846 | +1847 | +1848 | +1849 | +1850 | +1851 | +1852 | +1853 | +1854 | +1855 | +1856 | +1857 | +1858 | +1859 | +1860 | +1861 | +1862 | +1863 | +1864 | +1865 | +1866 | +1867 | +1868 | +1869 | +1870 | +1871 | +1872 | +1873 | +1874 | +1875 | +1876 | +1877 | +1878 | +1879 | +1880 | +1881 | +1882 | +1883 | +1884 | +1885 | +1886 | +1887 | +1888 | +1889 | +1890 | +1891 | +1892 | +1893 | +1894 | +1895 | +1896 | +1897 | +1898 | +1899 | +1900 | +1901 | +1902 | +1903 | +1904 | +1905 | +1906 | +1907 | +1908 | +1909 | +1910 | +1911 | +1912 | +1913 | +1914 | +1915 | +1916 | +1917 | +1918 | +1919 | +1920 | +1921 | +1922 | +1923 | +1924 | +1925 | +1926 | +1927 | +1928 | +1929 | +1930 | +1931 | +1932 | +1933 | +1934 | +1935 | +1936 | +1937 | +1938 | +1939 | +1940 | +1941 | +1942 | +1943 | +1944 | +1945 | +1946 | +1947 | +1948 | +1949 | +1950 | +1951 | +1952 | +1953 | +1954 | +1955 | +1956 | +1957 | +1958 | +1959 | +1960 | +1961 | +1962 | +1963 | +1964 | +1965 | +1966 | +1967 | +1968 | +1969 | +1970 | +1971 | +1972 | +1973 | +1974 | +1975 | +1976 | +1977 | +1978 | +1979 | +1980 | +1981 | +1982 | +1983 | +1984 | +1985 | +1986 | +1987 | +1988 | +1989 | +1990 | +1991 | +1992 | +1993 | +1994 | +1995 | +1996 | +1997 | +1998 | +1999 | +2000 | +2001 | +2002 | +2003 | +2004 | +2005 | +2006 | +2007 | +2008 | +2009 | +2010 | +2011 | +2012 | +2013 | +2014 | +2015 | +2016 | +2017 | +2018 | +2019 | +2020 | +2021 | +2022 | +2023 | +2024 | +2025 | +2026 | +2027 | +2028 | +2029 | +2030 | +2031 | +2032 | +2033 | +2034 | +2035 | +2036 | +2037 | +2038 | +2039 | +2040 | +2041 | +2042 | +2043 | +2044 | +2045 | +2046 | +2047 | +2048 | +2049 | +2050 | +2051 | +2052 | +2053 | +2054 | +2055 | +2056 | +2057 | +2058 | +2059 | +2060 | +2061 | +2062 | +2063 | +2064 | +2065 | +2066 | +2067 | +2068 | +2069 | +2070 | +2071 | +2072 | +2073 | +2074 | +2075 | +2076 | +2077 | +2078 | +2079 | +2080 | +2081 | +2082 | +2083 | +2084 | +2085 | +2086 | +2087 | +2088 | +2089 | +2090 | +2091 | +2092 | +2093 | +2094 | +2095 | +2096 | +2097 | +2098 | +2099 | +2100 | +2101 | +2102 | +2103 | +2104 | +2105 | +2106 | +2107 | +2108 | +2109 | +2110 | +2111 | +2112 | +2113 | +2114 | +2115 | +2116 | +2117 | +2118 | +2119 | +2120 | +2121 | +2122 | +2123 | +2124 | +2125 | +2126 | +2127 | +2128 | +2129 | +2130 | +2131 | +2132 | +2133 | +2134 | +2135 | +2136 | +2137 | +2138 | +2139 | +2140 | +2141 | +2142 | +2143 | +2144 | +2145 | +2146 | +2147 | +2148 | +2149 | +2150 | +2151 | +2152 | +2153 | +2154 | +2155 | +2156 | +2157 | +2158 | +2159 | +2160 | +2161 | +2162 | +2163 | +2164 | +2165 | +2166 | +2167 | +2168 | +2169 | +2170 | +2171 | +2172 | +2173 | +2174 | +2175 | +2176 | +2177 | +2178 | +2179 | +2180 | +2181 | +2182 | +2183 | +2184 | +2185 | +2186 | +2187 | +2188 | +2189 | +2190 | +2191 | +2192 | +2193 | +2194 | +2195 | +2196 | +2197 | +2198 | +2199 | +2200 | +2201 | +2202 | +2203 | +2204 | +2205 | +2206 | +2207 | +2208 | +2209 | +2210 | +2211 | +2212 | +2213 | +2214 | +2215 | +2216 | +2217 | +2218 | +2219 | +2220 | +2221 | +2222 | +2223 | +2224 | +2225 | +2226 | +2227 | +2228 | +2229 | +2230 | +2231 | +2232 | +2233 | +2234 | +2235 | +2236 | +2237 | +2238 | +2239 | +2240 | +2241 | +2242 | +2243 | +2244 | +2245 | +2246 | +2247 | +2248 | +2249 | +2250 | +2251 | +2252 | +2253 | +2254 | +2255 | +2256 | +2257 | +2258 | +2259 | +2260 | +2261 | +2262 | +2263 | +2264 | +2265 | +2266 | +2267 | +2268 | +2269 | +2270 | +2271 | +2272 | +2273 | +2274 | +2275 | +2276 | +2277 | +2278 | +2279 | +2280 | +2281 | +2282 | +2283 | +2284 | +2285 | +2286 | +2287 | +2288 | +2289 | +2290 | +2291 | +2292 | +2293 | +2294 | +2295 | +2296 | +2297 | +2298 | +2299 | +2300 | +2301 | +2302 | +2303 | +2304 | +2305 | +2306 | +2307 | +2308 | +2309 | +2310 | +2311 | +2312 | +2313 | +2314 | +2315 | +2316 | +2317 | +2318 | +2319 | +2320 | +2321 | +2322 | +2323 | +2324 | +2325 | +2326 | +2327 | +2328 | +2329 | +2330 | +2331 | +2332 | +2333 | +2334 | +2335 | +2336 | +2337 | +2338 | +2339 | +2340 | +2341 | +2342 | +2343 | +2344 | +2345 | +2346 | +2347 | +2348 | +2349 | +2350 | +2351 | +2352 | +2353 | +2354 | +2355 | +2356 | +2357 | +2358 | +2359 | +2360 | +2361 | +2362 | +2363 | +2364 | +2365 | +2366 | +2367 | +2368 | +2369 | +2370 | +2371 | +2372 | +2373 | +2374 | +2375 | +2376 | +2377 | +2378 | +2379 | +2380 | +2381 | +2382 | +2383 | +2384 | +2385 | +2386 | +2387 | +2388 | +2389 | +2390 | +2391 | +2392 | +2393 | +2394 | +2395 | +2396 | +2397 | +2398 | +2399 | +2400 | +2401 | +2402 | +2403 | +2404 | +2405 | +2406 | +2407 | +2408 | +2409 | +2410 | +2411 | +2412 | +2413 | +2414 | +2415 | +2416 | +2417 | +2418 | +2419 | +2420 | +2421 | +2422 | +2423 | +2424 | +2425 | +2426 | +2427 | +2428 | +2429 | +2430 | +2431 | +2432 | +2433 | +2434 | +2435 | +2436 | +2437 | +2438 | +2439 | +2440 | +2441 | +2442 | +2443 | +2444 | +2445 | +2446 | +2447 | +2448 | +2449 | +2450 | +2451 | +2452 | +2453 | +2454 | +2455 | +2456 | +2457 | +2458 | +2459 | +2460 | +2461 | +2462 | +2463 | +2464 | +2465 | +2466 | +2467 | +2468 | +2469 | +2470 | +2471 | +2472 | +2473 | +2474 | +2475 | +2476 | +2477 | +2478 | +2479 | +2480 | +2481 | +2482 | +2483 | +2484 | +2485 | +2486 | +2487 | +2488 | +2489 | +2490 | +2491 | +2492 | +2493 | +2494 | +2495 | +2496 | +2497 | +2498 | +2499 | +2500 | +2501 | +2502 | +2503 | +2504 | +2505 | +2506 | +2507 | +2508 | +2509 | +2510 | +2511 | +2512 | +2513 | +2514 | +2515 | +2516 | +2517 | +2518 | +2519 | +2520 | +2521 | +2522 | +2523 | +2524 | +2525 | +2526 | +2527 | +2528 | +2529 | +2530 | +2531 | +2532 | +2533 | +2534 | +2535 | +2536 | +2537 | +2538 | +2539 | +2540 | +2541 | +2542 | +2543 | +2544 | +2545 | +2546 | +2547 | +2548 | +2549 | +2550 | +2551 | +2552 | +2553 | +2554 | +2555 | +2556 | +2557 | +2558 | +2559 | +2560 | +2561 | +2562 | +2563 | +2564 | +2565 | +2566 | +2567 | +2568 | +2569 | +2570 | +2571 | +2572 | +2573 | +2574 | +2575 | +2576 | +2577 | +2578 | +2579 | +2580 | +2581 | +2582 | +2583 | +2584 | +2585 | +2586 | +2587 | +2588 | +2589 | +2590 | +2591 | +2592 | +2593 | +2594 | +2595 | +2596 | +2597 | +2598 | +2599 | +2600 | +2601 | +2602 | +2603 | +2604 | +2605 | +2606 | +2607 | +2608 | +2609 | +2610 | +2611 | +2612 | +2613 | +2614 | +2615 | +2616 | +2617 | +2618 | +2619 | +2620 | +2621 | +2622 | +2623 | +2624 | +2625 | +2626 | +2627 | +2628 | +2629 | +2630 | +2631 | +2632 | +2633 | +2634 | +2635 | +2636 | +2637 | +2638 | +2639 | +2640 | +2641 | +2642 | +2643 | +2644 | +2645 | +2646 | +2647 | +2648 | +2649 | +2650 | +2651 | +2652 | +2653 | +2654 | +2655 | +2656 | +2657 | +2658 | +2659 | +2660 | +2661 | +2662 | +2663 | +2664 | +2665 | +2666 | +2667 | +2668 | +2669 | +2670 | +2671 | +2672 | +2673 | +2674 | +2675 | +2676 | +2677 | +2678 | +2679 | +2680 | +2681 | +2682 | +2683 | +2684 | +2685 | +2686 | +2687 | +2688 | +2689 | +2690 | +2691 | +2692 | +2693 | +2694 | +2695 | +2696 | +2697 | +2698 | +2699 | +2700 | +2701 | +2702 | +2703 | +2704 | +2705 | +2706 | +2707 | +2708 | +2709 | +2710 | +2711 | +2712 | +2713 | +2714 | +2715 | +2716 | +2717 | +2718 | +2719 | +2720 | +2721 | +2722 | +2723 | +2724 | +2725 | +2726 | +2727 | +2728 | +2729 | +2730 | +2731 | +2732 | +2733 | +2734 | +2735 | +2736 | +2737 | +2738 | +2739 | +2740 | +2741 | +2742 | +2743 | +2744 | +2745 | +2746 | +2747 | +2748 | +2749 | +2750 | +2751 | +2752 | +2753 | +2754 | +2755 | +2756 | +2757 | +2758 | +2759 | +2760 | +2761 | +2762 | +2763 | +2764 | +2765 | +2766 | +2767 | +2768 | +2769 | +2770 | +2771 | +2772 | +2773 | +2774 | +2775 | +2776 | +2777 | +2778 | +2779 | +2780 | +2781 | +2782 | +2783 | +2784 | +2785 | +2786 | +2787 | +2788 | +2789 | +2790 | +2791 | +2792 | +2793 | +2794 | +2795 | +2796 | +2797 | +2798 | +2799 | +2800 | +2801 | +2802 | +2803 | +2804 | +2805 | +2806 | +2807 | +2808 | +2809 | +2810 | +2811 | +2812 | +2813 | +2814 | +2815 | +2816 | +2817 | +2818 | +2819 | +2820 | +2821 | +2822 | +2823 | +2824 | +2825 | +2826 | +2827 | +2828 | +2829 | +2830 | +2831 | +2832 | +2833 | +2834 | +2835 | +2836 | +2837 | +2838 | +2839 | +2840 | +2841 | +2842 | +2843 | +2844 | +2845 | +2846 | +2847 | +2848 | +2849 | +2850 | +2851 | +2852 | +2853 | +2854 | +2855 | +2856 | +2857 | +2858 | +2859 | +2860 | +2861 | +2862 | +2863 | +2864 | +2865 | +2866 | +2867 | +2868 | +2869 | +2870 | +2871 | +2872 | +2873 | +2874 | +2875 | +2876 | +2877 | +2878 | +2879 | +2880 | +2881 | +2882 | +2883 | +2884 | +2885 | +2886 | +2887 | +2888 | +2889 | +2890 | +2891 | +2892 | +2893 | +2894 | +2895 | +2896 | +2897 | +2898 | +2899 | +2900 | +2901 | +2902 | +2903 | +2904 | +2905 | +2906 | +2907 | +2908 | +2909 | +2910 | +2911 | +2912 | +2913 | +2914 | +2915 | +2916 | +2917 | +2918 | +2919 | +2920 | +2921 | +2922 | +2923 | +2924 | +2925 | +2926 | +2927 | +2928 | +2929 | +2930 | +2931 | +2932 | +2933 | +2934 | +2935 | +2936 | +2937 | +2938 | +2939 | +2940 | +2941 | +2942 | +2943 | +2944 | +2945 | +2946 | +2947 | +2948 | +2949 | +2950 | +2951 | +2952 | +2953 | +2954 | +2955 | +2956 | +2957 | +2958 | +2959 | +2960 | +2961 | +2962 | +2963 | +2964 | +2965 | +2966 | +2967 | +2968 | +2969 | +2970 | +2971 | +2972 | +2973 | +2974 | +2975 | +2976 | +2977 | +2978 | +2979 | +2980 | +2981 | +2982 | +2983 | +2984 | +2985 | +2986 | +2987 | +2988 | +2989 | +2990 | +2991 | +2992 | +2993 | +2994 | +2995 | +2996 | +2997 | +2998 | +2999 | +3000 | +3001 | +3002 | +3003 | +3004 | +3005 | +3006 | +3007 | +3008 | +3009 | +3010 | +3011 | +3012 | +3013 | +3014 | +3015 | +3016 | +3017 | +3018 | +3019 | +3020 | +3021 | +3022 | +3023 | +3024 | +3025 | +3026 | +3027 | +3028 | +3029 | +3030 | +3031 | +3032 | +3033 | +3034 | +3035 | +3036 | +3037 | +3038 | +3039 | +3040 | +3041 | +3042 | +3043 | +3044 | +3045 | +3046 | +3047 | +3048 | +3049 | +3050 | +3051 | +3052 | +3053 | +3054 | +3055 | +3056 | +3057 | +3058 | +3059 | +3060 | +3061 | +3062 | +3063 | +3064 | +3065 | +3066 | +3067 | +3068 | +3069 | +3070 | +3071 | +3072 | +3073 | +3074 | +3075 | +3076 | +3077 | +3078 | +3079 | +3080 | +3081 | +3082 | +3083 | +3084 | +3085 | +3086 | +3087 | +3088 | +3089 | +3090 | +3091 | +3092 | +3093 | +3094 | +3095 | +3096 | +3097 | +3098 | +3099 | +3100 | +3101 | +3102 | +3103 | +3104 | +3105 | +3106 | +3107 | +3108 | +3109 | +3110 | +3111 | +3112 | +3113 | +3114 | +3115 | +3116 | +3117 | +3118 | +3119 | +3120 | +3121 | +3122 | +3123 | +3124 | +3125 | +3126 | +3127 | +3128 | +3129 | +3130 | +3131 | +3132 | +3133 | +3134 | +3135 | +3136 | +3137 | +3138 | +3139 | +3140 | +3141 | +3142 | +3143 | +3144 | +3145 | +3146 | +3147 | +3148 | +3149 | +3150 | +3151 | +3152 | +3153 | +3154 | +3155 | +3156 | +3157 | +3158 | +3159 | +3160 | +3161 | +3162 | +3163 | +3164 | +3165 | +3166 | +3167 | +3168 | +3169 | +3170 | +3171 | +3172 | +3173 | +3174 | +3175 | +3176 | +3177 | +3178 | +3179 | +3180 | +3181 | +3182 | +3183 | +3184 | +3185 | +3186 | +3187 | +3188 | +3189 | +3190 | +3191 | +3192 | +3193 | +3194 | +3195 | +3196 | +3197 | +3198 | +3199 | +3200 | +3201 | +3202 | +3203 | +3204 | +3205 | +3206 | +3207 | +3208 | +3209 | +3210 | +3211 | +3212 | +3213 | +3214 | +3215 | +3216 | +3217 | +3218 | +3219 | +3220 | +3221 | +3222 | +3223 | +3224 | +3225 | +3226 | +3227 | +3228 | +3229 | +3230 | +3231 | +3232 | +3233 | +3234 | +3235 | +3236 | +3237 | +3238 | +3239 | +3240 | +3241 | +3242 | +3243 | +3244 | +3245 | +3246 | +3247 | +3248 | +3249 | +3250 | +3251 | +3252 | +3253 | +3254 | +3255 | +3256 | +3257 | +3258 | +3259 | +3260 | +3261 | +3262 | +3263 | +3264 | +3265 | +3266 | +3267 | +3268 | +3269 | +3270 | +3271 | +3272 | +3273 | +3274 | +3275 | +3276 | +3277 | +3278 | +3279 | +3280 | +3281 | +3282 | +3283 | +3284 | +3285 | +3286 | +3287 | +3288 | +3289 | +3290 | +3291 | +3292 | +3293 | +3294 | +3295 | +3296 | +3297 | +3298 | +3299 | +3300 | +3301 | +3302 | +3303 | +3304 | +3305 | +3306 | +3307 | +3308 | +3309 | +3310 | +3311 | +3312 | +3313 | +3314 | +3315 | +3316 | +3317 | +3318 | +3319 | +3320 | +3321 | +3322 | +3323 | +3324 | +3325 | +3326 | +3327 | +3328 | +3329 | +3330 | +3331 | +3332 | +3333 | +3334 | +3335 | +3336 | +3337 | +3338 | +3339 | +3340 | +3341 | +3342 | +3343 | +3344 | +3345 | +3346 | +3347 | +3348 | +3349 | +3350 | +3351 | +3352 | +3353 | +3354 | +3355 | +3356 | +3357 | +3358 | +3359 | +3360 | +3361 | +3362 | +3363 | +3364 | +3365 | +3366 | +3367 | +3368 | +3369 | +3370 | +3371 | +3372 | +3373 | +3374 | +3375 | +3376 | +3377 | +3378 | +3379 | +3380 | +3381 | +3382 | +3383 | +3384 | +3385 | +3386 | +3387 | +3388 | +3389 | +3390 | +3391 | +3392 | +3393 | +3394 | +3395 | +3396 | +3397 | +3398 | +3399 | +3400 | +3401 | +3402 | +3403 | +3404 | +3405 | +3406 | +3407 | +3408 | +3409 | +3410 | +3411 | +3412 | +3413 | +3414 | +3415 | +3416 | +3417 | +3418 | +3419 | +3420 | +3421 | +3422 | +3423 | +3424 | +3425 | +3426 | +3427 | +3428 | +3429 | +3430 | +3431 | +3432 | +3433 | +3434 | +3435 | +3436 | +3437 | +3438 | +3439 | +3440 | +3441 | +3442 | +3443 | +3444 | +3445 | +3446 | +3447 | +3448 | +3449 | +3450 | +3451 | +3452 | +3453 | +3454 | +3455 | +3456 | +3457 | +3458 | +3459 | +3460 | +3461 | +3462 | +3463 | +3464 | +3465 | +3466 | +3467 | +3468 | +3469 | +3470 | +3471 | +3472 | +3473 | +3474 | +3475 | +3476 | +3477 | +3478 | +3479 | +3480 | +3481 | +3482 | +3483 | +3484 | +3485 | +3486 | +3487 | +3488 | +3489 | +3490 | +3491 | +3492 | +3493 | +3494 | +3495 | +3496 | +3497 | +3498 | +3499 | +3500 | +3501 | +3502 | +3503 | +3504 | +3505 | +3506 | +3507 | +3508 | +3509 | +3510 | +3511 | +3512 | +3513 | +3514 | +3515 | +3516 | +3517 | +3518 | +3519 | +3520 | +3521 | +3522 | +3523 | +3524 | +3525 | +3526 | +3527 | +3528 | +3529 | +3530 | +3531 | +3532 | +3533 | +3534 | +3535 | +3536 | +3537 | +3538 | +3539 | +3540 | +3541 | +3542 | +3543 | +3544 | +3545 | +3546 | +3547 | +3548 | +3549 | +3550 | +3551 | +3552 | +3553 | +3554 | +3555 | +3556 | +3557 | +3558 | +3559 | +3560 | +3561 | +3562 | +3563 | +3564 | +3565 | +3566 | +3567 | +3568 | +3569 | +3570 | +3571 | +3572 | +3573 | +3574 | +3575 | +3576 | +3577 | +3578 | +3579 | +3580 | +3581 | +3582 | +3583 | +3584 | +3585 | +3586 | +3587 | +3588 | +3589 | +3590 | +3591 | +3592 | +3593 | +3594 | +3595 | +3596 | +3597 | +3598 | +3599 | +3600 | +3601 | +3602 | +3603 | +3604 | +3605 | +3606 | +3607 | +3608 | +3609 | +3610 | +3611 | +3612 | +3613 | +3614 | +3615 | +3616 | +3617 | +3618 | +3619 | +3620 | +3621 | +3622 | +3623 | +3624 | +3625 | +3626 | +3627 | +3628 | +3629 | +3630 | +3631 | +3632 | +3633 | +3634 | +3635 | +3636 | +3637 | +3638 | +3639 | +3640 | +3641 | +3642 | +3643 | +3644 | +3645 | +3646 | +3647 | +3648 | +3649 | +3650 | +3651 | +3652 | +3653 | +3654 | +3655 | +3656 | +3657 | +3658 | +3659 | +3660 | +3661 | +3662 | +3663 | +3664 | +3665 | +3666 | +3667 | +3668 | +3669 | +3670 | +3671 | +3672 | +3673 | +3674 | +3675 | +3676 | +3677 | +3678 | +3679 | +3680 | +3681 | +3682 | +3683 | +3684 | +3685 | +3686 | +3687 | +3688 | +3689 | +3690 | +3691 | +3692 | +3693 | +3694 | +3695 | +3696 | +3697 | +3698 | +3699 | +3700 | +3701 | +3702 | +3703 | +3704 | +3705 | +3706 | +3707 | +3708 | +3709 | +3710 | +3711 | +3712 | +3713 | +3714 | +3715 | +3716 | +3717 | +3718 | +3719 | +3720 | +3721 | +3722 | +3723 | +3724 | +3725 | +3726 | +3727 | +3728 | +3729 | +3730 | +3731 | +3732 | +3733 | +3734 | +3735 | +3736 | +3737 | +3738 | +3739 | +3740 | +3741 | +3742 | +3743 | +3744 | +3745 | +3746 | +3747 | +3748 | +3749 | +3750 | +3751 | +3752 | +3753 | +3754 | +3755 | +3756 | +3757 | +3758 | +3759 | +3760 | +3761 | +3762 | +3763 | +3764 | +3765 | +3766 | +3767 | +3768 | +3769 | +3770 | +3771 | +3772 | +3773 | +3774 | +3775 | +3776 | +3777 | +3778 | +3779 | +3780 | +3781 | +3782 | +3783 | +3784 | +3785 | +3786 | +3787 | +3788 | +3789 | +3790 | +3791 | +3792 | +3793 | +3794 | +3795 | +3796 | +3797 | +3798 | +3799 | +3800 | +3801 | +3802 | +3803 | +3804 | +3805 | +3806 | +3807 | +3808 | +3809 | +3810 | +3811 | +3812 | +3813 | +3814 | +3815 | +3816 | +3817 | +3818 | +3819 | +3820 | +3821 | +3822 | +3823 | +3824 | +3825 | +3826 | +3827 | +3828 | +3829 | +3830 | +3831 | +3832 | +3833 | +3834 | +3835 | +3836 | +3837 | +3838 | +3839 | +3840 | +3841 | +3842 | +3843 | +3844 | +3845 | +3846 | +3847 | +3848 | +3849 | +3850 | +3851 | +3852 | +3853 | +3854 | +3855 | +3856 | +3857 | +3858 | +3859 | +3860 | +3861 | +3862 | +3863 | +3864 | +3865 | +3866 | +3867 | +3868 | +3869 | +3870 | +3871 | +3872 | +3873 | +3874 | +3875 | +3876 | +3877 | +3878 | +3879 | +3880 | +3881 | +3882 | +3883 | +3884 | +3885 | +3886 | +3887 | +3888 | +3889 | +3890 | +3891 | +3892 | +3893 | +3894 | +3895 | +3896 | +3897 | +3898 | +3899 | +3900 | +3901 | +3902 | +3903 | +3904 | +3905 | +3906 | +3907 | +3908 | +3909 | +3910 | +3911 | +3912 | +3913 | +3914 | +3915 | +3916 | +3917 | +3918 | +3919 | +3920 | +3921 | +3922 | +3923 | +3924 | +3925 | +3926 | +3927 | +3928 | +3929 | +3930 | +3931 | +3932 | +3933 | +3934 | +3935 | +3936 | +3937 | +3938 | +3939 | +3940 | +3941 | +3942 | +3943 | +3944 | +3945 | +3946 | +3947 | +3948 | +3949 | +3950 | +3951 | +3952 | +3953 | +3954 | +3955 | +3956 | +3957 | +3958 | +3959 | +3960 | +3961 | +3962 | +3963 | +3964 | +3965 | +3966 | +3967 | +3968 | +3969 | +3970 | +3971 | +3972 | +3973 | +3974 | +3975 | +3976 | +3977 | +3978 | +3979 | +3980 | +3981 | +3982 | +3983 | +3984 | +3985 | +3986 | +3987 | +3988 | +3989 | +3990 | +3991 | +3992 | +3993 | +3994 | +3995 | +3996 | +3997 | +3998 | +3999 | +4000 | +4001 | +4002 | +4003 | +4004 | +4005 | +4006 | +4007 | +4008 | +4009 | +4010 | +4011 | +4012 | +4013 | +4014 | +4015 | +4016 | +4017 | +4018 | +4019 | +4020 | +4021 | +4022 | +4023 | +4024 | +4025 | +4026 | +4027 | +4028 | +4029 | +4030 | +4031 | +4032 | +4033 | +4034 | +4035 | +4036 | +4037 | +4038 | +4039 | +4040 | +4041 | +4042 | +4043 | +4044 | +4045 | +4046 | +4047 | +4048 | +4049 | +4050 | +4051 | +4052 | +4053 | +4054 | +4055 | +4056 | +4057 | +4058 | +4059 | +4060 | +4061 | +4062 | +4063 | +4064 | +4065 | +4066 | +4067 | +4068 | +4069 | +4070 | +4071 | +4072 | +4073 | +4074 | +4075 | +4076 | +4077 | +4078 | +4079 | +4080 | +4081 | +4082 | +4083 | +4084 | +4085 | +4086 | +4087 | +4088 | +4089 | +4090 | +4091 | +4092 | +4093 | +4094 | +4095 | +4096 | +4097 | +4098 | +4099 | +4100 | +4101 | +4102 | +4103 | +4104 | +4105 | +4106 | +4107 | +4108 | +4109 | +4110 | +4111 | +4112 | +4113 | +4114 | +4115 | +4116 | +4117 | +4118 | +4119 | +4120 | +4121 | +4122 | +4123 | +4124 | +4125 | +4126 | +4127 | +4128 | +4129 | +4130 | +4131 | +4132 | +4133 | +4134 | +4135 | +4136 | +4137 | +4138 | +4139 | +4140 | +4141 | +4142 | +4143 | +4144 | +4145 | +4146 | +4147 | +4148 | +4149 | +4150 | +4151 | +4152 | +4153 | +4154 | +4155 | +4156 | +4157 | +4158 | +4159 | +4160 | +4161 | +4162 | +4163 | +4164 | +4165 | +4166 | +4167 | +4168 | +4169 | +4170 | +4171 | +4172 | +4173 | +4174 | +4175 | +4176 | +4177 | +4178 | +4179 | +4180 | +4181 | +4182 | +4183 | +4184 | +4185 | +4186 | +4187 | +4188 | +4189 | +4190 | +4191 | +4192 | +4193 | +4194 | +4195 | +4196 | +4197 | +4198 | +4199 | +4200 | +4201 | +4202 | +4203 | +4204 | +4205 | +4206 | +4207 | +4208 | +4209 | +4210 | +4211 | +4212 | +4213 | +4214 | +4215 | +4216 | +4217 | +4218 | +4219 | +4220 | +4221 | +4222 | +4223 | +4224 | +4225 | +4226 | +4227 | +4228 | +4229 | +4230 | +4231 | +4232 | +4233 | +4234 | +4235 | +4236 | +4237 | +4238 | +4239 | +4240 | +4241 | +4242 | +4243 | +4244 | +4245 | +4246 | +4247 | +4248 | +4249 | +4250 | +4251 | +4252 | +4253 | +4254 | +4255 | +4256 | +4257 | +4258 | +4259 | +4260 | +4261 | +4262 | +4263 | +4264 | +4265 | +4266 | +4267 | +4268 | +4269 | +4270 | +4271 | +4272 | +4273 | +4274 | +4275 | +4276 | +4277 | +4278 | +4279 | +4280 | +4281 | +4282 | +4283 | +4284 | +4285 | +4286 | +4287 | +4288 | +4289 | +4290 | +4291 | +4292 | +4293 | +4294 | +4295 | +4296 | +4297 | +4298 | +4299 | +4300 | +4301 | +4302 | +4303 | +4304 | +4305 | +4306 | +4307 | +4308 | +4309 | +4310 | +4311 | +4312 | +4313 | +4314 | +4315 | +4316 | +4317 | +4318 | +4319 | +4320 | +4321 | +4322 | +4323 | +4324 | +4325 | +4326 | +4327 | +4328 | +4329 | +4330 | +4331 | +4332 | +4333 | +4334 | +4335 | +4336 | +4337 | +4338 | +4339 | +4340 | +4341 | +4342 | +4343 | +4344 | +4345 | +4346 | +4347 | +4348 | +4349 | +4350 | +4351 | +4352 | +4353 | +4354 | +4355 | +4356 | +4357 | +4358 | +4359 | +4360 | +4361 | +4362 | +4363 | +4364 | +4365 | +4366 | +4367 | +4368 | +4369 | +4370 | +4371 | +4372 | +4373 | +4374 | +4375 | +4376 | +4377 | +4378 | +4379 | +4380 | +4381 | +4382 | +4383 | +4384 | +4385 | +4386 | +4387 | +4388 | +4389 | +4390 | +4391 | +4392 | +4393 | +4394 | +4395 | +4396 | +4397 | +4398 | +4399 | +4400 | +4401 | +4402 | +4403 | +4404 | +4405 | +4406 | +4407 | +4408 | +4409 | +4410 | +4411 | +4412 | +4413 | +4414 | +4415 | +4416 | +4417 | +4418 | +4419 | +4420 | +4421 | +4422 | +4423 | +4424 | +4425 | +4426 | +4427 | +4428 | +4429 | +4430 | +4431 | +4432 | +4433 | +4434 | +4435 | +4436 | +4437 | +4438 | +4439 | +4440 | +4441 | +4442 | +4443 | +4444 | +4445 | +4446 | +4447 | +4448 | +4449 | +4450 | +4451 | +4452 | +4453 | +4454 | +4455 | +4456 | +4457 | +4458 | +4459 | +4460 | +4461 | +4462 | +4463 | +4464 | +4465 | +4466 | +4467 | +4468 | +4469 | +4470 | +4471 | +4472 | +4473 | +4474 | +4475 | +4476 | +4477 | +4478 | +4479 | +4480 | +4481 | +4482 | +4483 | +4484 | +4485 | +4486 | +4487 | +4488 | +4489 | +4490 | +4491 | +4492 | +4493 | +4494 | +4495 | +4496 | +4497 | +4498 | +4499 | +4500 | +4501 | +4502 | +4503 | +4504 | +4505 | +4506 | +4507 | +4508 | +4509 | +4510 | +4511 | +4512 | +4513 | +4514 | +4515 | +4516 | +4517 | +4518 | +4519 | +4520 | +4521 | +4522 | +4523 | +4524 | +4525 | +4526 | +4527 | +4528 | +4529 | +4530 | +4531 | +4532 | +4533 | +4534 | +4535 | +4536 | +4537 | +4538 | +4539 | +4540 | +4541 | +4542 | +4543 | +4544 | +4545 | +4546 | +4547 | +4548 | +4549 | +4550 | +4551 | +4552 | +4553 | +4554 | +4555 | +4556 | +4557 | +4558 | +4559 | +4560 | +4561 | +4562 | +4563 | +4564 | +4565 | +4566 | +4567 | +4568 | +4569 | +4570 | +4571 | +4572 | +4573 | +4574 | +4575 | +4576 | +4577 | +4578 | +4579 | +4580 | +4581 | +4582 | +4583 | +4584 | +4585 | +4586 | +4587 | +4588 | +4589 | +4590 | +4591 | +4592 | +4593 | +4594 | +4595 | +4596 | +4597 | +4598 | +4599 | +4600 | +4601 | +4602 | +4603 | +4604 | +4605 | +4606 | +4607 | +4608 | +4609 | +4610 | +4611 | +4612 | +4613 | +4614 | +4615 | +4616 | +4617 | +4618 | +4619 | +4620 | +4621 | +4622 | +4623 | +4624 | +4625 | +4626 | +4627 | +4628 | +4629 | +4630 | +4631 | +4632 | +4633 | +4634 | +4635 | +4636 | +4637 | +4638 | +4639 | +4640 | +4641 | +4642 | +4643 | +4644 | +4645 | +4646 | +4647 | +4648 | +4649 | +4650 | +4651 | +4652 | +4653 | +4654 | +4655 | +4656 | +4657 | +4658 | +4659 | +4660 | +4661 | +4662 | +4663 | +4664 | +4665 | +4666 | +4667 | +4668 | +4669 | +4670 | +4671 | +4672 | +4673 | +4674 | +4675 | +4676 | +4677 | +4678 | +4679 | +4680 | +4681 | +4682 | +4683 | +4684 | +4685 | +4686 | +4687 | +4688 | +4689 | +4690 | +4691 | +4692 | +4693 | +4694 | +4695 | +4696 | +4697 | +4698 | +4699 | +4700 | +4701 | +4702 | +4703 | +4704 | +4705 | +4706 | +4707 | +4708 | +4709 | +4710 | +4711 | +4712 | +4713 | +4714 | +4715 | +4716 | +4717 | +4718 | +4719 | +4720 | +4721 | +4722 | +4723 | +4724 | +4725 | +4726 | +4727 | +4728 | +4729 | +4730 | +4731 | +4732 | +4733 | +4734 | +4735 | +4736 | +4737 | +4738 | +4739 | +4740 | +4741 | +4742 | +4743 | +4744 | +4745 | +4746 | +4747 | +4748 | +4749 | +4750 | +4751 | +4752 | +4753 | +4754 | +4755 | +4756 | +4757 | +4758 | +4759 | +4760 | +4761 | +4762 | +4763 | +4764 | +4765 | +4766 | +4767 | +4768 | +4769 | +4770 | +4771 | +4772 | +4773 | +4774 | +4775 | +4776 | +4777 | +4778 | +4779 | +4780 | +4781 | +4782 | +4783 | +4784 | +4785 | +4786 | +4787 | +4788 | +4789 | +4790 | +4791 | +4792 | +4793 | +4794 | +4795 | +4796 | +4797 | +4798 | +4799 | +4800 | +4801 | +4802 | +4803 | +4804 | +4805 | +4806 | +4807 | +4808 | +4809 | +4810 | +4811 | +4812 | +4813 | +4814 | +4815 | +4816 | +4817 | +4818 | +4819 | +4820 | +4821 | +4822 | +4823 | +4824 | +4825 | +4826 | +4827 | +4828 | +4829 | +4830 | +4831 | +4832 | +4833 | +4834 | +4835 | +4836 | +4837 | +4838 | +4839 | +4840 | +4841 | +4842 | +4843 | +4844 | +4845 | +4846 | +4847 | +4848 | +4849 | +4850 | +4851 | +4852 | +4853 | +4854 | +4855 | +4856 | +4857 | +4858 | +4859 | +4860 | +4861 | +4862 | +4863 | +4864 | +4865 | +4866 | +4867 | +4868 | +4869 | +4870 | +4871 | +4872 | +4873 | +4874 | +4875 | +4876 | +4877 | +4878 | +4879 | +4880 | +4881 | +4882 | +4883 | +4884 | +4885 | +4886 | +4887 | +4888 | +4889 | +4890 | +4891 | +4892 | +4893 | +4894 | +4895 | +4896 | +4897 | +4898 | +4899 | +4900 | +4901 | +4902 | +4903 | +4904 | +4905 | +4906 | +4907 | +4908 | +4909 | +4910 | +4911 | +4912 | +4913 | +4914 | +4915 | +4916 | +4917 | +4918 | +4919 | +4920 | +4921 | +4922 | +4923 | +4924 | +4925 | +4926 | +4927 | +4928 | +4929 | +4930 | +4931 | +4932 | +4933 | +4934 | +4935 | +4936 | +4937 | +4938 | +4939 | +4940 | +4941 | +4942 | +4943 | +4944 | +4945 | +4946 | +4947 | +4948 | +4949 | +4950 | +4951 | +4952 | +4953 | +4954 | +4955 | +4956 | +4957 | +4958 | +4959 | +4960 | +4961 | +4962 | +4963 | +4964 | +4965 | +4966 | +4967 | +4968 | +4969 | +4970 | +4971 | +4972 | +4973 | +4974 | +4975 | +4976 | +4977 | +4978 | +4979 | +4980 | +4981 | +4982 | +4983 | +4984 | +4985 | +4986 | +4987 | +4988 | +4989 | +4990 | +4991 | +4992 | +4993 | +4994 | +4995 | +4996 | +4997 | +4998 | +4999; + +type Data = { + error?: ErrorCode, +}; diff --git a/tests/union_new/__snapshots__/jsfmt.spec.js.snap b/tests/union_new/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..8c6fb30c46f7 --- /dev/null +++ b/tests/union_new/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,1768 @@ +exports[`test issue-815.js 1`] = ` +"/* @flow */ +type T = A|B; +class U {}; +declare var children: U; +(children: T|U); +class A {}; +class B {}; + +type VirtualElement = Thunk|VirtualNode; +type Child = VirtualElement; +type Children = Array; + + +class Thunk {} +class VirtualNode { + children: Child|Children; + constructor(type, children/*:Children*/) { + this.children = children.length === 1 ? children[0] : + children; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-824.js 1`] = ` +"import { B, C } from \"./issue-824-helper\"; + +type K = B | C; + +type I = { + which(): number; +}; + +export default class A { + static foo(p: K): bool { + return false; + } + static bar(p: I & K): bool { + return this.foo(p); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-824-helper.js 1`] = ` +"import A from \"./issue-824\"; + +export class B extends A { + which(): number { + return 1; + } +} +export class C extends A { + which(): number { + return 2; + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +import A from \"./issue-824\"; +export class B extends A { + which(): number { + return 1; + } +} +export class C extends A { + which(): number { + return 2; + } +} + +" +`; + +exports[`test issue-1349.js 1`] = ` +"/* @flow */ + +var bar: Array<{b: ?boolean, c: number} | {b: boolean}> = [ + {b: true, c: 123}, + {b: true} +]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1497:36) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1371.js 1`] = ` +"function create(a: any): { type: \'B\', data: number } | { type: \'A\', data: string } +{ + return { + type: \'A\', + data: a + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1455.js 1`] = ` +"/* @flow */ +import type {Foobar} from \"./issue-1455-helper\" + +function create(content: ?Foobar | String | Array) { +} + +function node(content: ?Foobar | String | Array) { + create(content) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1455-helper.js 1`] = ` +"/* @flow */ + +export class Foobar { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +export class Foobar {} + +" +`; + +exports[`test issue-1462-i.js 1`] = ` +"type Common = { +}; + +type A = Common & { + type: \'A\', + foo: number +}; + +type B = Common & { + type: \'B\', + foo: Array +} + +type MyType = A | B; + +function print(x: number) { + console.log(x); +} + +function printAll(val: MyType) { + print(val.foo); // <--- foo could be an array +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1462-ii.js 1`] = ` +"type Common = { +}; + +type A = { + type: \'A\', + foo: number +} & Common; + +type B = { + type: \'B\', + foo: Array +} & Common; + +type MyType = A | B; + + +function print(x: number) { + console.log(x); +} + +function printAll(val: MyType) { + if (val.type === \'A\') { + print(val.foo); + } else { + val.foo.forEach(print); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1664.js 1`] = ` +"/* @flow */ + +type DataBase = { + id: string, + name: string, +}; + +type UserData = DataBase & { + kind: \"user\", +}; + +type SystemData = DataBase & { + kind: \"system\", +} + +type Data = UserData | SystemData; + +const data: Data = { + id: \"\", + name: \"\", + kind: \"system\", +} + +if (data.kind === \"system\") { + (data: SystemData); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-1759.js 1`] = ` +"// @flow + +type X = ({a:true} & {b:string}) | ({a:false} & {c:string}); +//type X = {a:true, b:string} | {a:false, c:string}; // this works. + +function hello(x:X): string { + if (x.a === true) return x.b; else return x.c; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test issue-2232.js 1`] = ` +"/* @flow */ + +declare type Entity = { + id: T, + name: string +} + +declare type StringEntity = Entity + + +declare type Foo = StringEntity & { + bars: Object, + kind: 1 +} +declare type EmptyFoo = StringEntity & { + bars: null, + kind: 2 +} + +function test(f: Foo| EmptyFoo) { + if (f.kind === 1) { + (f: Foo) + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test1.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////////////// +// example with object types +////////////////////////////// + +function obj(a: A1 | A2) { + return a.x; +} + +const obj_result = obj({ x: \"\" }); // currently an error! (expect it to be OK) + +// Type definitions used above are defined below, but in an order that +// deliberately makes their full resolution as lazy as possible. The call above +// blocks until A1 is partially resolved. Since the argument partially matches +// A1, that branch is selected. Later, that branch errors, but other branches +// have been lost by then. + +type A1 = { x: B1 }; +type A2 = { x: B2 }; + +type B1 = number; +type B2 = string; + +(obj_result: B1 | B2); + +/////////////////////////////////////// +// similar example with function types +/////////////////////////////////////// + +function fun(a: A3 | A4) { + return a(); +} + +const fun_result = fun(() => \"\"); + +type A3 = () => B3; +type A4 = () => B4; + +type B3 = number; +type B4 = string; + +(fun_result: B3 | B4); + +///////////////////////////////////////////// +// similar example with class instance types +///////////////////////////////////////////// + +function inst(a: A5 | A6) { } + +class B5 { } +class B6 { } +inst([new B6]); + +type A5 = B5[]; +type A6 = B6[]; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test2.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////////////// +// example with object types +////////////////////////////// + +function obj(a: { x: number } | { x: string }) { } + +obj(({ x: \"\" }: A1)); + +type A1 = { x: B1 }; + +type B1 = string; + +/////////////////////////////////////// +// similar example with function types +/////////////////////////////////////// + +function fun(a: (() => number) | (() => string)) { } + +fun(((() => \"\"): A2)); + +type A2 = () => B2; + +type B2 = string; + +///////////////////////////////////////////////////// +// similar example with generic class instance types +///////////////////////////////////////////////////// + +class C { } + +function inst(a: C | C) { } + +inst((new C: A3)); + +type A3 = C; + +type B3 = string; + +///////////////////////////////////////////// +// similar example with generic type aliases +///////////////////////////////////////////// + +function alias(a: T | T) { } +alias({ x: (x: V) => { } }); + +type T = { x: U } +type U = (x: V) => void; +type V = X; + +type B4 = string; + +// class statics + +function stat(a: { x: number } | { x: string }) { } + +class D { + static x: B5; +} + +stat(D); + +type B5 = string; + +// tuples + +function tup(a: [number,boolean] | [string,boolean]) { } + +tup(([\"\",false]: A6)); + +type A6 = [B6,boolean]; +type B6 = string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test3.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +/////////////////////////////// +// example with function types +/////////////////////////////// + +function fun(a: ((x: number) => void) | ((x: string) => void)) { } + +fun((((x) => {}): A1)); + +type A1 = (x: B1) => void; + +type B1 = string; + +//////////////////////////// +// example with array types +//////////////////////////// + +function arr(a: number[] | string[]) { } + +arr(([]: A2)); + +type A2 = B2[]; + +type B2 = string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test4.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +/////////////////////////////// +// example with function types +/////////////////////////////// + +function fun(a: ((x: number) => void) | ((x: string) => void)) { } + +const a1 = ((x) => {}: A1); +fun(a1); + +function fun_call(x: string) { a1(x); } + +type A1 = (x: B1) => void; + +type B1 = string; + +//////////////////////////// +// example with array types +//////////////////////////// + +function arr(a: number[] | string[]) { } + +const a2 = ([]: A2); +arr(a2); + +function arr_set(x: string, i: number) { a2[i] = x; } +function arr_get(i: number): string { return a2[i]; } + +type A2 = B2[]; + +type B2 = string; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test5.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +/////////////////////////////// +// example with function types +/////////////////////////////// + +function fun(a: ((x: number) => number) | ((x: string) => string)) { } + +function a1(x) { return x; } +fun(a1); + +function fun_call(x: string): string { return a1(x); } + +///////////////////////////// +// example with array types +///////////////////////////// + +function arr(a: number[] | string[]) { } + +var a2 = []; +arr(a2); + +function arr_set(x: string, i: number) { a2[i] = x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test6.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////////////////////////// +// example with generic class inheritance +////////////////////////////////////////// + +function inst(a: E): C | C { return a; } + +const mk_C = () => C; +const mk_D = () => D; +const mk_E = () => E; + +type B4 = string; + +const _D = mk_D(); +class E extends _D { } + +const _C = mk_C(); +class D extends _C { } + +class C { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test7.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +//////////////////// +// recursive types +//////////////////// + +function rec(x: F1 | F2) { } +rec({ x: 0 }); + +type F1 = G1; +type F2 = G2; +type G1 = { x: H1, y?: G1 }; +type G2 = { x: H2, y?: G2 }; +type H1 = string; +type H2 = number; + +/////////////////////////////// +// polymorphic recursive types +/////////////////////////////// + +function polyrec(x: PF | PF) { } +rec({ x: 0 }); + +type PF = PG; +type PG = { x: X, y?: PG }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test8.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////// +// nested union types +////////////////////// + +function rec(x: F1 | F2) { } +rec({ x: 0 }); + +type F1 = G1 | G1_; +type F2 = G2 | G2_; +type G1 = { x: H1 }; +type G1_ = { x: H1_ }; +type G2 = { x: H2 }; +type G2_ = { x: H2_ }; +type H1 = boolean; +type H1_ = string; +type H2 = boolean; +type H2_ = number; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test9.js 1`] = ` +"// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +//////////////// +// interference +//////////////// + +function square(x? = 0) { + return x * x; +} + +function foo(f: ((_: ?number) => ?number) | (() => void)) { } +foo((x): number => square(x)) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test10.js 1`] = ` +"// @noflow + +function id(x: X): X { return x; } + +///////////////////////// +// primitive annotations +///////////////////////// + +function check_prim(_: number | string) { } + +// ok +check_prim(\"\"); + +// ...even when they \"flow\" in +check_prim(id(\"\")); + +////////////////////////////// +// class instance annotations +////////////////////////////// + +class C { } +class D { } +function check_inst(_: C | D) { } + +// ok +check_inst(new D); + +// ...even when they \"flow\" in +check_inst(id(new C)); + +//////////////////////// +// function annotations +//////////////////////// + +function check_fun(_: ((_: number) => number) | ((_: string) => string)) { } + +// help! +check_fun((x) => x); + +////////////////////// +// object annotations +////////////////////// + +function check_obj(_: { x: number } | { x: string }) { } + +// ok +check_obj({ x: \"\" }); + +// help! +check_obj({ x: id(\"\") }); + +///////////////////// +// array annotations +///////////////////// + +function check_arr(_: number[] | string[]) { } + +// ok +check_arr([\"\"]); + +// help! +check_arr([id(\"\")]); + +////////////////////////////////////// +// generic class instance annotations +////////////////////////////////////// + +class P { } +function check_poly_inst(_: P | P) { } + +// help! +check_poly_inst(new P); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test11.js 1`] = ` +"// @noflow + +// disjoint unions + +function length(list: List) { + if (list.kind === \"cons\") return length(list.next) + 1; + else return 0; +} + + +length({ kind: \"nil\" }); +length({ kind: \"cons\" }); // missing \`next\` +length({ kind: \"cons\", next: { kind: \"nil\" } }); +length({ kind: \"empty\" }); // \`kind\` not found + +type List = Nil | Cons; +type Nil = { kind: \"nil\" }; +type Cons = { kind: \"cons\", next: List }; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test12.js 1`] = ` +"// @noflow + +// polymorphic recursive types + +type F = { f: F, x: X } +type G = { x: number } +type H = { x: string } + +function rec(x: F): G | H { return x; } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test13.js 1`] = ` +"// @noflow + +/* ensure there are no unintended side effects when trying branches */ + +({type: \'B\', id: \'hi\'}: { + type: \'A\'; + id: ?string; +} | { + type: \'B\'; + id: string; +}); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test14.js 1`] = ` +"// @noflow + +// annotations + +declare class C { + get(): X; +} + +function union(o: { x: string } | { x: number }) { } + +function foo(c: C) { + union({ x: c.get() }); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test15.js 1`] = ` +"// @noflow + +// functions as objects + +function foo(target: EventTarget) { + target.addEventListener(\'click\', (e) => {}); +} + +declare class EventTarget { + addEventListener(type: \'foo\', listener: KeyboardEventHandler): void; + addEventListener(type: string, listener: EventHandler): void; +} + +declare class Event { } +declare class KeyboardEvent { } + +type EventHandler = (event: Event) => mixed +type KeyboardEventHandler = (event: KeyboardEvent) => mixed + +// example where globals are not yet resolved + +function bar(x: (() => void) | { x: number }) { } + +bar(() => { }); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test16.js 1`] = ` +"// @noflow + +// annotations + +type T = number | (() => string); +type Foo = T | (() => bool); + +type Bar = number | (() => string) | (() => bool); + +function foo(x: Foo) { } +foo(() => qux()); + +function bar(x: Bar) { } +bar(() => qux()); + +var x = false; +function qux() { return x; } +x = \"\"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test17.js 1`] = ` +"// @noflow + +// Array#concat + +[].concat([]); + +([].concat([0,1])[1]: string) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @noflow +// Array#concat +[ ].concat([ ]); +([ ].concat([ 0, 1 ])[1]: string); + +" +`; + +exports[`test test18.js 1`] = ` +"// @noflow + +// method overloads + +declare class C { + m(x: number): void; + m(x: string): void; +} + +function f() { return 0; } + +new C().m(f()); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test19.js 1`] = ` +"// @noflow + +// constructor overloads + +function m() { + return new D(); +} + +declare class D { + constructor(_: void): void; + constructor(_: null): void; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:340:16) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test20.js 1`] = ` +"// @noflow + +// Array#reduce + +[0,1].reduce((x,y,i) => y); + +[\"a\", \"b\"].reduce( + (regex, representation, index) => { + return regex + (index ? \'|\' : \'\') + \'(\' + representation + \')\'; + }, + \'\', +); + +[\"\"].reduce((acc,str) => acc * str.length); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @noflow +// Array#reduce +[ 0, 1 ].reduce((x, y, i) => y); +[ \"a\", \"b\" ].reduce( + (regex, representation, index) => { + return regex + ((index ? \"|\" : \"\")) + \"(\" + representation + \")\"; + }, + \"\" +); +[ \"\" ].reduce((acc, str) => acc * str.length); + +" +`; + +exports[`test test21.js 1`] = ` +"// @noflow + +// annotations for disjoint unions + +type T = + | { type: \"FOO\", x: number } + | { type: \"BAR\", x: string } + +({ type: (bar(): \"BAR\"), x: str() }: T); + +({ type: bar(), x: str() }: T); + +({ type: bar(), x: (str(): string) }: T); + +function bar() { + return \"BAR\"; +} + +function str() { + return \"hello\"; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test22.js 1`] = ` +"// @noflow + +// refinement of disjoint unions + +type Empty = { } + +type Success = { + type: \'SUCCESS\'; + result: string; +}; + +type Error = { + type: \'ERROR\'; +} & Empty; + +export type T = Success | Error; + +function foo(x: T) { + if (x.type === \'SUCCESS\') return x.result; + else return x.result; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test23.js 1`] = ` +"// @noflow + +// nested intersections (see also lib/test23_lib.js) + +type NestedObj = { } & { dummy: SomeLibClass }; + +type Obj = NestedObj & { x: string }; + +function foo(obj: Obj) { + obj.x; // should be OK + obj.x; // should also be OK (the check above shouldn\'t affect anything) +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test24.js 1`] = ` +"// @noflow + +// scaling test for full type resolution + +declare class C { + addListener(event: string, listener: Function): C; + emit(event: string, ...args:Array): boolean; + listeners(event: string): Array; + listenerCount(event: string): number; + on(event: string, listener: Function): C; + once(event: string, listener: Function): C; + removeAllListeners(event?: string): C; + removeListener(event: string, listener: Function): C; + setMaxListeners(n: number): void; +} + +declare class D extends C { + listen(port: number, hostname?: string, backlog?: number, callback?: Function): D; + listen(path: string, callback?: Function): D; + listen(handle: Object, callback?: Function): D; + close(callback?: Function): D; + address(): number; + connections: number; + maxConnections: number; + getConnections(callback: Function): void; + ref(): D; + unref(): D; +} + +(0: D | number); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test25.js 1`] = ` +"// @noflow + +// termination test (see also lib/test25_lib.js) + +function foo(rows: Rows, set: Set) { + return rows.reduce_rows( + (set, row) => row.reduce_row( + (set, i) => set.add(i), + set, + ), + set, + ); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test26.js 1`] = ` +"// @noflow + +declare function foo(x: number): number; +declare function foo(x: string): string; + +declare var x: number | string; + +(foo(x): number | string); + +type T = number | string; +declare var y: T; + +(foo(y): T); + +declare class Record { + set(x: \'foo\', y: number): void; + set(x: \'bar\', y: string): void; +} + +new Record().set(\'foo\', \"42\"); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1254:25) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test27.js 1`] = ` +"// @noflow + +type X = ({a:true} & {b:string}) | ({a:false} & {c:string}); +//type X = {a:true, b:string} | {a:false, c:string}; // this works. + +function hello1(x:X): string { + if (x.a === true) return x.b; else return x.c; +} + +function hello2(x:X): string { + if (x.a === false) return x.c; else return x.b; +} + +function hello3(x:X): string { + if (x.a) { return x.b; } else { return x.c; } +} + +function hello4(x:X): string { + if (!x.a) { return x.c; } else { return x.b; } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1407 + return fromString(\" & \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1407:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.map (/src/fast-path.js:167:19) + at genericPrintNoParens (/src/printer.js:1530:42) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test29.js 1`] = ` +"// @noflow + +// Make sure caching doesn\'t cause a spurious successful match (e.g., when a +// failed match is tried again). This may happen, e.g., when checking +// polymorphic definitions, where the same code may be checked multiple times +// with different instantiations. + +type Row = { x: string }; + +declare class D { + reduce( + callbackfn: (previousValue: T, currentValue: T) => T, + initialValue: void + ): T; + reduce( + callbackfn: (previousValue: U, currentValue: T) => U, + initialValue: U + ): U; +} + +class C { + foo( + rows: D, + minWidth: number, + ): number { + return rows.reduce( + (length, row) => 0, + minWidth, + ); + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1368:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test30.js 1`] = ` +"// @noflow + +const Constants = require(\'./test30-helper\'); + +type ActionType = + | { type: \'foo\', x: number } + | { type: \'bar\', x: number } + +({ type: Constants.BAR, x: 0 }: ActionType); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1530 + return fromString(\" | \").join(path.map(print, \"types\")); + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1530:32) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1481:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test30-helper.js 1`] = ` +"// @noflow + +module.exports = { + FOO: \'foo\', + BAR: \'bar\', +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @noflow +module.exports = { FOO: \"foo\", BAR: \"bar\" }; + +" +`; + +exports[`test test31.js 1`] = ` +"// @noflow + +// make sure tuples are type arguments (as used e.g. when viewing maps as +// key/value iterables) work + +interface SomeIterator { } + +interface SomeIterable { + it(): SomeIterator; +} + +declare class SomeMap { + it(): SomeIterator<[K,V]>; + set(k: K, v: V): void; +} + +declare class ImmutableMap { } + +declare function convert(iter: SomeIterable<[K,V]>): ImmutableMap; + +function foo(): ImmutableMap { + const countersGlobalMap = new SomeMap(); + countersGlobalMap.set(\"\", false); + return convert(countersGlobalMap); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1384:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test32.js 1`] = ` +"// @flow + +// make sure that full resolution jobs don\'t cache improperly to signal success +// when they have failed earlier + +function foo(value: Indirect | number): Indirect | number { + const castedValue: number = typeof value === \'number\' ? value : 0; + return castedValue; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1374:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/union_new/issue-1349.js b/tests/union_new/issue-1349.js new file mode 100644 index 000000000000..3bb5c9f3ba3c --- /dev/null +++ b/tests/union_new/issue-1349.js @@ -0,0 +1,6 @@ +/* @flow */ + +var bar: Array<{b: ?boolean, c: number} | {b: boolean}> = [ + {b: true, c: 123}, + {b: true} +]; diff --git a/tests/union_new/issue-1371.js b/tests/union_new/issue-1371.js new file mode 100644 index 000000000000..e46b4059ea6b --- /dev/null +++ b/tests/union_new/issue-1371.js @@ -0,0 +1,7 @@ +function create(a: any): { type: 'B', data: number } | { type: 'A', data: string } +{ + return { + type: 'A', + data: a + } +} diff --git a/tests/union_new/issue-1455-helper.js b/tests/union_new/issue-1455-helper.js new file mode 100644 index 000000000000..a483642f8423 --- /dev/null +++ b/tests/union_new/issue-1455-helper.js @@ -0,0 +1,3 @@ +/* @flow */ + +export class Foobar { } diff --git a/tests/union_new/issue-1455.js b/tests/union_new/issue-1455.js new file mode 100644 index 000000000000..1163aaf93311 --- /dev/null +++ b/tests/union_new/issue-1455.js @@ -0,0 +1,9 @@ +/* @flow */ +import type {Foobar} from "./issue-1455-helper" + +function create(content: ?Foobar | String | Array) { +} + +function node(content: ?Foobar | String | Array) { + create(content) +} diff --git a/tests/union_new/issue-1462-i.js b/tests/union_new/issue-1462-i.js new file mode 100644 index 000000000000..e844d3b78221 --- /dev/null +++ b/tests/union_new/issue-1462-i.js @@ -0,0 +1,22 @@ +type Common = { +}; + +type A = Common & { + type: 'A', + foo: number +}; + +type B = Common & { + type: 'B', + foo: Array +} + +type MyType = A | B; + +function print(x: number) { + console.log(x); +} + +function printAll(val: MyType) { + print(val.foo); // <--- foo could be an array +} diff --git a/tests/union_new/issue-1462-ii.js b/tests/union_new/issue-1462-ii.js new file mode 100644 index 000000000000..260eb7c19017 --- /dev/null +++ b/tests/union_new/issue-1462-ii.js @@ -0,0 +1,27 @@ +type Common = { +}; + +type A = { + type: 'A', + foo: number +} & Common; + +type B = { + type: 'B', + foo: Array +} & Common; + +type MyType = A | B; + + +function print(x: number) { + console.log(x); +} + +function printAll(val: MyType) { + if (val.type === 'A') { + print(val.foo); + } else { + val.foo.forEach(print); + } +} diff --git a/tests/union_new/issue-1664.js b/tests/union_new/issue-1664.js new file mode 100644 index 000000000000..e2d1e2d50425 --- /dev/null +++ b/tests/union_new/issue-1664.js @@ -0,0 +1,26 @@ +/* @flow */ + +type DataBase = { + id: string, + name: string, +}; + +type UserData = DataBase & { + kind: "user", +}; + +type SystemData = DataBase & { + kind: "system", +} + +type Data = UserData | SystemData; + +const data: Data = { + id: "", + name: "", + kind: "system", +} + +if (data.kind === "system") { + (data: SystemData); +} diff --git a/tests/union_new/issue-1759.js b/tests/union_new/issue-1759.js new file mode 100644 index 000000000000..af3a1a3fe51f --- /dev/null +++ b/tests/union_new/issue-1759.js @@ -0,0 +1,8 @@ +// @flow + +type X = ({a:true} & {b:string}) | ({a:false} & {c:string}); +//type X = {a:true, b:string} | {a:false, c:string}; // this works. + +function hello(x:X): string { + if (x.a === true) return x.b; else return x.c; +} diff --git a/tests/union_new/issue-2232.js b/tests/union_new/issue-2232.js new file mode 100644 index 000000000000..2401f36058f5 --- /dev/null +++ b/tests/union_new/issue-2232.js @@ -0,0 +1,24 @@ +/* @flow */ + +declare type Entity = { + id: T, + name: string +} + +declare type StringEntity = Entity + + +declare type Foo = StringEntity & { + bars: Object, + kind: 1 +} +declare type EmptyFoo = StringEntity & { + bars: null, + kind: 2 +} + +function test(f: Foo| EmptyFoo) { + if (f.kind === 1) { + (f: Foo) + } +} diff --git a/tests/union_new/issue-815.js b/tests/union_new/issue-815.js new file mode 100644 index 000000000000..44f2bed4b095 --- /dev/null +++ b/tests/union_new/issue-815.js @@ -0,0 +1,21 @@ +/* @flow */ +type T = A|B; +class U {}; +declare var children: U; +(children: T|U); +class A {}; +class B {}; + +type VirtualElement = Thunk|VirtualNode; +type Child = VirtualElement; +type Children = Array; + + +class Thunk {} +class VirtualNode { + children: Child|Children; + constructor(type, children/*:Children*/) { + this.children = children.length === 1 ? children[0] : + children; + } +} diff --git a/tests/union_new/issue-824-helper.js b/tests/union_new/issue-824-helper.js new file mode 100644 index 000000000000..289eb998e500 --- /dev/null +++ b/tests/union_new/issue-824-helper.js @@ -0,0 +1,12 @@ +import A from "./issue-824"; + +export class B extends A { + which(): number { + return 1; + } +} +export class C extends A { + which(): number { + return 2; + } +} diff --git a/tests/union_new/issue-824.js b/tests/union_new/issue-824.js new file mode 100644 index 000000000000..655e03d1391b --- /dev/null +++ b/tests/union_new/issue-824.js @@ -0,0 +1,16 @@ +import { B, C } from "./issue-824-helper"; + +type K = B | C; + +type I = { + which(): number; +}; + +export default class A { + static foo(p: K): bool { + return false; + } + static bar(p: I & K): bool { + return this.foo(p); + } +} diff --git a/tests/union_new/jsfmt.spec.js b/tests/union_new/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/union_new/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/union_new/lib/__snapshots__/jsfmt.spec.js.snap b/tests/union_new/lib/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fe17b3fb98ef --- /dev/null +++ b/tests/union_new/lib/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,69 @@ +exports[`test test23_lib.js 1`] = ` +"declare class SomeLibClass { } +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +declare class SomeLibClass {} + +" +`; + +exports[`test test25_lib.js 1`] = ` +"declare class Set { + add(): Set; +} + +declare class Row { + reduce_row( + callbackfn: (previousValue: number, currentValue: number) => number, + initialValue: void + ): number; + reduce_row( + callbackfn: (previousValue: U, currentValue: number) => U, + initialValue: U + ): U; +} + +declare class Rows { + reduce_rows( + callbackfn: (previousValue: X, currentValue: Row) => X, + initialValue: X + ): X; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1348 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1348:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1452:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; + +exports[`test test32_lib.js 1`] = ` +"type Indirect = Array; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/src/printer.js:1497 + fromString(\", \").join(path.map(print, \"params\")), + ^ + +TypeError: fromString(...).join is not a function + at genericPrintNoParens (/src/printer.js:1497:26) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) + at printGenerically (/src/printer.js:111:12) + at FastPath.call (/src/fast-path.js:113:16) + at genericPrintNoParens (/src/printer.js:1479:14) + at genericPrint (/src/printer.js:166:7) + at p (/src/printer.js:111:37) + at exports.printComments (/src/comments.js:327:20) +" +`; diff --git a/tests/union_new/lib/jsfmt.spec.js b/tests/union_new/lib/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/union_new/lib/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/union_new/lib/test23_lib.js b/tests/union_new/lib/test23_lib.js new file mode 100644 index 000000000000..a0b41766ae6e --- /dev/null +++ b/tests/union_new/lib/test23_lib.js @@ -0,0 +1 @@ +declare class SomeLibClass { } diff --git a/tests/union_new/lib/test25_lib.js b/tests/union_new/lib/test25_lib.js new file mode 100644 index 000000000000..d79c71a20c19 --- /dev/null +++ b/tests/union_new/lib/test25_lib.js @@ -0,0 +1,21 @@ +declare class Set { + add(): Set; +} + +declare class Row { + reduce_row( + callbackfn: (previousValue: number, currentValue: number) => number, + initialValue: void + ): number; + reduce_row( + callbackfn: (previousValue: U, currentValue: number) => U, + initialValue: U + ): U; +} + +declare class Rows { + reduce_rows( + callbackfn: (previousValue: X, currentValue: Row) => X, + initialValue: X + ): X; +} diff --git a/tests/union_new/lib/test32_lib.js b/tests/union_new/lib/test32_lib.js new file mode 100644 index 000000000000..e0daf1518b2f --- /dev/null +++ b/tests/union_new/lib/test32_lib.js @@ -0,0 +1 @@ +type Indirect = Array; diff --git a/tests/union_new/test1.js b/tests/union_new/test1.js new file mode 100644 index 000000000000..10758e4134b2 --- /dev/null +++ b/tests/union_new/test1.js @@ -0,0 +1,60 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////////////// +// example with object types +////////////////////////////// + +function obj(a: A1 | A2) { + return a.x; +} + +const obj_result = obj({ x: "" }); // currently an error! (expect it to be OK) + +// Type definitions used above are defined below, but in an order that +// deliberately makes their full resolution as lazy as possible. The call above +// blocks until A1 is partially resolved. Since the argument partially matches +// A1, that branch is selected. Later, that branch errors, but other branches +// have been lost by then. + +type A1 = { x: B1 }; +type A2 = { x: B2 }; + +type B1 = number; +type B2 = string; + +(obj_result: B1 | B2); + +/////////////////////////////////////// +// similar example with function types +/////////////////////////////////////// + +function fun(a: A3 | A4) { + return a(); +} + +const fun_result = fun(() => ""); + +type A3 = () => B3; +type A4 = () => B4; + +type B3 = number; +type B4 = string; + +(fun_result: B3 | B4); + +///////////////////////////////////////////// +// similar example with class instance types +///////////////////////////////////////////// + +function inst(a: A5 | A6) { } + +class B5 { } +class B6 { } +inst([new B6]); + +type A5 = B5[]; +type A6 = B6[]; diff --git a/tests/union_new/test10.js b/tests/union_new/test10.js new file mode 100644 index 000000000000..deaa835fe346 --- /dev/null +++ b/tests/union_new/test10.js @@ -0,0 +1,72 @@ +// @noflow + +function id(x: X): X { return x; } + +///////////////////////// +// primitive annotations +///////////////////////// + +function check_prim(_: number | string) { } + +// ok +check_prim(""); + +// ...even when they "flow" in +check_prim(id("")); + +////////////////////////////// +// class instance annotations +////////////////////////////// + +class C { } +class D { } +function check_inst(_: C | D) { } + +// ok +check_inst(new D); + +// ...even when they "flow" in +check_inst(id(new C)); + +//////////////////////// +// function annotations +//////////////////////// + +function check_fun(_: ((_: number) => number) | ((_: string) => string)) { } + +// help! +check_fun((x) => x); + +////////////////////// +// object annotations +////////////////////// + +function check_obj(_: { x: number } | { x: string }) { } + +// ok +check_obj({ x: "" }); + +// help! +check_obj({ x: id("") }); + +///////////////////// +// array annotations +///////////////////// + +function check_arr(_: number[] | string[]) { } + +// ok +check_arr([""]); + +// help! +check_arr([id("")]); + +////////////////////////////////////// +// generic class instance annotations +////////////////////////////////////// + +class P { } +function check_poly_inst(_: P | P) { } + +// help! +check_poly_inst(new P); diff --git a/tests/union_new/test11.js b/tests/union_new/test11.js new file mode 100644 index 000000000000..c5a02b7fbf81 --- /dev/null +++ b/tests/union_new/test11.js @@ -0,0 +1,18 @@ +// @noflow + +// disjoint unions + +function length(list: List) { + if (list.kind === "cons") return length(list.next) + 1; + else return 0; +} + + +length({ kind: "nil" }); +length({ kind: "cons" }); // missing `next` +length({ kind: "cons", next: { kind: "nil" } }); +length({ kind: "empty" }); // `kind` not found + +type List = Nil | Cons; +type Nil = { kind: "nil" }; +type Cons = { kind: "cons", next: List }; diff --git a/tests/union_new/test12.js b/tests/union_new/test12.js new file mode 100644 index 000000000000..45aff3456d35 --- /dev/null +++ b/tests/union_new/test12.js @@ -0,0 +1,9 @@ +// @noflow + +// polymorphic recursive types + +type F = { f: F, x: X } +type G = { x: number } +type H = { x: string } + +function rec(x: F): G | H { return x; } diff --git a/tests/union_new/test13.js b/tests/union_new/test13.js new file mode 100644 index 000000000000..89333fc536a4 --- /dev/null +++ b/tests/union_new/test13.js @@ -0,0 +1,11 @@ +// @noflow + +/* ensure there are no unintended side effects when trying branches */ + +({type: 'B', id: 'hi'}: { + type: 'A'; + id: ?string; +} | { + type: 'B'; + id: string; +}); diff --git a/tests/union_new/test14.js b/tests/union_new/test14.js new file mode 100644 index 000000000000..8b69352cd591 --- /dev/null +++ b/tests/union_new/test14.js @@ -0,0 +1,13 @@ +// @noflow + +// annotations + +declare class C { + get(): X; +} + +function union(o: { x: string } | { x: number }) { } + +function foo(c: C) { + union({ x: c.get() }); +} diff --git a/tests/union_new/test15.js b/tests/union_new/test15.js new file mode 100644 index 000000000000..c5660df4e330 --- /dev/null +++ b/tests/union_new/test15.js @@ -0,0 +1,24 @@ +// @noflow + +// functions as objects + +function foo(target: EventTarget) { + target.addEventListener('click', (e) => {}); +} + +declare class EventTarget { + addEventListener(type: 'foo', listener: KeyboardEventHandler): void; + addEventListener(type: string, listener: EventHandler): void; +} + +declare class Event { } +declare class KeyboardEvent { } + +type EventHandler = (event: Event) => mixed +type KeyboardEventHandler = (event: KeyboardEvent) => mixed + +// example where globals are not yet resolved + +function bar(x: (() => void) | { x: number }) { } + +bar(() => { }); diff --git a/tests/union_new/test16.js b/tests/union_new/test16.js new file mode 100644 index 000000000000..0debe2bd0a86 --- /dev/null +++ b/tests/union_new/test16.js @@ -0,0 +1,18 @@ +// @noflow + +// annotations + +type T = number | (() => string); +type Foo = T | (() => bool); + +type Bar = number | (() => string) | (() => bool); + +function foo(x: Foo) { } +foo(() => qux()); + +function bar(x: Bar) { } +bar(() => qux()); + +var x = false; +function qux() { return x; } +x = ""; diff --git a/tests/union_new/test17.js b/tests/union_new/test17.js new file mode 100644 index 000000000000..919fa91246c5 --- /dev/null +++ b/tests/union_new/test17.js @@ -0,0 +1,7 @@ +// @noflow + +// Array#concat + +[].concat([]); + +([].concat([0,1])[1]: string) diff --git a/tests/union_new/test18.js b/tests/union_new/test18.js new file mode 100644 index 000000000000..6ae2bbd21c8c --- /dev/null +++ b/tests/union_new/test18.js @@ -0,0 +1,12 @@ +// @noflow + +// method overloads + +declare class C { + m(x: number): void; + m(x: string): void; +} + +function f() { return 0; } + +new C().m(f()); diff --git a/tests/union_new/test19.js b/tests/union_new/test19.js new file mode 100644 index 000000000000..2178cdf8a7d0 --- /dev/null +++ b/tests/union_new/test19.js @@ -0,0 +1,12 @@ +// @noflow + +// constructor overloads + +function m() { + return new D(); +} + +declare class D { + constructor(_: void): void; + constructor(_: null): void; +} diff --git a/tests/union_new/test2.js b/tests/union_new/test2.js new file mode 100644 index 000000000000..4647de3ccdfb --- /dev/null +++ b/tests/union_new/test2.js @@ -0,0 +1,77 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////////////// +// example with object types +////////////////////////////// + +function obj(a: { x: number } | { x: string }) { } + +obj(({ x: "" }: A1)); + +type A1 = { x: B1 }; + +type B1 = string; + +/////////////////////////////////////// +// similar example with function types +/////////////////////////////////////// + +function fun(a: (() => number) | (() => string)) { } + +fun(((() => ""): A2)); + +type A2 = () => B2; + +type B2 = string; + +///////////////////////////////////////////////////// +// similar example with generic class instance types +///////////////////////////////////////////////////// + +class C { } + +function inst(a: C | C) { } + +inst((new C: A3)); + +type A3 = C; + +type B3 = string; + +///////////////////////////////////////////// +// similar example with generic type aliases +///////////////////////////////////////////// + +function alias(a: T | T) { } +alias({ x: (x: V) => { } }); + +type T = { x: U } +type U = (x: V) => void; +type V = X; + +type B4 = string; + +// class statics + +function stat(a: { x: number } | { x: string }) { } + +class D { + static x: B5; +} + +stat(D); + +type B5 = string; + +// tuples + +function tup(a: [number,boolean] | [string,boolean]) { } + +tup((["",false]: A6)); + +type A6 = [B6,boolean]; +type B6 = string; diff --git a/tests/union_new/test20.js b/tests/union_new/test20.js new file mode 100644 index 000000000000..1aaab84f7941 --- /dev/null +++ b/tests/union_new/test20.js @@ -0,0 +1,14 @@ +// @noflow + +// Array#reduce + +[0,1].reduce((x,y,i) => y); + +["a", "b"].reduce( + (regex, representation, index) => { + return regex + (index ? '|' : '') + '(' + representation + ')'; + }, + '', +); + +[""].reduce((acc,str) => acc * str.length); diff --git a/tests/union_new/test21.js b/tests/union_new/test21.js new file mode 100644 index 000000000000..9f68c9485371 --- /dev/null +++ b/tests/union_new/test21.js @@ -0,0 +1,21 @@ +// @noflow + +// annotations for disjoint unions + +type T = + | { type: "FOO", x: number } + | { type: "BAR", x: string } + +({ type: (bar(): "BAR"), x: str() }: T); + +({ type: bar(), x: str() }: T); + +({ type: bar(), x: (str(): string) }: T); + +function bar() { + return "BAR"; +} + +function str() { + return "hello"; +} diff --git a/tests/union_new/test22.js b/tests/union_new/test22.js new file mode 100644 index 000000000000..2b7a263f859b --- /dev/null +++ b/tests/union_new/test22.js @@ -0,0 +1,21 @@ +// @noflow + +// refinement of disjoint unions + +type Empty = { } + +type Success = { + type: 'SUCCESS'; + result: string; +}; + +type Error = { + type: 'ERROR'; +} & Empty; + +export type T = Success | Error; + +function foo(x: T) { + if (x.type === 'SUCCESS') return x.result; + else return x.result; +} diff --git a/tests/union_new/test23.js b/tests/union_new/test23.js new file mode 100644 index 000000000000..ad65416fcffa --- /dev/null +++ b/tests/union_new/test23.js @@ -0,0 +1,12 @@ +// @noflow + +// nested intersections (see also lib/test23_lib.js) + +type NestedObj = { } & { dummy: SomeLibClass }; + +type Obj = NestedObj & { x: string }; + +function foo(obj: Obj) { + obj.x; // should be OK + obj.x; // should also be OK (the check above shouldn't affect anything) +} diff --git a/tests/union_new/test24.js b/tests/union_new/test24.js new file mode 100644 index 000000000000..98d2d704242d --- /dev/null +++ b/tests/union_new/test24.js @@ -0,0 +1,30 @@ +// @noflow + +// scaling test for full type resolution + +declare class C { + addListener(event: string, listener: Function): C; + emit(event: string, ...args:Array): boolean; + listeners(event: string): Array; + listenerCount(event: string): number; + on(event: string, listener: Function): C; + once(event: string, listener: Function): C; + removeAllListeners(event?: string): C; + removeListener(event: string, listener: Function): C; + setMaxListeners(n: number): void; +} + +declare class D extends C { + listen(port: number, hostname?: string, backlog?: number, callback?: Function): D; + listen(path: string, callback?: Function): D; + listen(handle: Object, callback?: Function): D; + close(callback?: Function): D; + address(): number; + connections: number; + maxConnections: number; + getConnections(callback: Function): void; + ref(): D; + unref(): D; +} + +(0: D | number); diff --git a/tests/union_new/test25.js b/tests/union_new/test25.js new file mode 100644 index 000000000000..581bed11d031 --- /dev/null +++ b/tests/union_new/test25.js @@ -0,0 +1,13 @@ +// @noflow + +// termination test (see also lib/test25_lib.js) + +function foo(rows: Rows, set: Set) { + return rows.reduce_rows( + (set, row) => row.reduce_row( + (set, i) => set.add(i), + set, + ), + set, + ); +} diff --git a/tests/union_new/test26.js b/tests/union_new/test26.js new file mode 100644 index 000000000000..501c49c1eaa2 --- /dev/null +++ b/tests/union_new/test26.js @@ -0,0 +1,20 @@ +// @noflow + +declare function foo(x: number): number; +declare function foo(x: string): string; + +declare var x: number | string; + +(foo(x): number | string); + +type T = number | string; +declare var y: T; + +(foo(y): T); + +declare class Record { + set(x: 'foo', y: number): void; + set(x: 'bar', y: string): void; +} + +new Record().set('foo', "42"); diff --git a/tests/union_new/test27.js b/tests/union_new/test27.js new file mode 100644 index 000000000000..823609224da8 --- /dev/null +++ b/tests/union_new/test27.js @@ -0,0 +1,20 @@ +// @noflow + +type X = ({a:true} & {b:string}) | ({a:false} & {c:string}); +//type X = {a:true, b:string} | {a:false, c:string}; // this works. + +function hello1(x:X): string { + if (x.a === true) return x.b; else return x.c; +} + +function hello2(x:X): string { + if (x.a === false) return x.c; else return x.b; +} + +function hello3(x:X): string { + if (x.a) { return x.b; } else { return x.c; } +} + +function hello4(x:X): string { + if (!x.a) { return x.c; } else { return x.b; } +} diff --git a/tests/union_new/test29.js b/tests/union_new/test29.js new file mode 100644 index 000000000000..5db89360ada5 --- /dev/null +++ b/tests/union_new/test29.js @@ -0,0 +1,31 @@ +// @noflow + +// Make sure caching doesn't cause a spurious successful match (e.g., when a +// failed match is tried again). This may happen, e.g., when checking +// polymorphic definitions, where the same code may be checked multiple times +// with different instantiations. + +type Row = { x: string }; + +declare class D { + reduce( + callbackfn: (previousValue: T, currentValue: T) => T, + initialValue: void + ): T; + reduce( + callbackfn: (previousValue: U, currentValue: T) => U, + initialValue: U + ): U; +} + +class C { + foo( + rows: D, + minWidth: number, + ): number { + return rows.reduce( + (length, row) => 0, + minWidth, + ); + } +} diff --git a/tests/union_new/test3.js b/tests/union_new/test3.js new file mode 100644 index 000000000000..fd12e5fd150f --- /dev/null +++ b/tests/union_new/test3.js @@ -0,0 +1,29 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +/////////////////////////////// +// example with function types +/////////////////////////////// + +function fun(a: ((x: number) => void) | ((x: string) => void)) { } + +fun((((x) => {}): A1)); + +type A1 = (x: B1) => void; + +type B1 = string; + +//////////////////////////// +// example with array types +//////////////////////////// + +function arr(a: number[] | string[]) { } + +arr(([]: A2)); + +type A2 = B2[]; + +type B2 = string; diff --git a/tests/union_new/test30-helper.js b/tests/union_new/test30-helper.js new file mode 100644 index 000000000000..b4eccdb14226 --- /dev/null +++ b/tests/union_new/test30-helper.js @@ -0,0 +1,6 @@ +// @noflow + +module.exports = { + FOO: 'foo', + BAR: 'bar', +} diff --git a/tests/union_new/test30.js b/tests/union_new/test30.js new file mode 100644 index 000000000000..96ec6ec5618c --- /dev/null +++ b/tests/union_new/test30.js @@ -0,0 +1,9 @@ +// @noflow + +const Constants = require('./test30-helper'); + +type ActionType = + | { type: 'foo', x: number } + | { type: 'bar', x: number } + +({ type: Constants.BAR, x: 0 }: ActionType); diff --git a/tests/union_new/test31.js b/tests/union_new/test31.js new file mode 100644 index 000000000000..23c2642bb22f --- /dev/null +++ b/tests/union_new/test31.js @@ -0,0 +1,25 @@ +// @noflow + +// make sure tuples are type arguments (as used e.g. when viewing maps as +// key/value iterables) work + +interface SomeIterator { } + +interface SomeIterable { + it(): SomeIterator; +} + +declare class SomeMap { + it(): SomeIterator<[K,V]>; + set(k: K, v: V): void; +} + +declare class ImmutableMap { } + +declare function convert(iter: SomeIterable<[K,V]>): ImmutableMap; + +function foo(): ImmutableMap { + const countersGlobalMap = new SomeMap(); + countersGlobalMap.set("", false); + return convert(countersGlobalMap); +} diff --git a/tests/union_new/test32.js b/tests/union_new/test32.js new file mode 100644 index 000000000000..b6f730ec9a37 --- /dev/null +++ b/tests/union_new/test32.js @@ -0,0 +1,9 @@ +// @flow + +// make sure that full resolution jobs don't cache improperly to signal success +// when they have failed earlier + +function foo(value: Indirect | number): Indirect | number { + const castedValue: number = typeof value === 'number' ? value : 0; + return castedValue; +} diff --git a/tests/union_new/test4.js b/tests/union_new/test4.js new file mode 100644 index 000000000000..93dd1dccaac4 --- /dev/null +++ b/tests/union_new/test4.js @@ -0,0 +1,36 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +/////////////////////////////// +// example with function types +/////////////////////////////// + +function fun(a: ((x: number) => void) | ((x: string) => void)) { } + +const a1 = ((x) => {}: A1); +fun(a1); + +function fun_call(x: string) { a1(x); } + +type A1 = (x: B1) => void; + +type B1 = string; + +//////////////////////////// +// example with array types +//////////////////////////// + +function arr(a: number[] | string[]) { } + +const a2 = ([]: A2); +arr(a2); + +function arr_set(x: string, i: number) { a2[i] = x; } +function arr_get(i: number): string { return a2[i]; } + +type A2 = B2[]; + +type B2 = string; diff --git a/tests/union_new/test5.js b/tests/union_new/test5.js new file mode 100644 index 000000000000..0222e8f934fc --- /dev/null +++ b/tests/union_new/test5.js @@ -0,0 +1,27 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +/////////////////////////////// +// example with function types +/////////////////////////////// + +function fun(a: ((x: number) => number) | ((x: string) => string)) { } + +function a1(x) { return x; } +fun(a1); + +function fun_call(x: string): string { return a1(x); } + +///////////////////////////// +// example with array types +///////////////////////////// + +function arr(a: number[] | string[]) { } + +var a2 = []; +arr(a2); + +function arr_set(x: string, i: number) { a2[i] = x; } diff --git a/tests/union_new/test6.js b/tests/union_new/test6.js new file mode 100644 index 000000000000..c780bb848351 --- /dev/null +++ b/tests/union_new/test6.js @@ -0,0 +1,25 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////////////////////////// +// example with generic class inheritance +////////////////////////////////////////// + +function inst(a: E): C | C { return a; } + +const mk_C = () => C; +const mk_D = () => D; +const mk_E = () => E; + +type B4 = string; + +const _D = mk_D(); +class E extends _D { } + +const _C = mk_C(); +class D extends _C { } + +class C { } diff --git a/tests/union_new/test7.js b/tests/union_new/test7.js new file mode 100644 index 000000000000..1f9f5713b938 --- /dev/null +++ b/tests/union_new/test7.js @@ -0,0 +1,29 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +//////////////////// +// recursive types +//////////////////// + +function rec(x: F1 | F2) { } +rec({ x: 0 }); + +type F1 = G1; +type F2 = G2; +type G1 = { x: H1, y?: G1 }; +type G2 = { x: H2, y?: G2 }; +type H1 = string; +type H2 = number; + +/////////////////////////////// +// polymorphic recursive types +/////////////////////////////// + +function polyrec(x: PF | PF) { } +rec({ x: 0 }); + +type PF = PG; +type PG = { x: X, y?: PG }; diff --git a/tests/union_new/test8.js b/tests/union_new/test8.js new file mode 100644 index 000000000000..4afbc4c62b5f --- /dev/null +++ b/tests/union_new/test8.js @@ -0,0 +1,23 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +////////////////////// +// nested union types +////////////////////// + +function rec(x: F1 | F2) { } +rec({ x: 0 }); + +type F1 = G1 | G1_; +type F2 = G2 | G2_; +type G1 = { x: H1 }; +type G1_ = { x: H1_ }; +type G2 = { x: H2 }; +type G2_ = { x: H2_ }; +type H1 = boolean; +type H1_ = string; +type H2 = boolean; +type H2_ = number; diff --git a/tests/union_new/test9.js b/tests/union_new/test9.js new file mode 100644 index 000000000000..18221e5d82cd --- /dev/null +++ b/tests/union_new/test9.js @@ -0,0 +1,16 @@ +// @noflow + +/** + * Test that shows how the implementation of union types is broken + */ + +//////////////// +// interference +//////////////// + +function square(x? = 0) { + return x * x; +} + +function foo(f: ((_: ?number) => ?number) | (() => void)) { } +foo((x): number => square(x)) diff --git a/tests/unreachable/__snapshots__/jsfmt.spec.js.snap b/tests/unreachable/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..dc6dbc6e22a9 --- /dev/null +++ b/tests/unreachable/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,95 @@ +exports[`test typecheck.js 1`] = ` +"/* @flow */ + +function test1(): string { + return bar(); + + function bar() { + return 0; + } +} + +// regression test for analysis after abnormal control flow: +// consts must not become bot (EmptyT). + +function test2() { + const n = 0; + + return; + + function f() { + var x: typeof n = 0; // no error, n is still number + var y: string = n; // error, n is number (EmptyT would work) + } +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function test1(): string { + return bar(); + function bar() { + return 0; + } +} +// regression test for analysis after abnormal control flow: +// consts must not become bot (EmptyT). +function test2() { + const n = 0; + return; + function f() { + var x: typeof n = 0;// no error, n is still number + var y: string = n;// error, n is number (EmptyT would work) + } +} + +" +`; + +exports[`test unreachable.js 1`] = ` +"/* @flow */ + +function foo(x, y) { + "use strict"; + return bar(x) + baz(y); + + // function declaration is hoisted, should not generate warning + function bar (ecks) { + return x + ecks; + } + + // assignment is not hoisted, should generate warning + var baz = function (why) { + return y + why; + }; + + // variable declaration is hoisted, should not generate warning + var x, y, z; + + // assignments are not hoisted, should generate 2 warnings + var t, + u = 5, + v, + w = 7; +} + +foo(1, 2); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo(x, y) { "use strict"; + return bar(x) + baz(y); + // function declaration is hoisted, should not generate warning + function bar(ecks) { + return x + ecks; + } + // assignment is not hoisted, should generate warning + var baz = function(why) { + return y + why; + }; + // variable declaration is hoisted, should not generate warning + var xy,z; + // assignments are not hoisted, should generate 2 warnings + var tu = 5,v,w = 7; +} +foo(1, 2); + +" +`; diff --git a/tests/unreachable/jsfmt.spec.js b/tests/unreachable/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/unreachable/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/unreachable/typecheck.js b/tests/unreachable/typecheck.js new file mode 100644 index 000000000000..78c517f82e75 --- /dev/null +++ b/tests/unreachable/typecheck.js @@ -0,0 +1,23 @@ +/* @flow */ + +function test1(): string { + return bar(); + + function bar() { + return 0; + } +} + +// regression test for analysis after abnormal control flow: +// consts must not become bot (EmptyT). + +function test2() { + const n = 0; + + return; + + function f() { + var x: typeof n = 0; // no error, n is still number + var y: string = n; // error, n is number (EmptyT would work) + } +} diff --git a/tests/unreachable/unreachable.js b/tests/unreachable/unreachable.js new file mode 100644 index 000000000000..84cee2a9e380 --- /dev/null +++ b/tests/unreachable/unreachable.js @@ -0,0 +1,27 @@ +/* @flow */ + +function foo(x, y) { + "use strict"; + return bar(x) + baz(y); + + // function declaration is hoisted, should not generate warning + function bar (ecks) { + return x + ecks; + } + + // assignment is not hoisted, should generate warning + var baz = function (why) { + return y + why; + }; + + // variable declaration is hoisted, should not generate warning + var x, y, z; + + // assignments are not hoisted, should generate 2 warnings + var t, + u = 5, + v, + w = 7; +} + +foo(1, 2); diff --git a/tests/value/__snapshots__/jsfmt.spec.js.snap b/tests/value/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..778376ff6508 --- /dev/null +++ b/tests/value/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,16 @@ +exports[`test value.js 1`] = ` +"var o = {}; +o["x"] = 4; +var y:string = o["x"]; + +var table: { [_: string]: number } = {}; +table["x"] = "hello"; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +var o = {}; +o["x"] = 4; +var y: string = o["x"]; +var table: { [_: string]: number } = {}; +table["x"] = "hello"; + +" +`; diff --git a/tests/value/jsfmt.spec.js b/tests/value/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/value/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/value/value.js b/tests/value/value.js new file mode 100644 index 000000000000..ef7f957c6fe0 --- /dev/null +++ b/tests/value/value.js @@ -0,0 +1,6 @@ +var o = {}; +o["x"] = 4; +var y:string = o["x"]; + +var table: { [_: string]: number } = {}; +table["x"] = "hello"; diff --git a/tests/vim_emacs_errors/__snapshots__/jsfmt.spec.js.snap b/tests/vim_emacs_errors/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fc4cf2d5fc7f --- /dev/null +++ b/tests/vim_emacs_errors/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,10 @@ +exports[`test test.js 1`] = ` +"// @flow + +(123: string); +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// @flow +(123: string); + +" +`; diff --git a/tests/vim_emacs_errors/jsfmt.spec.js b/tests/vim_emacs_errors/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/vim_emacs_errors/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/vim_emacs_errors/test.js b/tests/vim_emacs_errors/test.js new file mode 100644 index 000000000000..aa418762398d --- /dev/null +++ b/tests/vim_emacs_errors/test.js @@ -0,0 +1,3 @@ +// @flow + +(123: string); diff --git a/tests/weakmode/__snapshots__/jsfmt.spec.js.snap b/tests/weakmode/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..82293afbb43f --- /dev/null +++ b/tests/weakmode/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,47 @@ +exports[`test should_fail_without_weak.js 1`] = ` +"/* @flow */ +// This should fail without weak mode, because of the glaring type error. + +function returns_a_string() { + return "Hello"; +} + +function expects_an_int() { + return returns_a_string() * 10; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +// This should fail without weak mode, because of the glaring type error. +function returns_a_string() { + return "Hello"; +} +function expects_an_int() { + return returns_a_string() * 10; +} + +" +`; + +exports[`test should_pass_with_weak.js 1`] = ` +"/* @flow weak */ +// This should fail without weak mode, because of the glaring type error. + +function returns_a_string() { + return "Hello"; +} + +function expects_an_int() { + return returns_a_string() * 10; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow weak */ +// This should fail without weak mode, because of the glaring type error. +function returns_a_string() { + return "Hello"; +} +function expects_an_int() { + return returns_a_string() * 10; +} + +" +`; diff --git a/tests/weakmode/jsfmt.spec.js b/tests/weakmode/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/weakmode/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/weakmode/should_fail_without_weak.js b/tests/weakmode/should_fail_without_weak.js new file mode 100644 index 000000000000..9dcc0c64d334 --- /dev/null +++ b/tests/weakmode/should_fail_without_weak.js @@ -0,0 +1,10 @@ +/* @flow */ +// This should fail without weak mode, because of the glaring type error. + +function returns_a_string() { + return "Hello"; +} + +function expects_an_int() { + return returns_a_string() * 10; +} diff --git a/tests/weakmode/should_pass_with_weak.js b/tests/weakmode/should_pass_with_weak.js new file mode 100644 index 000000000000..14fce153d528 --- /dev/null +++ b/tests/weakmode/should_pass_with_weak.js @@ -0,0 +1,10 @@ +/* @flow weak */ +// This should fail without weak mode, because of the glaring type error. + +function returns_a_string() { + return "Hello"; +} + +function expects_an_int() { + return returns_a_string() * 10; +} diff --git a/tests/while/__snapshots__/jsfmt.spec.js.snap b/tests/while/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..5b99d486fc53 --- /dev/null +++ b/tests/while/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,73 @@ +exports[`test abnormal.js 1`] = ` +"/* @flow */ + +function foo(x: boolean) { + var ii = 10; + while (ii-- >= 0) { + if (x) { + continue; + } + return; + } + //console.log('this is still reachable'); +} + +function bar(x: boolean) { + var ii = 0; + while (ii > 0) { + return; + } + //console.log('this is still reachable'); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @flow */ +function foo(x: boolean) { + var ii = 10; + while (ii-- >= 0) { + if (x) { + continue; + } + return; + }//console.log('this is still reachable'); +} +function bar(x: boolean) { + var ii = 0; + while (ii > 0) { + return; + }//console.log('this is still reachable'); +} + +" +`; + +exports[`test test.js 1`] = ` +"class C { + m() { return new C; } +} +function blah() {} +var node: ?C = new C; +while (node) { + var parent = node.m(); + var cloneable: C = node; + blah(); + node = parent.m(); +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class C { + m() { + return new C(); + } +} +function blah() { + +} +var node: ?C = new C(); +while (node) { + var parent = node.m(); + var cloneable: C = node; + blah(); + node = parent.m(); +} + +" +`; diff --git a/tests/while/abnormal.js b/tests/while/abnormal.js new file mode 100644 index 000000000000..35431642a482 --- /dev/null +++ b/tests/while/abnormal.js @@ -0,0 +1,20 @@ +/* @flow */ + +function foo(x: boolean) { + var ii = 10; + while (ii-- >= 0) { + if (x) { + continue; + } + return; + } + //console.log('this is still reachable'); +} + +function bar(x: boolean) { + var ii = 0; + while (ii > 0) { + return; + } + //console.log('this is still reachable'); +} diff --git a/tests/while/jsfmt.spec.js b/tests/while/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/while/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/while/test.js b/tests/while/test.js new file mode 100644 index 000000000000..16f55038cdb7 --- /dev/null +++ b/tests/while/test.js @@ -0,0 +1,11 @@ +class C { + m() { return new C; } +} +function blah() {} +var node: ?C = new C; +while (node) { + var parent = node.m(); + var cloneable: C = node; + blah(); + node = parent.m(); +} diff --git a/tests/window/__snapshots__/jsfmt.spec.js.snap b/tests/window/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..fd3a6302ffdf --- /dev/null +++ b/tests/window/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,24 @@ +exports[`test window1.js 1`] = ` +"/* +@providesModule Window1 +*/ +module.exports = window.history; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* +@providesModule Window1 +*/ +module.exports = window.history; + +" +`; + +exports[`test window2.js 1`] = ` +"/* @providesModule Window2 */ + +module.exports = window.parent; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/* @providesModule Window2 */ +module.exports = window.parent; + +" +`; diff --git a/tests/window/jsfmt.spec.js b/tests/window/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/window/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/window/window1.js b/tests/window/window1.js new file mode 100644 index 000000000000..c5e6ac93949d --- /dev/null +++ b/tests/window/window1.js @@ -0,0 +1,4 @@ +/* +@providesModule Window1 +*/ +module.exports = window.history; diff --git a/tests/window/window2.js b/tests/window/window2.js new file mode 100644 index 000000000000..b16e6aa9eb88 --- /dev/null +++ b/tests/window/window2.js @@ -0,0 +1,3 @@ +/* @providesModule Window2 */ + +module.exports = window.parent; diff --git a/tests/x/XControllerURIBuilder.js b/tests/x/XControllerURIBuilder.js new file mode 100644 index 000000000000..78429106b236 --- /dev/null +++ b/tests/x/XControllerURIBuilder.js @@ -0,0 +1,30 @@ +/** + * @generated SignedSource<<13ca42bbc7fe91f15057861e18a77d88>> + * + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !! This file is a check-in of a static_upstream project! !! + * !! !! + * !! You should not modify this file directly. Instead: !! + * !! 1) Use `fjs use-upstream` to temporarily replace this with !! + * !! the latest version from upstream. !! + * !! 2) Make your changes, test them, etc. !! + * !! 3) Use `fjs push-upstream` to copy your changes back to !! + * !! static_upstream. !! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * @providesModule XControllerURIBuilder + * @typechecks + */ + +// ... +class XControllerURIBuilder { + + // ... + getURI() { + // ... + var tokenRegex = new RegExp(/^\{(\?)?(.+?)\}$/); + // ... + } +} + +module.exports = XControllerURIBuilder; diff --git a/tests/x/__snapshots__/jsfmt.spec.js.snap b/tests/x/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..2dc029c12a2e --- /dev/null +++ b/tests/x/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,61 @@ +exports[`test XControllerURIBuilder.js 1`] = ` +"/** + * @generated SignedSource<<13ca42bbc7fe91f15057861e18a77d88>> + * + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !! This file is a check-in of a static_upstream project! !! + * !! !! + * !! You should not modify this file directly. Instead: !! + * !! 1) Use \`fjs use-upstream\` to temporarily replace this with !! + * !! the latest version from upstream. !! + * !! 2) Make your changes, test them, etc. !! + * !! 3) Use \`fjs push-upstream\` to copy your changes back to !! + * !! static_upstream. !! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * @providesModule XControllerURIBuilder + * @typechecks + */ + +// ... +class XControllerURIBuilder { + + // ... + getURI() { + // ... + var tokenRegex = new RegExp(/^\\{(\\?)?(.+?)\\}$/); + // ... + } +} + +module.exports = XControllerURIBuilder; +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/** + * @generated SignedSource<<13ca42bbc7fe91f15057861e18a77d88>> + * + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * !! This file is a check-in of a static_upstream project! !! + * !! !! + * !! You should not modify this file directly. Instead: !! + * !! 1) Use \`fjs use-upstream\` to temporarily replace this with !! + * !! the latest version from upstream. !! + * !! 2) Make your changes, test them, etc. !! + * !! 3) Use \`fjs push-upstream\` to copy your changes back to !! + * !! static_upstream. !! + * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + * + * @providesModule XControllerURIBuilder + * @typechecks + */ +// ... +class XControllerURIBuilder { + // ... + getURI() { + // ... + var tokenRegex = new RegExp(/^\\{(\\?)?(.+?)\\}$/);// ... + } +} +module.exports = XControllerURIBuilder; + +" +`; diff --git a/tests/x/jsfmt.spec.js b/tests/x/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/x/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/yield/__snapshots__/jsfmt.spec.js.snap b/tests/yield/__snapshots__/jsfmt.spec.js.snap new file mode 100644 index 000000000000..18bae5f5cf57 --- /dev/null +++ b/tests/yield/__snapshots__/jsfmt.spec.js.snap @@ -0,0 +1,34 @@ +exports[`test yield_arrow_error.js 1`] = ` +"function * f () { + var e = () => { yield 1; }; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +/node_modules/babylon/lib/index.js:4255 + throw err; + ^ + +SyntaxError: Unexpected token (2:18) + at Parser.pp$5.raise (/node_modules/babylon/lib/index.js:4252:13) + at Parser.pp.unexpected (/node_modules/babylon/lib/index.js:1633:8) + at Parser.pp$3.parseIdentifier (/node_modules/babylon/lib/index.js:4128:10) + at Parser.pp$3.parseExprAtom (/node_modules/babylon/lib/index.js:3490:21) + at Parser.parseExprAtom (/node_modules/babylon/lib/index.js:6408:22) + at Parser.pp$3.parseExprSubscripts (/node_modules/babylon/lib/index.js:3337:19) + at Parser.pp$3.parseMaybeUnary (/node_modules/babylon/lib/index.js:3317:19) + at Parser.pp$3.parseExprOps (/node_modules/babylon/lib/index.js:3247:19) + at Parser.pp$3.parseMaybeConditional (/node_modules/babylon/lib/index.js:3224:19) + at Parser.pp$3.parseMaybeAssign (/node_modules/babylon/lib/index.js:3187:19) +" +`; + +exports[`test yield_arrow_error2.js 1`] = ` +"function * f () { + var e = () => yield 1; +} +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +function* f() { + var e = () => yield 1; +} + +" +`; diff --git a/tests/yield/jsfmt.spec.js b/tests/yield/jsfmt.spec.js new file mode 100644 index 000000000000..989047bccc52 --- /dev/null +++ b/tests/yield/jsfmt.spec.js @@ -0,0 +1 @@ +run_spec(__dirname); diff --git a/tests/yield/yield_arrow_error.js b/tests/yield/yield_arrow_error.js new file mode 100644 index 000000000000..330a07e8ad02 --- /dev/null +++ b/tests/yield/yield_arrow_error.js @@ -0,0 +1,3 @@ +function * f () { + var e = () => { yield 1; }; +} diff --git a/tests/yield/yield_arrow_error2.js b/tests/yield/yield_arrow_error2.js new file mode 100644 index 000000000000..243ac23ee67c --- /dev/null +++ b/tests/yield/yield_arrow_error2.js @@ -0,0 +1,3 @@ +function * f () { + var e = () => yield 1; +} diff --git a/tests_config/run_spec.js b/tests_config/run_spec.js new file mode 100644 index 000000000000..a7345bb42fb0 --- /dev/null +++ b/tests_config/run_spec.js @@ -0,0 +1,80 @@ +const fs = require('fs'); +const child_process = require('child_process'); + +function run_spec(dirname) { + fs.readdirSync(dirname).forEach(filename => { + if (filename.endsWith('.js') && filename !== 'jsfmt.spec.js') { + const path = dirname + '/' + filename; + + const RUN_AST_TESTS = + // true || // UNCOMMENT! + false; + + if (!RUN_AST_TESTS) { + const source = read(path); + const output = prettyprint(path); + test(filename, () => { + expect(source + '~'.repeat(80) + '\n' + output).toMatchSnapshot(); + }); + } + + if (RUN_AST_TESTS) { + test(path + ' parse', () => { + const file = read(dirname + '/' + filename); + const ast = parse(file); + const ppfile = pp(file); + const ppast = parse(ppfile); + expect(ast).toEqual(ppast); + }); + } + + } + }); +} +global.run_spec = run_spec; + +function stripLocation(ast) { + if (Array.isArray(ast)) { + return ast.map(e => stripLocation(e)); + } + if (typeof ast === 'object') { + const newObj = {}; + for (var key in ast) { + if (key === 'loc' || key === 'range' || key === 'raw' || key === 'comments') { + continue; + } + newObj[key] = stripLocation(ast[key]); + } + return newObj; + } + return ast; +} + +function parse(string) { + const flowParser = require('flow-parser'); + return stripLocation(flowParser.parse(string)); +} + +function prettyprint(path) { + const result = child_process.spawnSync( + './bin/jscodefmt', + [path], + ); + return ( + result.stdout.toString() || + result.stderr.toString() + .replace(new RegExp(process.cwd(), 'g'), '') + ); +} + +function pp(string) { + const tmp = 'tmp' + Math.random() + '.js'; + fs.writeFileSync(tmp, string); + const result = prettyprint(tmp); + fs.unlinkSync(tmp); + return result; +} + +function read(filename) { + return fs.readFileSync(filename, 'utf8'); +}