Skip to content

[localize-tools] Fix generic call expressions inside msg() substitutions#5334

Merged
jimsimon merged 2 commits into
lit:mainfrom
jimsimon:fix/localize-tools-generic-call-substitution
May 13, 2026
Merged

[localize-tools] Fix generic call expressions inside msg() substitutions#5334
jimsimon merged 2 commits into
lit:mainfrom
jimsimon:fix/localize-tools-generic-call-substitution

Conversation

@jimsimon

Copy link
Copy Markdown
Collaborator

Summary

parseStringAsTemplateLiteral in @lit/localize-tools parsed template literal bodies with ts.ScriptKind.JS. JavaScript has no generic-call syntax, so an expression like ${foo<T>(arg)} inside a msg() template substitution was parsed as (foo < T) > (arg) (a BinaryExpression chain) instead of a CallExpression with a type argument list.

In contexts that re-emit the parsed AST, this prints as foo < T > (arg), which evaluates to false at runtime and silently drops any side effects of the call. Source/English branches are unaffected because they reuse the original TypeScript-parsed source AST; translated branches that flow back through parseStringAsTemplateLiteral are vulnerable.

The fix is a one-line, surgical change: parse with ts.ScriptKind.TS so the TypeScript parser correctly disambiguates <T> as a type argument list. There is no behavior change for non-generic substitutions; TypeScript's parser is a strict superset of JavaScript's for this input.

Changes

  • packages/localize-tools/src/typescript.ts: switch parseStringAsTemplateLiteral to ts.ScriptKind.TS (with a comment explaining why).
  • packages/localize-tools/src/tests/typescript.unit.test.ts: new unit test file with 4 tests, including a regression test that asserts a generic call substitution parses as a CallExpression (not a BinaryExpression).
  • .changeset/: patch changeset for @lit/localize-tools.

Test plan

  • npm test in packages/localize-tools passes (test:unit 80/80, test:unit:ssr 4/4, test:check-tsc clean).
  • New regression test fails on main (with ScriptKind.JS) and passes with the fix.
  • npm run format and ESLint clean on changed files.

Made with Cursor

@jimsimon jimsimon requested a review from kevinpschaaf as a code owner May 13, 2026 20:59
@changeset-bot

changeset-bot Bot commented May 13, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7989f99

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@lit/localize-tools Patch
@lit-labs/ssr-dom-shim Patch

Not sure what this means? Click here to learn what changesets are.

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

@google-cla

google-cla Bot commented May 13, 2026

Copy link
Copy Markdown

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@jimsimon jimsimon force-pushed the fix/localize-tools-generic-call-substitution branch from dbd2914 to ac7d81d Compare May 13, 2026 21:02
Parse template literal bodies as TypeScript instead of JavaScript so that
generic call expressions like `${foo<T>(arg)}` inside a msg()
substitution are recognized as type-argument calls instead of being
misparsed as a chain of comparison operators (`(foo < T) > (arg)`),
which would silently emit `false` and drop the call's side effects in
any consumer that re-emits the parsed AST.

Adds a focused unit test for parseStringAsTemplateLiteral that asserts
generic call substitutions parse as a CallExpression.
@jimsimon jimsimon force-pushed the fix/localize-tools-generic-call-substitution branch 2 times, most recently from 2b8d76b to 9ef487a Compare May 13, 2026 21:32
Bring the existing changeset in line with the repo's prettier config
(single quotes) so `npm run format:check` passes in CI.
@jimsimon jimsimon force-pushed the fix/localize-tools-generic-call-substitution branch from 9ef487a to 7989f99 Compare May 13, 2026 21:33

@justinfagnani justinfagnani left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

thanks!

@jimsimon jimsimon merged commit a691944 into lit:main May 13, 2026
8 checks passed
@lit-robot lit-robot mentioned this pull request May 14, 2026
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