From 0851b3ebb56747a35cf3cd44526f4bf490869a51 Mon Sep 17 00:00:00 2001 From: George Zahariev Date: Wed, 1 Sep 2021 21:51:16 -0700 Subject: [PATCH] [parser] Parse import.meta Summary: Allows parsing of `import.meta`, which is in the latest standard (from ES2020). While we don't type-check it or other `MetaProperty`s (e.g. `new.target`), at least it's not a parse error so someone can just use `$FlowFixMe` now. There was a PR for this but it was 3 years old, didn't have parser tests, so I just implemented from scratch myself here instead. Fixes #6913 Closes #6958 Changelog: [feature] Added parser support for `import.meta` Reviewed By: mroch Differential Revision: D30716916 fbshipit-source-id: eb5c5ec53d34d46c228e89137d6a4da8d0839e84 --- src/parser/expression_parser.ml | 51 ++++++++++++++---- src/parser/parser_flow.ml | 4 +- .../test/flow/meta_property/import_meta.js | 1 + .../flow/meta_property/import_meta.tree.json | 35 ++++++++++++ .../flow/meta_property/import_meta_assign.js | 1 + .../import_meta_assign.tree.json | 54 +++++++++++++++++++ .../flow/meta_property/import_not_meta.js | 1 + .../meta_property/import_not_meta.tree.json | 41 ++++++++++++++ 8 files changed, 177 insertions(+), 11 deletions(-) create mode 100644 src/parser/test/flow/meta_property/import_meta.js create mode 100644 src/parser/test/flow/meta_property/import_meta.tree.json create mode 100644 src/parser/test/flow/meta_property/import_meta_assign.js create mode 100644 src/parser/test/flow/meta_property/import_meta_assign.tree.json create mode 100644 src/parser/test/flow/meta_property/import_not_meta.js create mode 100644 src/parser/test/flow/meta_property/import_not_meta.tree.json diff --git a/src/parser/expression_parser.ml b/src/parser/expression_parser.ml index dbdd368b27e..37ef4941cad 100644 --- a/src/parser/expression_parser.ml +++ b/src/parser/expression_parser.ml @@ -69,6 +69,14 @@ module Expression comments = _; } ) -> false + | ( _, + MetaProperty + { + MetaProperty.meta = (_, { Identifier.name = "import"; comments = _ }); + property = (_, { Identifier.name = "meta"; comments = _ }); + comments = _; + } ) -> + false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *) | (_, Array _) | (_, Identifier _) @@ -258,6 +266,14 @@ module Expression comments = _; } ) -> false + | ( _, + MetaProperty + { + MetaProperty.meta = (_, { Identifier.name = "import"; comments = _ }); + property = (_, { Identifier.name = "meta"; comments = _ }); + comments = _; + } ) -> + false (* #sec-static-semantics-static-semantics-isvalidsimpleassignmenttarget *) | (_, Identifier _) | (_, Member _) @@ -677,17 +693,32 @@ module Expression with_loc (fun env -> let leading = Peek.comments env in + let start_loc = Peek.loc env in Expect.token env T_IMPORT; - let leading_arg = Peek.comments env in - Expect.token env T_LPAREN; - let argument = add_comments (assignment (with_no_in false env)) ~leading:leading_arg in - Expect.token env T_RPAREN; - let trailing = Eat.trailing_comments env in - Expression.Import - { - Expression.Import.argument; - comments = Flow_ast_utils.mk_comments_opt ~leading ~trailing (); - }) + if Eat.maybe env T_PERIOD then ( + (* import.meta *) + let import_ident = Flow_ast_utils.ident_of_source (start_loc, "import") in + let meta_loc = Peek.loc env in + Expect.identifier env "meta"; + let meta_ident = Flow_ast_utils.ident_of_source (meta_loc, "meta") in + let trailing = Eat.trailing_comments env in + Expression.MetaProperty + { + Expression.MetaProperty.meta = import_ident; + property = meta_ident; + comments = Flow_ast_utils.mk_comments_opt ~leading ~trailing (); + } + ) else + let leading_arg = Peek.comments env in + Expect.token env T_LPAREN; + let argument = add_comments (assignment (with_no_in false env)) ~leading:leading_arg in + Expect.token env T_RPAREN; + let trailing = Eat.trailing_comments env in + Expression.Import + { + Expression.Import.argument; + comments = Flow_ast_utils.mk_comments_opt ~leading ~trailing (); + }) env and call_cover ?(allow_optional_chain = true) ?(in_optional_chain = false) env start_loc left = diff --git a/src/parser/parser_flow.ml b/src/parser/parser_flow.ml index f52c7f9f0dc..64acbbc59e4 100644 --- a/src/parser/parser_flow.ml +++ b/src/parser/parser_flow.ml @@ -135,7 +135,9 @@ module rec Parse : PARSER = struct error_on_decorators env decorators; let statement = match Peek.ith_token ~i:1 env with - | T_LPAREN -> Statement.expression env + | T_LPAREN (* import(...) *) + | T_PERIOD (* import.meta *) -> + Statement.expression env | _ -> Statement.import_declaration env in statement diff --git a/src/parser/test/flow/meta_property/import_meta.js b/src/parser/test/flow/meta_property/import_meta.js new file mode 100644 index 00000000000..e06e1e4da63 --- /dev/null +++ b/src/parser/test/flow/meta_property/import_meta.js @@ -0,0 +1 @@ +import.meta; diff --git a/src/parser/test/flow/meta_property/import_meta.tree.json b/src/parser/test/flow/meta_property/import_meta.tree.json new file mode 100644 index 00000000000..2ece0e70321 --- /dev/null +++ b/src/parser/test/flow/meta_property/import_meta.tree.json @@ -0,0 +1,35 @@ +{ + "type":"Program", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":12}}, + "range":[0,12], + "body":[ + { + "type":"ExpressionStatement", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":12}}, + "range":[0,12], + "expression":{ + "type":"MetaProperty", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":11}}, + "range":[0,11], + "meta":{ + "type":"Identifier", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":6}}, + "range":[0,6], + "name":"import", + "typeAnnotation":null, + "optional":false + }, + "property":{ + "type":"Identifier", + "loc":{"source":null,"start":{"line":1,"column":7},"end":{"line":1,"column":11}}, + "range":[7,11], + "name":"meta", + "typeAnnotation":null, + "optional":false + } + }, + "directive":null + } + ], + "comments":[] +} diff --git a/src/parser/test/flow/meta_property/import_meta_assign.js b/src/parser/test/flow/meta_property/import_meta_assign.js new file mode 100644 index 00000000000..d15b45f9b8b --- /dev/null +++ b/src/parser/test/flow/meta_property/import_meta_assign.js @@ -0,0 +1 @@ +import.meta = 1; diff --git a/src/parser/test/flow/meta_property/import_meta_assign.tree.json b/src/parser/test/flow/meta_property/import_meta_assign.tree.json new file mode 100644 index 00000000000..5bb0b95aad9 --- /dev/null +++ b/src/parser/test/flow/meta_property/import_meta_assign.tree.json @@ -0,0 +1,54 @@ +{ + "errors":[ + { + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":11}}, + "message":"Invalid left-hand side in assignment" + } + ], + "type":"Program", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":16}}, + "range":[0,16], + "body":[ + { + "type":"ExpressionStatement", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":16}}, + "range":[0,16], + "expression":{ + "type":"AssignmentExpression", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":15}}, + "range":[0,15], + "operator":"=", + "left":{ + "type":"MetaProperty", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":11}}, + "range":[0,11], + "meta":{ + "type":"Identifier", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":6}}, + "range":[0,6], + "name":"import", + "typeAnnotation":null, + "optional":false + }, + "property":{ + "type":"Identifier", + "loc":{"source":null,"start":{"line":1,"column":7},"end":{"line":1,"column":11}}, + "range":[7,11], + "name":"meta", + "typeAnnotation":null, + "optional":false + } + }, + "right":{ + "type":"Literal", + "loc":{"source":null,"start":{"line":1,"column":14},"end":{"line":1,"column":15}}, + "range":[14,15], + "value":1, + "raw":"1" + } + }, + "directive":null + } + ], + "comments":[] +} diff --git a/src/parser/test/flow/meta_property/import_not_meta.js b/src/parser/test/flow/meta_property/import_not_meta.js new file mode 100644 index 00000000000..33392b9363b --- /dev/null +++ b/src/parser/test/flow/meta_property/import_not_meta.js @@ -0,0 +1 @@ +import.foo; diff --git a/src/parser/test/flow/meta_property/import_not_meta.tree.json b/src/parser/test/flow/meta_property/import_not_meta.tree.json new file mode 100644 index 00000000000..a4cf802977b --- /dev/null +++ b/src/parser/test/flow/meta_property/import_not_meta.tree.json @@ -0,0 +1,41 @@ +{ + "errors":[ + { + "loc":{"source":null,"start":{"line":1,"column":7},"end":{"line":1,"column":10}}, + "message":"Unexpected identifier, expected the identifier `meta`" + } + ], + "type":"Program", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":11}}, + "range":[0,11], + "body":[ + { + "type":"ExpressionStatement", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":11}}, + "range":[0,11], + "expression":{ + "type":"MetaProperty", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":10}}, + "range":[0,10], + "meta":{ + "type":"Identifier", + "loc":{"source":null,"start":{"line":1,"column":0},"end":{"line":1,"column":6}}, + "range":[0,6], + "name":"import", + "typeAnnotation":null, + "optional":false + }, + "property":{ + "type":"Identifier", + "loc":{"source":null,"start":{"line":1,"column":7},"end":{"line":1,"column":10}}, + "range":[7,10], + "name":"meta", + "typeAnnotation":null, + "optional":false + } + }, + "directive":null + } + ], + "comments":[] +}