Skip to content

Commit d0479ad

Browse files
pkasardaclaude
andauthored
fix(babel-plugin-lingui-macro): unwrap non-null assertion (x!) and satisfies in placeholders (#2622)
`tokenizeExpression` only unwrapped `TSAsExpression`, so a placeholder like `t`${x!}`` was treated as a complex expression and assigned an indexed placeholder (`{0}`), whereas `@lingui/swc-plugin` unwraps it to a named placeholder (`{x}`). This produced different message IDs for identical source, breaking catalog lookups in projects that extract with the JS macro but run with the SWC plugin. Unwrap `TSNonNullExpression` and `TSSatisfiesExpression` alongside `TSAsExpression` so all TS-only wrappers name the inner expression, matching the SWC plugin and the existing `as` behavior. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent b4be90d commit d0479ad

3 files changed

Lines changed: 37 additions & 2 deletions

File tree

packages/babel-plugin-lingui-macro/src/macroJsAst.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,13 @@ export function tokenizeExpression(
262262
node: Node | Expression,
263263
ctx: MacroJsContext,
264264
): ArgToken {
265-
if (t.isTSAsExpression(node)) {
265+
if (
266+
t.isTSAsExpression(node) ||
267+
t.isTSNonNullExpression(node) ||
268+
t.isTSSatisfiesExpression(node)
269+
) {
270+
// Unwrap TS-only expression wrappers (`x as T`, `x!`, `x satisfies T`) so the
271+
// inner expression drives placeholder naming (e.g. `${x!}` → `{x}`, not `{0}`).
266272
return tokenizeExpression(node.expression, ctx)
267273
}
268274
if (t.isObjectExpression(node)) {

packages/babel-plugin-lingui-macro/test/__snapshots__/js-t.test.ts.snap

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -511,6 +511,26 @@ _i18n._(
511511
512512
`;
513513
514+
exports[`Variables with non-null assertion get a named placeholder (parity with \`as\`) 1`] = `
515+
import { t } from "@lingui/core/macro";
516+
t\`Variable \${name!}\`;
517+
518+
↓ ↓ ↓ ↓ ↓ ↓
519+
520+
import { i18n as _i18n } from "@lingui/core";
521+
_i18n._(
522+
/** i18n */
523+
{
524+
id: "xRRkAE",
525+
message: "Variable {name}",
526+
values: {
527+
name: name,
528+
},
529+
},
530+
);
531+
532+
`;
533+
514534
exports[`Variables with escaped double quotes are correctly formatted 1`] = `
515535
import { t } from "@lingui/core/macro";
516536
t\`Variable "name"\`;

packages/babel-plugin-lingui-macro/test/js-t.test.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,10 +105,19 @@ macroTester({
105105
name: "Variables with `as` type casting",
106106
code: `
107107
import { t } from '@lingui/core/macro';
108-
108+
109109
t\`Variable \${{name} as any}\`;
110110
`,
111111
},
112+
{
113+
useTypescriptPreset: true,
114+
name: "Variables with non-null assertion get a named placeholder (parity with `as`)",
115+
code: `
116+
import { t } from '@lingui/core/macro';
117+
118+
t\`Variable \${name!}\`;
119+
`,
120+
},
112121
{
113122
name: "Newlines are preserved",
114123
code: `

0 commit comments

Comments
 (0)