Skip to content

Rust extractor + faster native transform#236

Draft
timofei-iatsenko wants to merge 57 commits into
lingui:mainfrom
timofei-iatsenko:main
Draft

Rust extractor + faster native transform#236
timofei-iatsenko wants to merge 57 commits into
lingui:mainfrom
timofei-iatsenko:main

Conversation

@timofei-iatsenko

Copy link
Copy Markdown
Collaborator

No description provided.

timofei-iatsenko and others added 30 commits March 4, 2026 15:39
* extractor initial

* add snapshot testing

* improve extractor

* sourcemaps support

* reorganize repo

* use object for Origin and add napi attribute

* add napi-rs bindings

* more extractor methods, extract from files with parallelism

* clean up

* support comment and context extraction

* fixup tests

* format

* remove js extractor

* setup pipelines

* wf

* wf2

* wf3

* wf4

* wf5

* wf6

* fix tests

* debug test

* debug test

* debug test

* debug test

* debug test

* fix wf

* fix wf

* fix wf

* fix wf

* clean up

* add a target

* test publish

* fix clippy warnings, fix publish

* add target for e2e test

* add node types

* fixes

* fixes

* fixes

* fixes

* fixes

* reorganize repo

* fix e2e test for macro

* cleanup
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/lingui_macro/src/lib.rs
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/js_should_process_only_elements_imported_from_macro.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/js_should_process_only_elements_imported_from_macro2.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/js_should_support_renamed_imports.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/jsx_should_process_only_elements_imported_from_macro.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/jsx_should_process_only_elements_imported_from_macro2.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/jsx_should_support_renamed_imports.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/should_add_imports_after_directive_prologues.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/imports.rs/should_add_not_clashing_imports.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_define_message.rs/define_message_should_support_template_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_define_message.rs/should_expand_macros.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_define_message.rs/should_expand_values.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_define_message.rs/should_kept_only_essential_props.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_define_message.rs/should_preserve_custom_id.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_define_message.rs/should_transform_define_message.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_choices_may_contain_expressions.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_dedup_values_in_icu.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_icu_diffrent_object_literal_syntax.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_icu_macro.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_icu_nested_in_choices.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_icu_nested_in_t.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_plural_with_offset_and_exact_matches.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_plural_with_placeholders.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_should_not_touch_non_lungui_fns.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_icu.rs/js_should_not_treat_offset_in_select.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_choice_labels_in_tpl_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_continuation_character.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_custom_i18n_passed.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_dedup_values_in_tpl_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_explicit_labels_in_tpl_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_newlines_are_preserved.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_ph_labels_in_tpl_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_should_kept_only_essential_props.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_should_not_touch_code_if_no_macro_import.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_should_not_touch_not_related_tagget_tpls.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_should_produce_all_fields_when_no_message_set.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_should_produce_all_fields_without_strip_flag.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_should_work_with_legacy_import.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_substitution_in_tpl_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_support_message_descriptor_in_t_fn.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_support_template_strings_in_t_macro_message_with_custom_i18n_instance.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/js_t_fn_wrapped_in_call_expr.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/should_generate_diffrent_id_when_context_provided.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/support_id_and_comment_in_t_macro_as_call_expression.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/support_id_in_template_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/js_t.rs/unicode_characters_interpreted.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/elements_inside_expression_container.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/elements_without_children.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/html_attributes_are_handled.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/ignore_jsx_empty_expression.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_comments_should_not_affect_expression_index.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_components_interpolation.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_explicit_labels.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_explicit_labels_with_as_statement.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_expressions_are_converted_to_positional_arguments.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_nested_labels.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_ph_labels.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_should_suppor_legacy_import.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_simple_jsx.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_template_literal_in_children.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_values_dedup.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_with_context.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/jsx_with_custom_id.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/keep_multiple_forced_newlines.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/non_breaking_whitespace_handling_2226.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/normalize_crlf_lf_cr.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/production_only_essential_props_are_kept.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/quoted_jsx_attributes_are_handled.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/strip_whitespace_around_arguments.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/strip_whitespace_around_tags_but_keep_forced_spaces.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/strip_whitespaces_in_jsxtext_but_keep_in_jsx_expression_containers.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/use_decoded_html_entities.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/use_js_macro_in_jsx_attrs.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx.rs/use_js_plural_in_jsx_attrs.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu_explicit_id.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu_nested.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu_with_template_literal.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_multivelel_nesting.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_with_offset_and_exact_matches.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_ordinal_with_offset_and_exact_matches.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_simple.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_expressions_in_cases.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_trans_inside_plural.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/multiple_new_lines_with_nbsp_endind.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/jsx_icu.rs/production_only_essential_props_are_kept.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/runtime_config.rs/should_use_provided_runtime_modules.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/js_use_lingui_hook.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/should_process_macro_with_matching_name_in_correct_scopes.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/support_nested_macro.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/support_nested_macro_when_in_arrow_function_issue_2095.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/support_passing_t_variable_as_dependency.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/support_renamed_destructuring.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/work_when_t_is_not_used.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/work_with_components_defined_as_arrow_function.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/work_with_existing_use_lingui_statement.js
#	crates/lingui_macro/tests/__swc_snapshots__/tests/use_lingui.rs/work_with_multiple_react_components.js
#	crates/lingui_macro/tests/common/mod.rs
#	crates/lingui_macro/tests/js_define_message.rs
#	crates/lingui_macro/tests/js_t.rs
#	crates/lingui_macro/tests/jsx.rs
#	crates/lingui_macro/tests/jsx_icu.rs
#	crates/lingui_macro/tests/jsx_named_placeholders.rs
#	crates/lingui_macro/tests/snapshots/imports__js_should_process_only_elements_imported_from_macro.snap
#	crates/lingui_macro/tests/snapshots/imports__js_should_process_only_elements_imported_from_macro2.snap
#	crates/lingui_macro/tests/snapshots/imports__js_should_support_renamed_imports.snap
#	crates/lingui_macro/tests/snapshots/imports__jsx_should_process_only_elements_imported_from_macro.snap
#	crates/lingui_macro/tests/snapshots/imports__jsx_should_process_only_elements_imported_from_macro2.snap
#	crates/lingui_macro/tests/snapshots/imports__jsx_should_support_renamed_imports.snap
#	crates/lingui_macro/tests/snapshots/imports__should_add_imports_after_directive_prologues.snap
#	crates/lingui_macro/tests/snapshots/imports__should_add_not_clashing_imports.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__define_message_should_support_template_literal.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__id_only_should_keep_only_id.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__message_should_keep_message_and_context.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__should_expand_macros.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__should_expand_values.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__should_preserve_custom_id.snap
#	crates/lingui_macro/tests/snapshots/js_define_message__should_transform_define_message.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_choices_may_contain_expressions.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_dedup_values_in_icu.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_icu_diffrent_object_literal_syntax.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_icu_macro.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_icu_nested_in_choices.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_icu_nested_in_t.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_plural_with_offset_and_exact_matches.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_plural_with_placeholders.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_should_not_touch_non_lungui_fns.snap
#	crates/lingui_macro/tests/snapshots/js_icu__js_should_not_treat_offset_in_select.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_choice_labels_in_tpl_literal.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_continuation_character.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_custom_i18n_passed.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_dedup_values_in_tpl_literal.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_explicit_labels_in_tpl_literal.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_id_only_should_keep_only_id.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_message_should_keep_message_and_context.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_newlines_are_preserved.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_ph_labels_in_tpl_literal.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_should_not_touch_code_if_no_macro_import.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_should_not_touch_not_related_tagget_tpls.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_should_produce_all_fields_when_no_message_set.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_should_produce_all_fields_without_strip_flag.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_should_use_v5_generate_id_with_parameter.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_should_work_with_legacy_import.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_substitution_in_tpl_literal.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_support_message_descriptor_in_t_fn.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_support_template_strings_in_t_macro_message_with_custom_i18n_instance.snap
#	crates/lingui_macro/tests/snapshots/js_t__js_t_fn_wrapped_in_call_expr.snap
#	crates/lingui_macro/tests/snapshots/js_t__should_generate_diffrent_id_when_context_provided.snap
#	crates/lingui_macro/tests/snapshots/js_t__support_id_and_comment_in_t_macro_as_call_expression.snap
#	crates/lingui_macro/tests/snapshots/js_t__support_id_in_template_literal.snap
#	crates/lingui_macro/tests/snapshots/js_t__unicode_characters_interpreted.snap
#	crates/lingui_macro/tests/snapshots/jsx__elements_inside_expression_container.snap
#	crates/lingui_macro/tests/snapshots/jsx__elements_without_children.snap
#	crates/lingui_macro/tests/snapshots/jsx__html_attributes_are_handled.snap
#	crates/lingui_macro/tests/snapshots/jsx__id_only_essential_props_are_kept.snap
#	crates/lingui_macro/tests/snapshots/jsx__ignore_jsx_empty_expression.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_comments_should_not_affect_expression_index.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_components_interpolation.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_explicit_labels.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_explicit_labels_with_as_statement.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_expressions_are_converted_to_positional_arguments.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_nested_labels.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_ph_labels.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_preserve_reserved_attrs.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_should_suppor_legacy_import.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_simple_jsx.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_template_literal_in_children.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_values_dedup.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_with_context.snap
#	crates/lingui_macro/tests/snapshots/jsx__jsx_with_custom_id.snap
#	crates/lingui_macro/tests/snapshots/jsx__keep_multiple_forced_newlines.snap
#	crates/lingui_macro/tests/snapshots/jsx__message_keeps_message_and_context.snap
#	crates/lingui_macro/tests/snapshots/jsx__non_breaking_whitespace_handling_2226.snap
#	crates/lingui_macro/tests/snapshots/jsx__normalize_crlf_lf_cr.snap
#	crates/lingui_macro/tests/snapshots/jsx__quoted_jsx_attributes_are_handled.snap
#	crates/lingui_macro/tests/snapshots/jsx__strip_whitespace_around_arguments.snap
#	crates/lingui_macro/tests/snapshots/jsx__strip_whitespace_around_tags_but_keep_forced_spaces.snap
#	crates/lingui_macro/tests/snapshots/jsx__strip_whitespaces_in_jsxtext_but_keep_in_jsx_expression_containers.snap
#	crates/lingui_macro/tests/snapshots/jsx__use_decoded_html_entities.snap
#	crates/lingui_macro/tests/snapshots/jsx__use_js_macro_in_jsx_attrs.snap
#	crates/lingui_macro/tests/snapshots/jsx__use_js_plural_in_jsx_attrs.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__id_only_essential_props_are_kept.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_icu.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_icu_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_icu_nested.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_icu_with_template_literal.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_multivelel_nesting.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_plural_preserve_reserved_attrs.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_plural_with_offset_and_exact_matches.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_select_ordinal_with_offset_and_exact_matches.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_select_simple.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_select_with_expressions_in_cases.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_select_with_reserved_attrs.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__jsx_trans_inside_plural.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__message_keeps_message_and_context.snap
#	crates/lingui_macro/tests/snapshots/jsx_icu__multiple_new_lines_with_nbsp_endind.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__allows_dotted.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__allows_hyphenated.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__attribute_ignored_when_not_configured.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__basic.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__deduplication_different_props.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__deduplication_identical.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__deduplication_with_stripped_props.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__defaults.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__different_spreads_throw.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__identical_spreads_reused.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__mixed_explicit_and_defaults.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__prop_order.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__prop_order2.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__same_element_different_attributes_count_throws.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__same_name_different_element_throws.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__same_spread_different_order_throws.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__stripped_ast.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__supports_string_in_jsx_expression.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__throws_ending_with_dot.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__throws_on_boolean_expr.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__throws_on_empty_attribute_value.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__throws_on_non_string_attribute_value.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__throws_on_numeric_name.snap
#	crates/lingui_macro/tests/snapshots/jsx_named_placeholders__throws_starting_with_hyphen.snap
#	crates/lingui_macro/tests/snapshots/runtime_config__should_use_provided_runtime_modules.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__js_use_lingui_hook.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__should_process_macro_with_matching_name_in_correct_scopes.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__support_nested_macro.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__support_nested_macro_when_in_arrow_function_issue_2095.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__support_passing_t_variable_as_dependency.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__support_renamed_destructuring.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__work_when_t_is_not_used.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__work_with_components_defined_as_arrow_function.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__work_with_existing_use_lingui_statement.snap
#	crates/lingui_macro/tests/snapshots/use_lingui__work_with_multiple_react_components.snap
#	package.json
#	tests/__swc_snapshots__/tests/imports.rs/js_should_process_only_elements_imported_from_macro.js
#	tests/__swc_snapshots__/tests/imports.rs/js_should_process_only_elements_imported_from_macro2.js
#	tests/__swc_snapshots__/tests/imports.rs/js_should_support_renamed_imports.js
#	tests/__swc_snapshots__/tests/imports.rs/jsx_should_process_only_elements_imported_from_macro.js
#	tests/__swc_snapshots__/tests/imports.rs/jsx_should_process_only_elements_imported_from_macro2.js
#	tests/__swc_snapshots__/tests/imports.rs/jsx_should_support_renamed_imports.js
#	tests/__swc_snapshots__/tests/imports.rs/should_add_imports_after_directive_prologues.js
#	tests/__swc_snapshots__/tests/imports.rs/should_add_not_clashing_imports.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_choices_may_contain_expressions.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_dedup_values_in_icu.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_icu_diffrent_object_literal_syntax.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_icu_macro.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_icu_nested_in_choices.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_icu_nested_in_t.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_plural_with_offset_and_exact_matches.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_plural_with_placeholders.js
#	tests/__swc_snapshots__/tests/js_icu.rs/js_should_not_treat_offset_in_select.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_choice_labels_in_tpl_literal.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_custom_i18n_passed.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_dedup_values_in_tpl_literal.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_explicit_labels_in_tpl_literal.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_ph_labels_in_tpl_literal.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_should_produce_all_fields_without_strip_flag.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_should_work_with_legacy_import.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_substitution_in_tpl_literal.js
#	tests/__swc_snapshots__/tests/js_t.rs/js_support_message_descriptor_in_t_fn.js
#	tests/__swc_snapshots__/tests/js_t.rs/should_generate_diffrent_id_when_context_provided.js
#	tests/__swc_snapshots__/tests/js_t.rs/support_id_and_comment_in_t_macro_as_call_expression.js
#	tests/__swc_snapshots__/tests/js_t.rs/unicode_characters_interpreted.js
#	tests/__swc_snapshots__/tests/jsx.rs/elements_inside_expression_container.js
#	tests/__swc_snapshots__/tests/jsx.rs/elements_without_children.js
#	tests/__swc_snapshots__/tests/jsx.rs/html_attributes_are_handled.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_comments_should_not_affect_expression_index.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_components_interpolation.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_explicit_labels.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_explicit_labels_with_as_statement.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_expressions_are_converted_to_positional_arguments.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_nested_labels.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_ph_labels.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_preserve_reserved_attrs.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_should_suppor_legacy_import.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_simple_jsx.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_template_literal_in_children.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_values_dedup.js
#	tests/__swc_snapshots__/tests/jsx.rs/jsx_with_context.js
#	tests/__swc_snapshots__/tests/jsx.rs/non_breaking_whitespace_handling_2226.js
#	tests/__swc_snapshots__/tests/jsx.rs/normalize_crlf_lf_cr.js
#	tests/__swc_snapshots__/tests/jsx.rs/quoted_jsx_attributes_are_handled.js
#	tests/__swc_snapshots__/tests/jsx.rs/strip_whitespace_around_arguments.js
#	tests/__swc_snapshots__/tests/jsx.rs/strip_whitespace_around_tags_but_keep_forced_spaces.js
#	tests/__swc_snapshots__/tests/jsx.rs/strip_whitespaces_in_jsxtext_but_keep_in_jsx_expression_containers.js
#	tests/__swc_snapshots__/tests/jsx.rs/use_js_macro_in_jsx_attrs.js
#	tests/__swc_snapshots__/tests/jsx.rs/use_js_plural_in_jsx_attrs.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu_explicit_id.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_icu_with_template_literal.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_preserve_reserved_attrs.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_plural_with_offset_and_exact_matches.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_ordinal_with_offset_and_exact_matches.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_simple.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_expressions_in_cases.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/jsx_select_with_reserved_attrs.js
#	tests/__swc_snapshots__/tests/jsx_icu.rs/multiple_new_lines_with_nbsp_endind.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/js_use_lingui_hook.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/should_process_macro_with_matching_name_in_correct_scopes.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/support_passing_t_variable_as_dependency.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/support_renamed_destructuring.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/work_with_components_defined_as_arrow_function.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/work_with_existing_use_lingui_statement.js
#	tests/__swc_snapshots__/tests/use_lingui.rs/work_with_multiple_react_components.js
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	crates/lingui_macro/src/comment_directive.rs
#	crates/lingui_macro/src/options.rs
#	crates/lingui_macro/tests/lingui_directive.rs
#	crates/lingui_macro/tests/snapshots/lingui_directive__define_message_explicit_context_overrides_directive.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__define_message_id_prefix_leader_with_matching_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__define_message_id_prefix_leader_with_non_matching_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__define_message_id_prefix_with_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__define_message_tagged_template_with_directive.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__define_message_with_directive_context.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_plural_with_directive_context.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_select_with_directive_context.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_closest_directive_takes_precedence.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_directive_applies_to_multiple_subsequent_macros.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_directives_merge_with_preceding_ones.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_empty_param_value_clears_single_param.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_explicit_comment_overrides_directive.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_id_only_with_directive_context_uses_context_for_hash.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_id_prefix_leader_with_dynamic_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_id_prefix_with_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_reset_clears_all_inherited_values.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_reset_combined_with_new_values.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_with_directive_comment_line_comment.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_with_directive_context_and_comment.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_with_directive_context_block_comment.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_with_id_prefix_leader.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_multiple_directives_switching_context_mid_file.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_plural_with_directive_context.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_select_with_directive_context.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_directive_comment.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_directive_context.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_directive_id_prefix_and_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_directive_id_prefix_without_explicit_id.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_dynamic_id_and_id_prefix.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_dynamic_id_and_no_id_prefix.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_explicit_context_overrides_directive.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_id_prefix_leader.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_matching_id_prefix_leader.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__jsx_trans_with_non_matching_id_prefix_leader.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__use_lingui_t_with_directive_applied_per_reference.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__use_lingui_t_with_directive_context.snap
#	package.json
#	packages/lingui-macro/e2e/fixtures/lingui-options/custom.config.js
#	packages/lingui-macro/e2e/fixtures/lingui-options/lingui.config.js
#	packages/lingui-macro/e2e/options.test.ts
#	yarn.lock
Remove standalone yarn.lock and .yarnrc.yml from packages/lingui-swc,
add workspaces field to root package.json, and update CI workflow to
install dependencies from the workspace root.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
# Conflicts:
#	.github/workflows/release.yml
#	Cargo.lock
#	Cargo.toml
#	crates/lingui_macro/src/lib.rs
#	crates/lingui_macro/src/options.rs
#	crates/lingui_macro/tests/snapshots/imports__should_transform_custom_core_macro_package.snap
#	crates/lingui_macro/tests/snapshots/imports__should_transform_custom_jsx_macro_package.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_with_directive_before_removed_macro_import_after_regular_import.snap
#	crates/lingui_macro/tests/snapshots/lingui_directive__js_t_with_top_of_file_directive_before_macro_import.snap
#	package.json
# Conflicts:
#	crates/lingui_macro/src/lib.rs
#	crates/lingui_macro/tests/snapshots/imports__should_transform_messages_after_ts_module_declarations.snap
# Conflicts:
#	.github/workflows/ci-macro.yml
#	CLAUDE.md
#	CONTRIBUTING.md
#	Cargo.lock
#	Cargo.toml
#	crates/lingui_macro/Cargo.toml
#	crates/lingui_macro/src/options.rs
#	crates/lingui_macro/tests/common/mod.rs
#	packages/lingui-macro/package.json
#	yarn.lock
@codecov

