When applying the add-conversions plugin on TypeScript code involving ternary expressions that return function expressions in one branch and property accesses in the other, the output code is malformed. Specifically, the transformation incorrectly duplicates part of the code and introduces syntax errors.
Input Code
export function Complaints({ currentUserCanEdit, updateComplaint }) {
const complaint = {};
return currentUserCanEdit
? () => {
updateComplaint(complaint.id);
}
: complaint.type;
}
Expected Output
export function Complaints({ currentUserCanEdit, updateComplaint }) {
const complaint = {};
return currentUserCanEdit
? () => {
updateComplaint((complaint as any).id);
}
: (complaint as any).type;
}
Actual Output
export function Complaints({ currentUserCanEdit, updateComplaint }) {
const complaint = {};
return currentUserCanEdit
? () => {
updateComplaint(complaint.id);
}
: (complaint as any).type;
updateComplaint((complaint as any).id);
}
: complaint.type;
}
Steps to Reproduce
- Create a TypeScript file with the provided input code snippet.
- Run the add-conversions plugin from the ts-migrate tool on this file.
- Observe the malformed output as described above.
Additional Information
- The problem seems to arise from the transformation logic not correctly handling the scoping or branching of ternary expressions, especially when mixed with function expressions, which is a simplified version of a problem I ran into when converting a react component that contained a component within a ternary operation.
{currentUserCanEdit ? (
<Input
widthOptions="s"
onChange={(e: any) => {
updateComplaint(e.currentTarget.value, 'caseNumber', complaint.id, index)
}}
value={complaint.caseNumber}
/>
) : (
complaint.caseNumber
)}
Request for Guidance
I've attempted to address this issue by adding a new failing test case to highlight the problem, but I'm unsure where within the add-conversions plugin's transformation logic this case should be specifically handled. Any insights or suggestions on how to properly transform these expressions without introducing syntax errors would be greatly appreciated.
New Failing Test
it("handles ternary expressions containing a function call", async () => {
const text = `export function Complaints({ currentUserCanEdit, updateComplaint }) {
const complaint = {};
return currentUserCanEdit
? () => {
updateComplaint(complaint.id);
}
: complaint.type;
}
`;
const result = addConversionsPlugin.run(await realPluginParams({ text }));
expect(result)
.toBe(`export function Complaints({ currentUserCanEdit, updateComplaint }) {
const complaint = {};
return currentUserCanEdit
? () => {
updateComplaint((complaint as any).id);
}
: (complaint as any).type;
}
`);
});
Possible Solution
It does seem like this will solve it
const ancestorChecks = [
ts.SyntaxKind.ExpressionStatement,
ts.SyntaxKind.ConditionalExpression,
];
ancestorReplaceMap.set(
origNode,
ancestorShouldBeReplaced === undefined
? ancestorChecks.includes(origNode.kind)
: ancestorChecks.includes(origNode.kind) || ancestorShouldBeReplaced
);
But I'm not comfortable enough with the package to know if this could have any negative consequences.
When applying the add-conversions plugin on TypeScript code involving ternary expressions that return function expressions in one branch and property accesses in the other, the output code is malformed. Specifically, the transformation incorrectly duplicates part of the code and introduces syntax errors.
Input Code
Expected Output
Actual Output
Steps to Reproduce
Additional Information
Request for Guidance
I've attempted to address this issue by adding a new failing test case to highlight the problem, but I'm unsure where within the add-conversions plugin's transformation logic this case should be specifically handled. Any insights or suggestions on how to properly transform these expressions without introducing syntax errors would be greatly appreciated.
New Failing Test
Possible Solution
It does seem like this will solve it
But I'm not comfortable enough with the package to know if this could have any negative consequences.