Files
orca/config/scripts/mobile-localization-rendered-variable.mjs
T

120 lines
3.2 KiB
JavaScript

// TypeScript 7 is a native CLI; AST consumers still need the legacy JavaScript API.
import ts from 'typescript-api'
function isDirectDisplayExpressionParent(parent, child) {
if (
ts.isParenthesizedExpression(parent) ||
ts.isAsExpression(parent) ||
ts.isSatisfiesExpression(parent)
) {
return parent.expression === child
}
if (ts.isConditionalExpression(parent)) {
return parent.whenTrue === child || parent.whenFalse === child
}
if (ts.isBinaryExpression(parent)) {
return [
ts.SyntaxKind.PlusToken,
ts.SyntaxKind.BarBarToken,
ts.SyntaxKind.QuestionQuestionToken
].includes(parent.operatorToken.kind)
}
return ts.isTemplateSpan(parent) || ts.isTemplateExpression(parent)
}
export function isRenderedJsxExpression(node) {
let current = node.parent
while (current) {
if (ts.isJsxExpression(current)) {
return (
ts.isJsxElement(current.parent) ||
ts.isJsxFragment(current.parent) ||
ts.isJsxSelfClosingElement(current.parent)
)
}
if (
ts.isConditionalExpression(current) ||
ts.isParenthesizedExpression(current) ||
ts.isTemplateExpression(current) ||
ts.isNoSubstitutionTemplateLiteral(current)
) {
if (ts.isConditionalExpression(current) && current.condition === node) {
return false
}
current = current.parent
continue
}
if (ts.isBinaryExpression(current)) {
const operator = current.operatorToken.kind
if (
![
ts.SyntaxKind.PlusToken,
ts.SyntaxKind.AmpersandAmpersandToken,
ts.SyntaxKind.BarBarToken,
ts.SyntaxKind.QuestionQuestionToken
].includes(operator) ||
(operator !== ts.SyntaxKind.PlusToken && current.left === node)
) {
return false
}
current = current.parent
continue
}
return false
}
return false
}
function assignedVariableName(node) {
let current = node
while (current.parent && isDirectDisplayExpressionParent(current.parent, current)) {
current = current.parent
}
const parent = current.parent
if (
parent &&
ts.isVariableDeclaration(parent) &&
parent.initializer === current &&
ts.isIdentifier(parent.name)
) {
return parent.name.text
}
return parent &&
ts.isBinaryExpression(parent) &&
parent.operatorToken.kind === ts.SyntaxKind.EqualsToken &&
parent.right === current &&
ts.isIdentifier(parent.left)
? parent.left.text
: undefined
}
export function isAssignedToRenderedVariable(node, isRenderedExpression = isRenderedJsxExpression) {
if (ts.isTemplateExpression(node)) {
return false
}
const name = assignedVariableName(node)
if (!name) {
return false
}
let owner = node.parent
while (owner && !ts.isFunctionLike(owner) && !ts.isSourceFile(owner)) {
owner = owner.parent
}
if (!owner) {
return false
}
let rendered = false
function visit(current) {
if (rendered) {
return
}
if (ts.isIdentifier(current) && current.text === name && isRenderedExpression(current)) {
rendered = true
return
}
ts.forEachChild(current, visit)
}
visit(owner)
return rendered
}