Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | 27x 27x 27x 27x 49x 27x 27x 22x 11x 11x 11x 11x 11x 11x 11x 11x | import ts from 'typescript';
/**
* Parse a JS-shaped condition string (e.g. `"size === 'medium'"`, `"disabled"`,
* `"a || b"`) into a TS expression node, prefixing identifier references that
* match `propNames` with `this.`.
*
* The analyzer emits these conditions as plain JS expressions over the
* component's own props, so a small recursive rewrite is enough.
*/
export function conditionToExpression(condition: string, propNames: ReadonlySet<string>): ts.Expression {
const sourceFile = ts.createSourceFile(
'__cond.ts',
`(${condition});`,
ts.ScriptTarget.ESNext,
true,
ts.ScriptKind.TS,
);
const stmt = sourceFile.statements[0] as ts.ExpressionStatement;
const expr = (stmt.expression as ts.ParenthesizedExpression).expression;
return rewrite(expr, propNames);
}
function rewrite(node: ts.Expression, propNames: ReadonlySet<string>): ts.Expression {
if (ts.isIdentifier(node)) {
Eif (propNames.has(node.text)) {
return ts.factory.createPropertyAccessExpression(
ts.factory.createThis(),
ts.factory.createIdentifier(node.text),
);
}
return ts.factory.createIdentifier(node.text);
}
if (ts.isStringLiteral(node)) {
// Clone with fresh position info so the printer emits the text instead
// of trying to look it up in the (different) original source file.
return ts.factory.createStringLiteral(node.text);
}
Iif (ts.isNumericLiteral(node)) {
return ts.factory.createNumericLiteral(node.text);
}
Iif (node.kind === ts.SyntaxKind.TrueKeyword) return ts.factory.createTrue();
Iif (node.kind === ts.SyntaxKind.FalseKeyword) return ts.factory.createFalse();
Iif (node.kind === ts.SyntaxKind.NullKeyword) return ts.factory.createNull();
Iif (ts.isParenthesizedExpression(node)) {
return ts.factory.createParenthesizedExpression(rewrite(node.expression, propNames));
}
Eif (ts.isBinaryExpression(node)) {
return ts.factory.createBinaryExpression(
rewrite(node.left, propNames),
node.operatorToken,
rewrite(node.right, propNames),
);
}
if (ts.isPrefixUnaryExpression(node)) {
return ts.factory.createPrefixUnaryExpression(
node.operator,
rewrite(node.operand, propNames) as ts.UnaryExpression,
);
}
if (ts.isConditionalExpression(node)) {
return ts.factory.createConditionalExpression(
rewrite(node.condition, propNames),
node.questionToken,
rewrite(node.whenTrue, propNames),
node.colonToken,
rewrite(node.whenFalse, propNames),
);
}
if (ts.isPropertyAccessExpression(node)) {
// Only rewrite the receiver side, not the .name (which is an identifier
// inside the property-access slot, not a free reference).
return ts.factory.updatePropertyAccessExpression(node, rewrite(node.expression, propNames), node.name);
}
if (ts.isElementAccessExpression(node)) {
return ts.factory.updateElementAccessExpression(
node,
rewrite(node.expression, propNames),
rewrite(node.argumentExpression, propNames),
);
}
if (ts.isCallExpression(node)) {
return ts.factory.updateCallExpression(
node,
rewrite(node.expression, propNames),
node.typeArguments,
node.arguments.map((a) => rewrite(a as ts.Expression, propNames)),
);
}
// Literals (string, numeric, boolean, null/undefined, etc.) pass through
// untouched.
return node;
}
|