-
Notifications
You must be signed in to change notification settings - Fork 666
fix: support lowercase member expressions in JSX elements #1474
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
fix: support lowercase member expressions in JSX elements #1474
Conversation
This fixes issue lingodotdev#1165 where JSX elements using member expressions with lowercase variable names (e.g., form.Button) were incorrectly treated as HTML element strings instead of React component identifiers. The compiler was only checking if element names started with an uppercase letter, which broke common library patterns like Tanstack Forms that use lowercase variables with member expressions. Changes: - Updated jsx-scope-inject.ts to check for member expressions (containing dots) before checking case sensitivity - Now both 'form.Button' and 'Form.Button' are correctly treated as component identifiers - Added test component demonstrating the fix works with both cases This allows developers to use standard library conventions without being forced to use uppercase variable names as a workaround. Fixes lingodotdev#1165
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR attempts to fix an issue where JSX elements using member expressions with lowercase variable names (e.g., form.Button) were incorrectly treated as HTML element strings instead of React component identifiers. The fix adds a check for member expressions (containing dots) before the uppercase check in the compiler.
Key changes:
- Updated
jsx-scope-inject.tsto detect member expressions using.includes(".") - Added a test component demonstrating both lowercase and uppercase member expression patterns
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| packages/compiler/src/jsx-scope-inject.ts | Added member expression detection logic to determine when JSX elements should be treated as component references |
| demo/vite-project/src/components/tanstack-form-test.tsx | Added demo component showcasing the fix for Tanstack Forms pattern with both lowercase and uppercase variable names |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const as = isMemberExpression || isComponent | ||
| ? t.identifier(originalJsxElementName) | ||
| : originalJsxElementName; |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using t.identifier() with a dotted string like "form.Button" creates an invalid AST node because JavaScript identifiers cannot contain dots. For member expressions, you need to build a proper member expression AST structure.
Consider creating a helper function that parses the dotted string and builds the correct AST:
function createMemberExpressionFromString(str: string): t.Expression {
const parts = str.split('.');
if (parts.length === 1) {
return t.identifier(parts[0]);
}
let expr: t.Expression = t.identifier(parts[0]);
for (let i = 1; i < parts.length; i++) {
expr = t.memberExpression(expr, t.identifier(parts[i]));
}
return expr;
}Then use it like:
const as = isMemberExpression || isComponent
? createMemberExpressionFromString(originalJsxElementName)
: originalJsxElementName;This will correctly generate form.Button as a member expression AST node instead of an invalid identifier.
| <h2>Tanstack Forms + Lingo.dev Compiler Issue #1165</h2> | ||
|
|
||
| <div style={{ marginBottom: '40px' }}> | ||
| <h3>Broken: Lowercase variable name (form)</h3> |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The heading says "Broken" but this test file is included in the PR that fixes the issue. After the fix, this case should work correctly. Consider updating the heading to something like "Previously broken: Lowercase variable name (form) - now fixed" to accurately reflect the current state.
| <h3>Broken: Lowercase variable name (form)</h3> | |
| <h3>Previously broken: Lowercase variable name (form) - now fixed</h3> |
|
|
||
| // Add $as prop | ||
| const as = /^[A-Z]/.test(originalJsxElementName) | ||
| // Check if it's a member expression (contains dot) or starts with uppercase |
Copilot
AI
Nov 12, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] The comment could be more specific about the rationale. Consider expanding it to explain why member expressions need special handling:
// Check if it's a member expression (contains dot) or starts with uppercase
// Member expressions (e.g., form.Button) and uppercase names (e.g., Button)
// should be treated as component references, not HTML element stringsThis makes it clearer for future maintainers why both conditions are checked.
| // Check if it's a member expression (contains dot) or starts with uppercase | |
| // Check if it's a member expression (contains dot) or starts with uppercase. | |
| // Member expressions (e.g., form.Button) and uppercase names (e.g., Button) | |
| // should be treated as component references, not HTML element strings. |
- Add createMemberExpressionFromString() helper to build correct AST nodes - Fix bug where t.identifier() was incorrectly used with dotted strings like 'form.Button' - Improve code comments to explain member expression handling rationale - Update demo heading to reflect that the issue is now fixed This addresses all review comments from PR lingodotdev#1474
|
Addressed the comments @maxprilutskiy |
Users were forced to use uppercase variable names as a workaround:
The Solution
Updated
jsx-scope-inject.ts(line 58-63) to check for member expressions (containing dots) before checking case sensitivity:Changes
packages/compiler/src/jsx-scope-inject.tsto recognize member expressionsform.ButtonandForm.Buttonare correctly treated as component identifiersTesting
Tested with the vite-project demo showing both lowercase and uppercase member expressions render and function correctly with full styling and interactivity preserved.
Impact
This allows developers to use standard library conventions without being forced to use uppercase variable names as a workaround. Fixes compatibility with:
form.Field,form.Input, etc.)dialog.Panel,menu.Item, etc.)Fixes #1165