Skip to content

refactor: labeled expressions implementation#244

Merged
andrii-bodnar merged 9 commits into
mainfrom
refactor/labeled-expressions
Jun 30, 2026
Merged

refactor: labeled expressions implementation#244
andrii-bodnar merged 9 commits into
mainfrom
refactor/labeled-expressions

Conversation

@timofei-iatsenko

@timofei-iatsenko timofei-iatsenko commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

This is my attempt on fixing #241 and #239

This is more systematic refactoring rather ad-hoc fix. The refactoring make closer Rust implementation to a babel's one, so they not diverge.

Previously indexes for expression were allocated during processing a Message Phase in a message builder, in babel version those indexes where assigned during AST scanning phase, so it produced a diffrent result described in #241

Additionally ph macro was not processed uniformly. It was processed in some places but were skipped in other, for example:

<Plural value={ph({count: getCount()})} / > 

With this refactoring, ph support is added everywhere and processed uniformly.

Other changes:

  1. I extracted all tests related to labeled expressions feature into separate file. It's easier to see all cases and work on the feature this way
  2. I changed internal structures,
  • TransformCtx (formerly MacroCtx) — global per-file context holding macro imports, options, directives, and runtime identifiers.
  • MacroCtx<'a> — short-lived, created fresh for each macro invocation. Borrows &'a mut TransformCtx and owns its own expression index counter starting at 0.
  • Free tokenization functions: tokenize_tpl, tokenize_expr_to_arg, try_tokenize_call_expr_as_choice_cmp, try_tokenize_expr, and get_choice_cases_from_obj are now free functions taking &mut MacroCtx explicitly, making the data flow clear.

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 90.88235% with 31 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.83%. Comparing base (32416e4) to head (43cfc14).

Files with missing lines Patch % Lines
crates/lingui_macro/src/macro_utils.rs 90.56% 20 Missing ⚠️
crates/lingui_macro/src/jsx_visitor.rs 84.05% 11 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #244      +/-   ##
==========================================
- Coverage   95.06%   94.83%   -0.24%     
==========================================
  Files           9        9              
  Lines        2251     2325      +74     
