Skip to content

fix(es/parser): close remaining Flow parser gaps for #11729 (phase 2)#11740

Merged
kdy1 merged 2 commits intomainfrom
kdy1/fix-11729-phase2
Mar 26, 2026
Merged

fix(es/parser): close remaining Flow parser gaps for #11729 (phase 2)#11740
kdy1 merged 2 commits intomainfrom
kdy1/fix-11729-phase2

Conversation

@kdy1
Copy link
Copy Markdown
Member

@kdy1 kdy1 commented Mar 25, 2026

Summary

  • close the remaining RN Flow parser gaps tracked by Flow parser fails to parse valid Flow syntax #11729
  • in Flow component type contexts, accept rest type forms like ...AnimatedProps<Props>, ...Props<any, T>, and ...{ ... }
  • preserve non-declare component declaration behavior (component Foo(...rest) {}) by keeping named-rest parsing there
  • allow anonymous typed params in Flow signature/member contexts (including nested function-type params) while still preferring named-param parsing when :, ?, or = markers are present
  • prevent decorator parsing from consuming @@... in Flow mode and parse @@ident keys as string keys ("@@ident")
  • add Flow fixtures for phase 2 coverage under crates/swc_ecma_parser/tests/flow/issue-11729-phase2

Testing

  • git submodule update --init --recursive
  • UPDATE=1 cargo test -p swc_ecma_parser
  • cargo test -p swc_ecma_parser
  • cargo fmt --all
  • cargo clippy --all --all-targets -- -D warnings
  • cargo test -p swc_ecma_parser --features flow --test flow -- --ignored

Closes #11729

@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Mar 25, 2026

⚠️ No Changeset found

Latest commit: 39f65b5

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@kdy1 kdy1 changed the title fix(parser): close remaining Flow parser gaps for #11729 (phase 2) fix(es/parser): close remaining Flow parser gaps for #11729 (phase 2) Mar 25, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 25, 2026

Binary Sizes

File Size
swc.linux-x64-gnu.node 28M (29069896 bytes)

Commit: 11259b2

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Mar 25, 2026

Merging this PR will not alter performance

✅ 215 untouched benchmarks
⏩ 4 skipped benchmarks1


Comparing kdy1/fix-11729-phase2 (39f65b5) with main (886fe53)

Open in CodSpeed

Footnotes

  1. 4 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@kdy1 kdy1 marked this pull request as ready for review March 26, 2026 10:59
@kdy1 kdy1 requested a review from a team as a code owner March 26, 2026 10:59
Copilot AI review requested due to automatic review settings March 26, 2026 10:59
@kdy1 kdy1 merged commit 8d36f05 into main Mar 26, 2026
114 of 115 checks passed
@kdy1 kdy1 deleted the kdy1/fix-11729-phase2 branch March 26, 2026 10:59
@github-actions github-actions Bot added this to the Planned milestone Mar 26, 2026
@claude
Copy link
Copy Markdown
Contributor

claude Bot commented Mar 26, 2026

PR Review: fix(es/parser): close remaining Flow parser gaps for #11729 (phase 2)

Overall

Good work closing the remaining Flow parser gaps. The approach of using speculative parsing (try_parse_ts) for anonymous typed params and falling back to named-param parsing is sound. The test fixture covers the key new scenarios well. A few observations below.

Code Quality

  1. Duplicated @@ident parsing logic — The @@ident"@@ident" string key construction appears in three places with near-identical code:

    • parse_prop_name in mod.rs (line ~772–786)
    • parse_ts_property_name in typescript.rs (line ~3579–3599)
    • Decorator break guard in class_and_fn.rs (line ~81–83)

    The first two share the same pattern: bump @, bump @, assert word, build Str with format!("@@{key}"). Consider extracting a small helper (e.g. parse_flow_at_at_key) to reduce duplication and ensure consistent behavior if the logic ever needs to change.

  2. format! allocation in hot pathformat!("@@{key}").into() allocates a temporary String on each call. For well-known symbols like @@iterator, @@asyncIterator, @@toPrimitive, etc., you could use atom!("@@iterator") directly via a match, or at minimum use a small-string optimization. This is minor since it only triggers in Flow mode for @@ keys, but worth noting.

  3. Large flow-specific branch in parse_ts_binding_list_for_signature — The new ~80-line Flow branch (lines 2560–2639) duplicates significant logic from parse_formal_params (rest pattern handling, assignment pattern fallback, ? after rest error, comma-after-rest error). This is a maintenance risk — if the shared logic changes, it's easy to miss this branch. Consider whether the flow-specific part (anonymous param detection) could be integrated more tightly with the existing path rather than forking the entire loop.

Potential Issues

  1. QuestionMark in flow_starts_like_anon_signature_param_typeToken::QuestionMark is listed as a token that starts an anonymous type param, but it's also one of the bail-out tokens in try_parse_flow_anon_signature_param (line 3207: Token::Colon | Token::QuestionMark | Token::Eq). If the current token is ? and the speculative parse tries parse_ts_type, it may succeed (e.g. parsing a conditional/optional type) or fail — either way try_parse_ts will handle it. But it means we always attempt a full speculative type parse for ? tokens that are actually named-param optionality markers. This is correct but potentially wasteful; a targeted peek could short-circuit this.

  2. Asterisk in flow_starts_like_anon_signature_param_type — Similarly, Token::Asterisk is listed. In Flow, * can appear as a generator marker or existential type (*). Make sure this doesn't cause false positives in non-type contexts that reach this code path (the InType context guard in try_parse_flow_anon_signature_param should prevent this, but worth verifying).

  3. component_rest synthetic bindingmake_flow_component_rest_fallback_binding creates a Pat::Ident with name "component_rest" and a span that covers the entire rest expression (self.span(start)). If a user's code happens to have a parameter named component_rest, this synthetic name could potentially collide in downstream analysis. The existing make_flow_component_fallback_binding uses "component_prop" — are these names documented/guaranteed not to conflict? The anon fn param uses __flow_anon_param_{index} with double-underscore prefix which is a bit safer.

