[localize-tools] Fix generic call expressions inside msg() substitutions#5334
Merged
jimsimon merged 2 commits intoMay 13, 2026
Merged
Conversation
🦋 Changeset detectedLatest commit: 7989f99 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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 |
|
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. |
dbd2914 to
ac7d81d
Compare
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.
2b8d76b to
9ef487a
Compare
Bring the existing changeset in line with the repo's prettier config (single quotes) so `npm run format:check` passes in CI.
9ef487a to
7989f99
Compare
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
parseStringAsTemplateLiteralin@lit/localize-toolsparsed template literal bodies withts.ScriptKind.JS. JavaScript has no generic-call syntax, so an expression like${foo<T>(arg)}inside amsg()template substitution was parsed as(foo < T) > (arg)(aBinaryExpressionchain) instead of aCallExpressionwith a type argument list.In contexts that re-emit the parsed AST, this prints as
foo < T > (arg), which evaluates tofalseat 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 throughparseStringAsTemplateLiteralare vulnerable.The fix is a one-line, surgical change: parse with
ts.ScriptKind.TSso 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: switchparseStringAsTemplateLiteraltots.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 aCallExpression(not aBinaryExpression)..changeset/: patch changeset for@lit/localize-tools.Test plan
npm testinpackages/localize-toolspasses (test:unit80/80,test:unit:ssr4/4,test:check-tscclean).main(withScriptKind.JS) and passes with the fix.npm run formatand ESLint clean on changed files.Made with Cursor