feat(parser): complete Hermes Flow stripping parity#11702
Conversation
|
Binary Sizes
Commit: dd86413 |
PR Review: feat(parser): complete Hermes Flow stripping parityOverall this is a solid, well-structured PR that adds substantial Flow syntax support (components, hooks, pattern matching, decorators) and backs it up with a thorough strip correctness test. A few observations: Code QualityGood:
Suggestions:
Potential Bugs / Issues
Performance Considerations
Test Coverage
Minor Nits
SecurityNo concerns — this is purely parsing/AST lowering with no I/O or external input beyond source files. Verdict: This is high-quality work that significantly advances Flow support. The main actionable items are (1) verifying the |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f8ee699693
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| is_async: false, | ||
| is_generator: false, |
There was a problem hiding this comment.
Preserve enclosing async/generator context in match expr lowering
flow_match_make_iife_expr always wraps a match (...) { ... } expression in a plain function () { ... }() with is_async/is_generator hard-coded to false. In an async function, an arm like 1: await foo() now strips to return await foo() inside a non-async function, which makes the emitted JS invalid; in generators it similarly breaks yield, and it also changes lexical captures such as this and arguments.
Useful? React with 👍 / 👎.
| bindings.push(FlowMatchBindingInit { | ||
| kind: binding.kind, | ||
| pat: binding.pat.clone(), | ||
| init: value, | ||
| span: binding.span, |
There was a problem hiding this comment.
Compute object rest bindings from unmatched properties
For object patterns with a rest binding, the lowering currently initializes the binding from the entire subject object. For example, match (x) { {const a, ...const rest}: rest } will bind rest to x, not to x without a. That makes every supported object-rest case return the wrong runtime value even though pattern-object.js now exercises these forms.
Useful? React with 👍 / 👎.
| if self.input().syntax().flow_components() { | ||
| if self.is_flow_contextual_word("component") { | ||
| self.bump(); | ||
| return self.parse_flow_component_type(start).map(Box::new); | ||
| } |
There was a problem hiding this comment.
Keep
component contextual when parsing Flow types
This branch unconditionally treats any type-position identifier named component as the start of a Flow component type. With FlowSyntax.components enabled, valid references like type T = component; now fail because parse_flow_component_type immediately expects (; the adjacent hook branch has the same problem. These keywords need lookahead before they steal ordinary type identifiers.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Pull request overview
Adds support for additional Hermes/Flow syntax extensions (Flow decorators, component/hook syntax, and match pattern matching) and introduces a new SWC-level fixture test to ensure Flow stripping produces re-parsable JavaScript for the Hermes corpus.
Changes:
- Extend
FlowSyntaxwith new feature toggles (decorators,components,pattern_matching) and wire them intoSyntaxFlags. - Implement parsing/lowering for Flow
component/hookdeclarations/types and Flowmatchexpressions/statements. - Add
flow_strip_hermestest + newknown-fail-strip.txt, and reset the Hermes parserknown-fail.txtgeneration to be empty.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/swc/tests/flow_strip_hermes.rs | New integration test compiling the Hermes Flow corpus through SWC Flow-strip + ES reparse. |
| crates/swc_ecma_parser/tests/flow-hermes/known-fail.txt | Emptied experimental known-fail list (now generated as empty). |
| crates/swc_ecma_parser/tests/flow-hermes/known-fail-strip.txt | New list of Flow-strip known-failing fixtures. |
| crates/swc_ecma_parser/tests/flow_hermes.rs | Reads new per-fixture options and enables Flow decorators/components/pattern-matching flags. |
| crates/swc_ecma_parser/src/syntax.rs | Adds new FlowSyntax flags, serde aliases, and new SyntaxFlags bits/accessors. |
| crates/swc_ecma_parser/src/parser/typescript.rs | Adds Flow component/hook parsing support in the TS/Flow parser path. |
| crates/swc_ecma_parser/src/parser/stmt.rs | Adds Flow match parsing and lowering into standard JS AST constructs. |
| crates/swc_ecma_parser/src/parser/module_item.rs | Adjust decorator handling for Flow-decorators mode; export-default support for component/hook decls. |
| crates/swc_ecma_parser/src/parser/expr.rs | Recognize/parse Flow match in expression position. |
| crates/swc_ecma_parser/src/parser/class_and_fn.rs | Adjust leading-decorator error behavior when Flow decorators are enabled. |
| crates/swc_ecma_parser/scripts/sync_flow_hermes.sh | Stops generating known-fail.txt content (writes empty file). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| if let Some(Some(binding)) = rest { | ||
| bindings.push(FlowMatchBindingInit { | ||
| kind: binding.kind, | ||
| pat: binding.pat.clone(), | ||
| init: value, |
| for (key, pat) in props { | ||
| let has_key = self.flow_match_bin_expr( | ||
| span, | ||
| BinaryOp::In, | ||
| self.flow_match_prop_key_expr(key), | ||
| value.clone(), | ||
| ); | ||
| predicate = self.flow_match_and_expr(span, predicate, has_key); | ||
|
|
||
| let lowered = self.flow_match_lower_pattern( | ||
| span, | ||
| self.flow_match_member_expr(span, value.clone(), key), | ||
| pat, | ||
| ); |
| } | ||
|
|
||
| fn flow_match_make_temp_ident(&self, span: Span) -> Ident { | ||
| Ident::new_no_ctxt(format!("__match_subject_{}", span.lo.0).into(), span) |
Summary
This PR completes Hermes-based Flow stripping parity by extending parser support and adding strip correctness coverage for Hermes corpus cases.
What changed
decoratorscomponentspattern_matchingesproposal_decoratorscomponentspattern_matchingmatch/*,components/*, andhook_syntax/*fixtures.component/hookparsing with lowering to existing AST nodes:component,hook,declare component, export forms)component (...) renders T,hook (...) => T)matchparsing and lowering (statement + expression paths) underpattern_matching:|,as, guard)crates/swc/tests/flow_strip_hermes.rsexpected-errors=falsefixtures,IsModule::Unknown, no__flow_leakage, ES reparse successasync_await/migrated_0020.jsasync_await/migrated_0024.jsknown-fail.txtand updated sync script to stop category-based known-fail generation.Verification
Executed locally:
git submodule update --init --recursivecargo test -p swc_ecma_parser --test flow_hermes --features flowcargo test -p swc --test flow_strip_hermes --features flowcargo test -p swc --test flow_strip_correctness --features flow -- --ignoredcargo test -p swc_ecma_parsercargo fmt --allcargo clippy --all --all-targets -- -D warningsAdditional note:
cargo test -p swcwas also run, buttests/source_map.rs::issue_622failed duesourcemap-validatorruntime assertion (There were no mappings in the file) in local environment; this appears unrelated to the Flow/Hermes parser-strip changes.