codecov Bot commented Jun 12, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 95.04%. Comparing base (27e38f2) to head (1636627).
⚠️ Report is 5 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #236      +/-   ##
==========================================
+ Coverage   94.96%   95.04%   +0.07%     
==========================================
  Files          10       10              
  Lines        2603     2542      -61     
==========================================
- Hits         2472     2416      -56     
+ Misses        131      126       -5     
Flag Coverage Δ
unittests 95.04% <ø> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.
see 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment on lines +6 to +9
"repository": {
"url": "https://github.com/timofei-iatsenko/lingui-rust-tools.git",
"directory": "packages/lingui-swc"
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please update the repository url

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Let's agree on the package/repostiry name first, then i will make this PR ready to be merged.

]
},
"engines": {
"node": ">= 12.22.0 < 13 || >= 14.17.0 < 15 || >= 15.12.0 < 16 || >= 16.0.0"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do we need all of these versions here?

Comment on lines +65 to +67
# - host: windows-latest
# build: yarn build --target i686-pc-windows-msvc
# target: i686-pc-windows-msvc#

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

There is a lot of commented code in this workflow. Is there anything we can do to eliminate it?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Some planning artifact

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It's not planning artifact. It's an ADR, (architecture decision record), which is answering on a question why we decided to do this or not that, etc

It's not for AI, it's for further contributors

@andrii-bodnar

Copy link
Copy Markdown
Contributor

Can we split the transformer out of this PR? The extractor and transform() are independent surfaces - extraction depends on lingui_extractor + lingui_macro, while transform() only needs lingui_macro plus the shared detect_parser_config. Nothing in the extraction path touches transform.rs.

Landing them separately would shrink this draft a lot, de-risk the first native publish, and let the transform's design settle on its own (the warnings-as-fatal handling, sourcemap dedup, etc.).

One architectural note: the extractor logic lives in a pure crates/lingui_extractor, but the transform logic sits inside the napi binding crate (packages/lingui-swc/src/transform.rs). I'd rather see it as a crates/lingui_transform too, so packages/lingui-swc (or rust-tools if we agree on this name) stays thin FFI glue and the split is uniform - crates = logic, package = bindings. That also makes the transform testable without napi.

So my suggestion: extractor in this PR, transformer as a follow-up. Keeps each PR focused and the boundaries clean.

@timofei-iatsenko

Copy link
Copy Markdown
Collaborator Author

I’d like to clarify my perspective on this PR to make sure we're on the same page.

It might look like I’m the one pushing hard to get this merged, but that’s not really the case. I don’t use this functionality in my current projects or pet projects. I created this contribution simply because I had the capacity and knew it would bring massive value to the project and community. Honestly, I believe the core project benefits from this much more than I do - it’s a solid, high-impact improvement.

Right now, the process feels overly bureaucratic and slows us down from iterating fast and delivering value. Instead of focusing on actual engineering work, I'm spending time on administrative overhead that isn't really necessary. For context, this exact code is already deployed and actively used by part of the community via the lingui-swc package, where it has been thoroughly proven to work.

Splitting this PR into smaller parts and delivering them separately would take a significant amount of extra time. Since both features will end up merged anyway, breaking them apart now means I’d have to waste hours fixing temporary test failures and type mismatches, only to recombine them later.

As a core contributor (though not an official maintainer), my available open-source time is limited, and I’d much rather spend it on meaningful engineering tasks.

If you strictly require this code to be split, refactored, and reformatted according to these administrative guidelines, I’m open to doing that as paid consulting work. Otherwise, I recommend merging this PR as-is so the main project can benefit from these improvements immediately without further delay.

@andrii-bodnar

Copy link
Copy Markdown
Contributor

Thanks for laying out your perspective - let me be equally direct about mine, so we can reset this conversation and move to a productive place.

Asking to split an 8k+ line draft into reviewable pieces isn't administrative overhead - it's standard engineering practice, and it exists precisely because it makes delivery faster. Smaller, focused PRs get reviewed in hours instead of weeks, land independently, and are far easier to debug and revert. What actually slows a project down is a monolithic draft no one can responsibly review in one pass. I'd also note the timeline: my feedback was posted on June 18 and sat unanswered for over a month. The pace of this PR has not been constrained by review requirements.

Framing a routine change request as billable work is not a mode of collaboration that works here. Responding to review feedback is a normal part of contributing to any open-source project - for everyone. I appreciate that your open-source time is limited (so is ours), but review requests can't be met with an invoice.

That said, I understand the practical cost of splitting at this stage. Since both halves will land anyway, I'm fine with keeping the extractor and the transform in this PR.

So let's set the framing debate aside and focus on getting this from draft to merge-ready:

  • Resolve the open design points and comments above.
  • Mark it ready for review once that's done, and I commit to a fast review turnaround.

Going forward, though, let's treat splitting as the norm: work of this scale gets proposed and broken into reviewable PRs from the start. That's not process for its own sake - it's how we keep iteration fast for everyone.

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.

2 participants