==========================================
+ Hits         2140     2205      +65     
- Misses        111      120       +9     
Flag Coverage Δ
unittests 94.83% <90.88%> (-0.24%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
crates/lingui_macro/src/ast_utils.rs 90.80% <ø> (-0.41%) ⬇️
crates/lingui_macro/src/builder.rs 99.15% <100.00%> (+0.17%) ⬆️
crates/lingui_macro/src/js_macro_folder.rs 98.42% <100.00%> (+0.06%) ⬆️
crates/lingui_macro/src/lib.rs 91.09% <100.00%> (+0.01%) ⬆️
crates/lingui_macro/src/jsx_visitor.rs 86.95% <84.05%> (-1.49%) ⬇️
crates/lingui_macro/src/macro_utils.rs 91.72% <90.56%> (+2.50%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@timofei-iatsenko timofei-iatsenko changed the title Refactor/labeled expressions refactor: labeled expressions Jun 26, 2026
@timofei-iatsenko timofei-iatsenko changed the title refactor: labeled expressions refactor: labeled expressions implementation Jun 26, 2026
@timofei-iatsenko timofei-iatsenko marked this pull request as ready for review June 29, 2026 07:21
@timofei-iatsenko timofei-iatsenko requested a review from Copilot June 29, 2026 07:21

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

Refactors the SWC Lingui macro tokenization/indexing to more closely mirror the Babel implementation, with a focus on consistent numeric placeholder allocation (source-order for ICU value, and not counting named placeholders) and uniform ph(...) handling across tokenization paths.

Changes:

  • Replaced expression/ICU-choice tokens with a unified MsgArg model (name + value + optional ICU format/cases) and updated the builder accordingly.
  • Introduced a split context model (TransformCtx per file + MacroCtx per macro invocation) and moved tokenization into free functions that operate on &mut MacroCtx.
  • Reorganized/expanded tests and snapshots for labeled expressions and added coverage for ICU value index allocation order.

Reviewed changes

Copilot reviewed 32 out of 32 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
crates/lingui_macro/src/tokens.rs Refactors message tokens to use MsgArg for expressions/ICU arguments.
crates/lingui_macro/src/macro_utils.rs Introduces TransformCtx/MacroCtx split and new tokenization helpers; adds ph(...) unwrapping and labeled-expression handling.
crates/lingui_macro/src/lib.rs Updates transform entrypoints to use the new per-invocation MacroCtx and custom JSX visitor traversal.
crates/lingui_macro/src/jsx_visitor.rs Reworks JSX traversal/tokenization to produce MsgArg tokens and handle ICU macros in source order.
crates/lingui_macro/src/js_macro_folder.rs Adapts JS macro folding to new tokenization APIs and context types.
crates/lingui_macro/src/builder.rs Updates message construction to consume MsgArg tokens (including ICU format/cases) and simplify value handling.
crates/lingui_macro/src/ast_utils.rs Removes TS as expansion helper (moved/handled elsewhere).
crates/lingui_macro/tests/labeled_expressions.rs New consolidated test file for labeled-expressions and ph scenarios (including error cases).
crates/lingui_macro/tests/jsx.rs Removes labeled-expression test cases moved into labeled_expressions.rs.
crates/lingui_macro/tests/jsx_icu.rs Adds regression tests for ICU value index allocation ordering.
crates/lingui_macro/tests/js_t.rs Removes labeled-expression test cases moved into labeled_expressions.rs.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_ph_with_non_object_arg.snap New snapshot covering invalid ph(variable) usage in JSX.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_ph_labels.snap Updates snapshot source location and removes multi-prop case (now an error test).
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_ph_labeled_expression_multiple_props.snap New snapshot covering multi-prop labeled-expression error via ph({a,b}).
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_ph_label_with_nested_plural.snap Updates snapshot source location after test move.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_nested_labels.snap Updates snapshot source location after test move.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_labeled_expression_multiple_props.snap New snapshot covering multi-prop labeled-expression error in JSX explicit label.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_icu_with_labeled_expression_as_value.snap New snapshot covering labeled-expression as ICU value.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_icu_with_labeled_expression_as_value_with_ph.snap New snapshot covering ph({count: ...}) used as ICU value.
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_explicit_labels.snap Updates snapshot source location and removes multi-prop case (now an error test).
crates/lingui_macro/tests/snapshots/labeled_expressions__jsx_explicit_labels_with_as_statement.snap Updates snapshot source location after test move.
crates/lingui_macro/tests/snapshots/labeled_expressions__js_ph_with_non_object_arg.snap New snapshot covering invalid ph(variable) usage in template literals.
crates/lingui_macro/tests/snapshots/labeled_expressions__js_ph_labels_in_tpl_literal.snap Updates snapshot source location and removes multi-prop case (now an error test).
crates/lingui_macro/tests/snapshots/labeled_expressions__js_ph_labeled_expression_multiple_props.snap New snapshot covering multi-prop labeled-expression error via ph({a,b}) in template literal.
crates/lingui_macro/tests/snapshots/labeled_expressions__js_labeled_expression_multiple_props.snap New snapshot covering multi-prop labeled-expression error in template literal explicit label.
crates/lingui_macro/tests/snapshots/labeled_expressions__js_explicit_labels_in_tpl_literal.snap Updates snapshot source location and removes multi-prop case (now an error test).
crates/lingui_macro/tests/snapshots/labeled_expressions__js_choice_labels_in_tpl_literal.snap Updates snapshot source location after test move.
crates/lingui_macro/tests/snapshots/jsx_icu__with_value_index_in_source_order.snap New regression snapshot for source-order ICU value index allocation.
crates/lingui_macro/tests/snapshots/jsx_icu__with_non_identifier_value_first.snap New regression snapshot for ICU value when it appears first.
crates/lingui_macro/tests/snapshots/js_t__js_substitution_in_tpl_literal.snap Snapshot updates reflecting new values ordering/allocation behavior.
crates/lingui_macro/tests/snapshots/js_t__js_custom_i18n_passed.snap Snapshot updates reflecting new values ordering/allocation behavior.
crates/lingui_macro/tests/snapshots/js_icu__js_choices_may_contain_expressions.snap Snapshot updates reflecting new values ordering/allocation behavior.

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

Comment thread crates/lingui_macro/src/macro_utils.rs Outdated
Comment thread crates/lingui_macro/src/jsx_visitor.rs
Comment thread crates/lingui_macro/src/jsx_visitor.rs Outdated
@timofei-iatsenko timofei-iatsenko marked this pull request as draft June 29, 2026 08:50
@timofei-iatsenko timofei-iatsenko marked this pull request as ready for review June 29, 2026 14:22
@timofei-iatsenko

Copy link
Copy Markdown
Collaborator Author

@andrii-bodnar this one is ready

@andrii-bodnar andrii-bodnar merged commit bccd4a3 into main Jun 30, 2026
4 checks passed
@andrii-bodnar andrii-bodnar deleted the refactor/labeled-expressions branch June 30, 2026 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants