diff --git a/src/parser/expression_parser.ml b/src/parser/expression_parser.ml index b8d872fd6d5..b4fc8f93174 100644 --- a/src/parser/expression_parser.ml +++ b/src/parser/expression_parser.ml @@ -39,6 +39,9 @@ module Expression let is_assignable_lhs = Expression.(function | _, MetaProperty { MetaProperty.meta = (_, "new"); property = (_, "target") } -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *) + | _, MetaProperty { MetaProperty.meta = (_, "import"); property = (_, "meta") } + -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *) + (* draft spec: https://tc39.github.io/proposal-import-meta/ *) | _, Array _ | _, Identifier _ @@ -193,6 +196,9 @@ module Expression and is_lhs = Expression.(function | _, MetaProperty { MetaProperty.meta = (_, "new"); property = (_, "target") } -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *) + | _, MetaProperty { MetaProperty.meta = (_, "import"); property = (_, "meta") } + -> false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *) + (* draft spec: https://tc39.github.io/proposal-import-meta/ *) | _, Identifier _ | _, Member _ @@ -534,11 +540,36 @@ module Expression super and import env = with_loc (fun env -> + let start_loc = Peek.loc env in Expect.token env T_IMPORT; - Expect.token env T_LPAREN; - let arg = assignment (with_no_in false env) in - Expect.token env T_RPAREN; - Expression.Import arg + match Peek.token env with + | T_LPAREN -> + (* "import(...)" syntax *) + Eat.token env; + let arg = assignment (with_no_in false env) in + Expect.token env T_RPAREN; + Expression.Import arg + | T_PERIOD -> begin + (* "import.meta" syntax (no other metaproperties are permitted) *) + Eat.token env; + match Peek.token env with + | T_IDENTIFIER { raw = "meta"; _ } -> + Eat.token env; + let end_loc = Peek.loc env in + Expression.(MetaProperty MetaProperty.({ + meta = start_loc, "import"; + property = end_loc, "meta"; + })) + | T_IDENTIFIER _ -> + error_at env (start_loc, Parse_error.InvalidImportMetaProperty); + Expression.Identifier (start_loc, "import") + | _ -> + error_unexpected env; + Expression.Identifier (start_loc, "import") + end + | _ -> + error_unexpected env; + Expression.Identifier (start_loc, "import") ) env and call_cover ?(allow_optional_chain=true) ?(in_optional_chain=false) env start_loc left = diff --git a/src/parser/parse_error.ml b/src/parser/parse_error.ml index 19679b88831..822911061f9 100644 --- a/src/parser/parse_error.ml +++ b/src/parser/parse_error.ml @@ -35,6 +35,7 @@ type t = | InvalidLHSInExponentiation | InvalidLHSInForIn | InvalidLHSInForOf + | InvalidImportMetaProperty | ExpectedPatternFoundExpression | MultipleDefaultsInSwitch | NoCatchOrFinally @@ -154,6 +155,7 @@ module PP = | InvalidLHSInExponentiation -> "Invalid left-hand side in exponentiation expression" | InvalidLHSInForIn -> "Invalid left-hand side in for-in" | InvalidLHSInForOf -> "Invalid left-hand side in for-of" + | InvalidImportMetaProperty -> "The only valid meta property for import is import.meta" | ExpectedPatternFoundExpression -> ( "Expected an object pattern, array pattern, or an identifier but " ^ "found an expression instead" diff --git a/src/parser/parser_flow.ml b/src/parser/parser_flow.ml index 8b68893c21a..b87a8dfe895 100644 --- a/src/parser/parser_flow.ml +++ b/src/parser/parser_flow.ml @@ -100,7 +100,7 @@ module rec Parse : PARSER = struct | T_IMPORT -> error_on_decorators env decorators; let statement = match Peek.ith_token ~i:1 env with - | T_LPAREN -> Statement.expression env + | T_LPAREN | T_PERIOD -> Statement.expression env | _ -> Statement.import_declaration env in statement | T_DECLARE when Peek.ith_token ~i:1 env = T_EXPORT -> diff --git a/tests/import_meta/.flowconfig b/tests/import_meta/.flowconfig new file mode 100644 index 00000000000..2e4a2ec92b8 --- /dev/null +++ b/tests/import_meta/.flowconfig @@ -0,0 +1,3 @@ +[options] +module.system=haste +no_flowlib=false diff --git a/tests/import_meta/import_meta.exp b/tests/import_meta/import_meta.exp new file mode 100644 index 00000000000..1e6cb09e630 --- /dev/null +++ b/tests/import_meta/import_meta.exp @@ -0,0 +1,42 @@ +Error ----------------------------------------------------------------------------------------------- import_meta.js:9:1 + +Not supported. + + 9| import.meta; + ^^^^^^^^^^^ + + +Error ---------------------------------------------------------------------------------------------- import_meta.js:12:1 + +Not supported. + + 12| import.meta.hello = "world"; + ^^^^^^^^^^^ + + +Error --------------------------------------------------------------------------------------------- import_meta.js:15:14 + +Not supported. + + 15| const meta = import.meta; + ^^^^^^^^^^^ + + +Error ---------------------------------------------------------------------------------- no_assign_to_import_meta.js:4:1 + +Invalid left-hand side in assignment + + 4| import.meta = {wat: "wat"}; // parse error + ^^^^^^^^^^^ + + +Error ----------------------------------------------------------------------------------- no_other_metaproperties.js:4:1 + +The only valid meta property for import is import.meta + + 4| import.atem; // parse error + ^^^^^^ + + + +Found 5 errors diff --git a/tests/import_meta/import_meta.js b/tests/import_meta/import_meta.js new file mode 100644 index 00000000000..9b0d7640f4d --- /dev/null +++ b/tests/import_meta/import_meta.js @@ -0,0 +1,22 @@ +// @flow + +// NOTE: The following tests all currently yield a "Not supported." +// error because Flow does not process MetaProperty expressions at all. +// The comments above each test case describe what the behavior _should_ +// be once typechecking is implemented. + +// You can access `import.meta` at the root of the module. +import.meta; + +// You can write to `import.meta` at the root of the module. +import.meta.hello = "world"; + +// You can use `import.meta` in a normal expression context. +const meta = import.meta; + +// All properties are `mixed`. +(meta.whatever: mixed); +(meta.whatnever: number); // error + +// Properties are writable. +meta.writeable = "definitely"; diff --git a/tests/import_meta/no_assign_to_import_meta.js b/tests/import_meta/no_assign_to_import_meta.js new file mode 100644 index 00000000000..3ef6b72a7a0 --- /dev/null +++ b/tests/import_meta/no_assign_to_import_meta.js @@ -0,0 +1,4 @@ +// @flow + +// You can't assign to it. +import.meta = {wat: "wat"}; // parse error diff --git a/tests/import_meta/no_other_metaproperties.js b/tests/import_meta/no_other_metaproperties.js new file mode 100644 index 00000000000..26d6fff16a4 --- /dev/null +++ b/tests/import_meta/no_other_metaproperties.js @@ -0,0 +1,4 @@ +// @flow + +// You can't access any other metaproperties on `import`. +import.atem; // parse error