diff --git a/src/commands/commandUtils.ml b/src/commands/commandUtils.ml
index 11796e851c0..937e475c8af 100644
--- a/src/commands/commandUtils.ml
+++ b/src/commands/commandUtils.ml
@@ -1100,6 +1100,7 @@ let make_options ~flowconfig_name ~flowconfig ~lazy_mode ~root (options_flags: O
opt_recursion_limit = FlowConfig.recursion_limit flowconfig;
opt_max_files_checked_per_worker = FlowConfig.max_files_checked_per_worker flowconfig;
opt_type_asserts = FlowConfig.type_asserts flowconfig;
+ opt_jsx_pragma = FlowConfig.jsx_pragma flowconfig;
}
let make_env flowconfig_name connect_flags root =
diff --git a/src/commands/config/flowConfig.ml b/src/commands/config/flowConfig.ml
index 475cdabd1da..afd6fa5da98 100644
--- a/src/commands/config/flowConfig.ml
+++ b/src/commands/config/flowConfig.ml
@@ -101,6 +101,7 @@ module Opts = struct
types_first: bool;
wait_for_recheck: bool;
weak: bool;
+ jsx_pragma: string option;
}
let warn_on_unknown_opts (raw_opts, config) : (t * warning list, error) result =
@@ -192,6 +193,7 @@ module Opts = struct
types_first = false;
wait_for_recheck = false;
weak = false;
+ jsx_pragma = None;
}
let parse_lines : line list -> (raw_options, error) result =
@@ -634,6 +636,9 @@ module Opts = struct
"experimental.types_first.max_files_checked_per_worker",
uint (fun opts v -> Ok { opts with max_files_checked_per_worker = v });
+
+ "jsx.pragma",
+ string (fun opts v -> Ok { opts with jsx_pragma = Some v });
]
let parse =
@@ -1070,6 +1075,7 @@ let traces c = c.options.Opts.traces
let trust_mode c = c.options.Opts.trust_mode
let type_asserts c = c.options.Opts.type_asserts
let types_first c = c.options.Opts.types_first
+let jsx_pragma c = c.options.Opts.jsx_pragma
let required_version c = c.version
let wait_for_recheck c = c.options.Opts.wait_for_recheck
let weak c = c.options.Opts.weak
diff --git a/src/commands/config/flowConfig.mli b/src/commands/config/flowConfig.mli
index 45a21a30355..8ade9b29af4 100644
--- a/src/commands/config/flowConfig.mli
+++ b/src/commands/config/flowConfig.mli
@@ -95,6 +95,7 @@ val traces: config -> int
val trust_mode: config -> Options.trust_mode
val type_asserts: config -> bool
val types_first: config -> bool
+val jsx_pragma: config -> string option
val wait_for_recheck: config -> bool
val weak: config -> bool
diff --git a/src/common/options.ml b/src/common/options.ml
index 6ff71845b17..05c19c05b04 100644
--- a/src/common/options.ml
+++ b/src/common/options.ml
@@ -117,6 +117,7 @@ type t = {
opt_include_suppressions : bool;
opt_trust_mode: trust_mode;
opt_type_asserts: bool;
+ opt_jsx_pragma: string option;
}
let all opts = opts.opt_all
@@ -182,6 +183,7 @@ let strict_mode opts = opts.opt_strict_mode
let trust_mode opts = opts.opt_trust_mode
let type_asserts opts = opts.opt_type_asserts
+let jsx_pragma opts = opts.opt_jsx_pragma
let lazy_mode_to_string lazy_mode =
diff --git a/src/parsing/parsing_service_js.ml b/src/parsing/parsing_service_js.ml
index 20c97ee2e7d..8f9fbf14761 100644
--- a/src/parsing/parsing_service_js.ml
+++ b/src/parsing/parsing_service_js.ml
@@ -472,7 +472,7 @@ let does_content_match_file_hash ~reader file content =
* Add success/error info to passed accumulator. *)
let reducer
~worker_mutator ~reader ~parse_options ~skip_hash_mismatch
- ~max_header_tokens ~noflow ~parse_unchanged
+ ~max_header_tokens ~noflow ~jsx_pragma ~parse_unchanged
parse_results file
: results =
(* It turns out that sometimes files appear and disappear very quickly. Just
@@ -525,6 +525,13 @@ let reducer
if noflow file then { info with Docblock.flow = Some Docblock.OptOut }
else info
in
+ let info = match jsx_pragma with
+ | Some jsx_pragma ->
+ let padding = (String.make 1 '\n') ^ (String.make 1 ' ') in
+ let (jsx_expr, _) = Parser_flow.jsx_pragma_expression (padding ^ jsx_pragma) (Some file) in
+ { info with Docblock.jsx = Some (Docblock.Jsx_pragma (jsx_pragma, jsx_expr)) }
+ | None -> info
+ in
begin match (do_parse ~parse_options ~info content file) with
| Parse_ok parse_ok ->
let ast, file_sig = basic parse_ok in
@@ -602,13 +609,13 @@ let next_of_filename_set ?(with_progress=false) workers filenames =
else MultiWorkerLwt.next workers (FilenameSet.elements filenames)
let parse ~worker_mutator ~reader ~parse_options ~skip_hash_mismatch ~profile
- ~max_header_tokens ~noflow ~parse_unchanged workers next
+ ~max_header_tokens ~noflow ~jsx_pragma ~parse_unchanged workers next
: results Lwt.t =
let t = Unix.gettimeofday () in
let reducer =
reducer
~worker_mutator ~reader ~parse_options ~skip_hash_mismatch
- ~max_header_tokens ~noflow ~parse_unchanged
+ ~max_header_tokens ~noflow ~jsx_pragma ~parse_unchanged
in
let%lwt results = MultiWorkerLwt.call
workers
@@ -632,7 +639,7 @@ let parse ~worker_mutator ~reader ~parse_options ~skip_hash_mismatch ~profile
Lwt.return results
let reparse
- ~transaction ~reader ~parse_options ~profile ~max_header_tokens ~noflow
+ ~transaction ~reader ~parse_options ~profile ~max_header_tokens ~noflow ~jsx_pragma
~parse_unchanged ~with_progress ~workers ~modified:files ~deleted =
(* save old parsing info for files *)
let all_files = FilenameSet.union files deleted in
@@ -640,7 +647,7 @@ let reparse
let next = next_of_filename_set ?with_progress workers files in
let%lwt results =
parse ~worker_mutator ~reader ~parse_options ~skip_hash_mismatch:false ~profile
- ~max_header_tokens ~noflow ~parse_unchanged workers next
+ ~max_header_tokens ~noflow ~jsx_pragma ~parse_unchanged workers next
in
let modified = results.parse_ok |> FilenameMap.keys |> FilenameSet.of_list in
let modified = List.fold_left (fun acc (fail, _, _) ->
@@ -664,6 +671,7 @@ let parse_with_defaults ?types_mode ?use_strict ~reader options workers next =
let facebook_fbt = Options.facebook_fbt options in
let arch = Options.arch options in
let abstract_locations = options.Options.opt_abstract_locations in
+ let jsx_pragma = Options.jsx_pragma options in
let parse_options =
make_parse_options ~arch ~abstract_locations ~types_mode ~use_strict ~module_ref_prefix
~facebook_fbt ()
@@ -673,7 +681,7 @@ let parse_with_defaults ?types_mode ?use_strict ~reader options workers next =
let worker_mutator = Parsing_heaps.Parse_mutator.create () in
parse
~worker_mutator ~reader ~parse_options ~skip_hash_mismatch:false
- ~profile ~max_header_tokens ~noflow ~parse_unchanged workers next
+ ~profile ~max_header_tokens ~noflow ~jsx_pragma ~parse_unchanged workers next
let reparse_with_defaults
~transaction ~reader ?types_mode ?use_strict ?with_progress
@@ -686,12 +694,13 @@ let reparse_with_defaults
let facebook_fbt = Options.facebook_fbt options in
let arch = Options.arch options in
let abstract_locations = options.Options.opt_abstract_locations in
+ let jsx_pragma = Options.jsx_pragma options in
let parse_options =
make_parse_options ~arch ~abstract_locations ~types_mode ~use_strict ~module_ref_prefix
~facebook_fbt ()
in
reparse
- ~transaction ~reader ~parse_options ~profile ~max_header_tokens ~noflow
+ ~transaction ~reader ~parse_options ~profile ~max_header_tokens ~noflow ~jsx_pragma
~parse_unchanged ~with_progress ~workers ~modified ~deleted
(* ensure_parsed takes a set of files, finds the files which haven't been parsed, and parses them.
@@ -730,6 +739,7 @@ let ensure_parsed ~reader options workers files =
let facebook_fbt = Options.facebook_fbt options in
let arch = Options.arch options in
let abstract_locations = options.Options.opt_abstract_locations in
+ let jsx_pragma = Options.jsx_pragma options in
let parse_options =
make_parse_options ~types_mode ~use_strict ~module_ref_prefix ~facebook_fbt ~arch
@@ -738,7 +748,7 @@ let ensure_parsed ~reader options workers files =
let%lwt results = parse
~worker_mutator ~reader ~parse_options ~skip_hash_mismatch:true
- ~profile ~max_header_tokens ~noflow ~parse_unchanged workers next
+ ~profile ~max_header_tokens ~noflow ~jsx_pragma ~parse_unchanged workers next
in
Lwt.return results.parse_hash_mismatch_skips
diff --git a/tests/jsx_pragma_option/.flowconfig b/tests/jsx_pragma_option/.flowconfig
new file mode 100644
index 00000000000..e3502af3b06
--- /dev/null
+++ b/tests/jsx_pragma_option/.flowconfig
@@ -0,0 +1,2 @@
+[options]
+jsx.pragma=bar
diff --git a/tests/jsx_pragma_option/index.js b/tests/jsx_pragma_option/index.js
new file mode 100644
index 00000000000..529ad1e4079
--- /dev/null
+++ b/tests/jsx_pragma_option/index.js
@@ -0,0 +1,10 @@
+//@flow
+
+import { bar } from './jsx'
+
+
+// ok
+const Hello = ;
+
+// error
+const Bye = ;
diff --git a/tests/jsx_pragma_option/jsx.js b/tests/jsx_pragma_option/jsx.js
new file mode 100644
index 00000000000..1d2762db23a
--- /dev/null
+++ b/tests/jsx_pragma_option/jsx.js
@@ -0,0 +1,5 @@
+//@flow
+
+declare export var bar: {
+ (type: 'hello', props: {|a: string|}, children: any): {| hello: 'div' |}
+}
diff --git a/tests/jsx_pragma_option/jsx_pragma_option.exp b/tests/jsx_pragma_option/jsx_pragma_option.exp
new file mode 100644
index 00000000000..cd43568ef97
--- /dev/null
+++ b/tests/jsx_pragma_option/jsx_pragma_option.exp
@@ -0,0 +1,24 @@
+Error --------------------------------------------------------------------------------------------------- index.js:10:13
+
+Cannot create `a` element because:
+ - `a` [1] is incompatible with string literal `hello` [2].
+ - inexact null [3] is incompatible with exact object type [4].
+
+ index.js:10:13
+ 10| const Bye = ;
+ ^^^^^ [3]
+
+References:
+ index.js:10:14
+ 10| const Bye = ;
+ ^ [1]
+ jsx.js:4:10
+ 4| (type: 'hello', props: {|a: string|}, children: any): {| hello: 'div' |}
+ ^^^^^^^ [2]
+ jsx.js:4:26
+ 4| (type: 'hello', props: {|a: string|}, children: any): {| hello: 'div' |}
+ ^^^^^^^^^^^^^ [4]
+
+
+
+Found 2 errors