Test Coverage

  1. The fixture basic.js covers:

    • @@iterator class method keys
    • Anonymous typed params in function types (($ReadOnlyArray<IgnorePattern>): void)
    • Callback params with anonymous function types ((agent: ReactDevToolsAgent) => void)
    • Generic intersection function types (GetMethod)
    • Rest type forms: ...AnimatedProps<Props>, ...GenericProps<any, string>, ...{ mode: ... }

    This looks solid. Consider also adding edge cases:

    • @@ followed by a non-identifier (error recovery)
    • Mixed named and anonymous params in the same signature
    • Nested component types with rest types

Minor

  1. The visibility change fn parse_formal_param_patpub(crate) fn parse_formal_param_pat is fine since it stays crate-internal, but add a brief comment on why it needs wider visibility (called from typescript.rs).

Summary

The core logic is correct and well-tested. The main suggestions are around reducing code duplication (especially the @@ parsing and the forked binding-list loop) and a couple of edge cases worth stress-testing. Nice work on the speculative parsing approach for anonymous typed params.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends swc_ecma_parser’s Flow support to cover additional React Native Flow syntax patterns tracked in #11729, and adds fixture coverage for the new parsing behavior.

Changes:

  • Extend Flow component parameter parsing to accept rest type forms in component type contexts (e.g. ...AnimatedProps<Props>, ...{ ... }) while preserving named-rest behavior in non-declare component declarations.
  • Allow anonymous typed parameters in Flow signature/member contexts (including nested function-type params), and prevent decorator parsing from consuming @@... in Flow mode by parsing @@ident keys as string keys.
  • Add a new Flow fixture suite (issue-11729-phase2) with config + source + expected AST output.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
crates/swc_ecma_parser/src/parser/typescript.rs Main Flow parsing adjustments: component rest-type parsing, Flow anon signature param handling, and @@ident property name handling.
crates/swc_ecma_parser/src/parser/pat.rs Makes parse_formal_param_pat pub(crate) for reuse by Flow-in-type signature parsing.
crates/swc_ecma_parser/src/parser/mod.rs Adds Flow @@ident support to parse_prop_name (string key).
crates/swc_ecma_parser/src/parser/class_and_fn.rs Stops decorator parsing at @@ in Flow mode so @@ident can be parsed as a key.
crates/swc_ecma_parser/tests/flow/issue-11729-phase2/config.json Enables Flow components syntax for the new fixture directory.
crates/swc_ecma_parser/tests/flow/issue-11729-phase2/basic.js New Flow source fixture covering the reported RN patterns.
crates/swc_ecma_parser/tests/flow/issue-11729-phase2/basic.js.json Expected AST output for the new fixture.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

return peek!(self).is_some_and(|peek| peek == Token::LBrace);
}

cur.is_word() && peek!(self).is_some_and(|peek| peek == Token::Lt || peek == Token::LShift)
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flow_starts_like_anon_signature_param_type only treats word tokens as anonymous parameter types when followed by </<<. This means anonymous params whose type is a plain identifier (e.g. MethodName / Foo) won’t be parsed via try_parse_flow_anon_signature_param and will instead be treated as a named parameter with no type annotation. Consider broadening the start check (or relying on the post-parse_ts_type delimiter/marker checks) so identifier-only anonymous param types are handled consistently with other anon-param types.

Suggested change
cur.is_word() && peek!(self).is_some_and(|peek| peek == Token::Lt || peek == Token::LShift)
if cur.is_word() {
// Treat identifier-like tokens as potential anonymous parameter types
// unless they are immediately followed by a delimiter that clearly
// indicates a named parameter (`id:`, `id?`, or `id =`).
return !peek!(self)
.is_some_and(|peek| matches!(peek, Token::Colon | Token::QuestionMark | Token::Eq));
}
false

Copilot uses AI. Check for mistakes.
_ => unexpected!(
self,
p,
"an identifier, [ for an array pattern, { for an object patter or ... for a \
Copy link

Copilot AI Mar 26, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the unexpected! message: "object patter" should be "object pattern".

Suggested change
"an identifier, [ for an array pattern, { for an object patter or ... for a \
"an identifier, [ for an array pattern, { for an object pattern or ... for a \

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39f65b5ffc

ℹ️ 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".

Comment on lines +772 to +775
} else if p.syntax().flow()
&& cur == Token::At
&& peek!(p).is_some_and(|peek| peek == Token::At)
{
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict @@ key parsing to declaration/type contexts

parse_prop_name is reused by runtime object/class member parsing as well as Flow declaration parsing, so this new flow && @@ fast-path now accepts value-level syntax that should still be rejected. In Flow mode, inputs like ({ @@iterator() {} }) or class C { @@iterator() {} } will be interpreted as string-key members instead of producing a syntax error, which changes parser correctness outside the intended declare/type-member cases. Please gate this branch to the specific Flow declaration/type contexts that actually support @@ident keys.

Useful? React with 👍 / 👎.

@github-actions github-actions Bot modified the milestones: Planned, 1.15.24 Apr 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Flow parser fails to parse valid Flow syntax

2 participants