Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
function createFix(node: ts.CallExpression, sourceFile: ts.SourceFile) {
const args = node.arguments;
const objectNeedsParens = objectLiteralNeedsParens(node);
const fix = [
Replacement.replace(node.getStart(sourceFile), args[0].getStart(sourceFile), `${objectNeedsParens ? '(' : ''}{`),
Replacement.replace(node.end - 1, node.end, `}${objectNeedsParens ? ')' : ''}`),
];
let removedPrevious = false;
for (let i = 0; i < args.length; ++i) {
const arg = args[i];
if (!isObjectLiteralExpression(arg)) {
fix.push(Replacement.append(arg.getStart(sourceFile), '...'));
removedPrevious = false;
continue;
}
if (arg.properties.length === 0) {
let end = arg.end;
if (i !== args.length - 1) {
end = args[i + 1].getStart(sourceFile);
} else if (args.hasTrailingComma) {
end = args.end;
}
// remove empty object iteral and the following comma if exists
fix.push(Replacement.delete(removedPrevious ? arg.getStart(sourceFile) : arg.pos, end));
removedPrevious = true;
} else {
const start = arg.getStart(sourceFile);
fix.push(
function enforceAsTypeAssertion(context: RuleContext) {
for (const node of context.getFlatAst()) {
if (isTypeAssertion(node)) {
const assertionParens = assertionNeedsParens(node);
const expressionParens = node.expression.kind === ts.SyntaxKind.YieldExpression ||
!assertionParens && expressionNeedsParensWhenReplacingNode(node.expression, node);
const start = node.getStart(context.sourceFile);
context.addFinding(start, node.expression.pos, "Use 'obj as T' instead.", [
Replacement.replace(
start,
node.expression.getStart(context.sourceFile),
charIf(expressionParens, '(') + charIf(assertionParens, '('),
),
Replacement.append(
node.end,
`${charIf(expressionParens, ')')} as ${node.type.getText(context.sourceFile)}${charIf(assertionParens, ')')}`,
),
]);
}
}
}
private checkReturnExpression(node: ts.Expression) {
const {pos} = node;
while (isParenthesizedExpression(node))
node = node.expression;
if (node.kind === ts.SyntaxKind.AwaitExpression)
return;
if (isThenableType(this.checker, node))
this.addFinding(
pos - 'return'.length,
pos,
"Missing 'await' of Promise returned inside try-catch.",
needsParens(node)
? [
Replacement.append(pos, ' await'),
Replacement.append(node.getStart(this.sourceFile), '('),
Replacement.append(node.end, ')'),
]
: Replacement.append(pos, ' await'),
);
}
}
public apply() {
const re = /\bawait\b/g;
let wrappedAst: WrappedAst | undefined;
for (let match = re.exec(this.sourceFile.text); match !== null; match = re.exec(this.sourceFile.text)) {
const {node} = getWrappedNodeAtPosition(wrappedAst || (wrappedAst = this.context.getWrappedAst()), match.index)!;
if (isAwaitExpression(node)) {
if (
node.expression.pos !== re.lastIndex ||
this.maybePromiseLike(this.checker.getTypeAtLocation(node.expression)!, node.expression)
)
continue;
const fix = [Replacement.delete(match.index, node.expression.getStart(this.sourceFile))];
if (expressionNeedsParensWhenReplacingNode(node.expression, node))
fix.push(
Replacement.append(match.index, '('),
Replacement.append(node.expression.end, ')'),
);
this.addFinding(
match.index,
node.end,
"Unnecessary 'await' of a non-Promise value.",
fix,
);
} else if (node.kind === ts.SyntaxKind.AwaitKeyword && node.end === re.lastIndex) {
const parent = node.parent!;
if (isForOfStatement(parent) && !this.isAsyncIterable(parent.expression)) {
const start = node.pos - 'for'.length;
this.addFinding(
start,
parent.statement.pos,
"Unnecessary 'for await' of a non-AsyncIterable value.",
Replacement.delete(start + 'for'.length, re.lastIndex),
private checkReturnExpression(node: ts.Expression) {
const {pos} = node;
while (isParenthesizedExpression(node))
node = node.expression;
if (node.kind === ts.SyntaxKind.AwaitExpression)
return;
if (isThenableType(this.checker, node))
this.addFinding(
pos - 'return'.length,
pos,
"Missing 'await' of Promise returned inside try-catch.",
needsParens(node)
? [
Replacement.append(pos, ' await'),
Replacement.append(node.getStart(this.sourceFile), '('),
Replacement.append(node.end, ')'),
]
: Replacement.append(pos, ' await'),
);
}
}
public apply() {
const sourceFile = this.sourceFile;
const end = sourceFile.end;
if (end === 0 || end === 1 && sourceFile.text[0] === '\uFEFF' || sourceFile.text[end - 1] === '\n')
return;
const lines = sourceFile.getLineStarts();
this.addFinding(
end,
end,
'File must end with a newline.',
Replacement.append(end, lines.length === 0 || sourceFile.text[lines[1] - 2] !== '\r' ? '\n' : '\r\n'),
);
}
}
private checkReturnExpression(node: ts.Expression) {
const {pos} = node;
while (isParenthesizedExpression(node))
node = node.expression;
if (node.kind === ts.SyntaxKind.AwaitExpression)
return;
if (isThenableType(this.checker, node))
this.addFinding(
pos - 'return'.length,
pos,
"Missing 'await' of Promise returned inside try-catch.",
needsParens(node)
? [
Replacement.append(pos, ' await'),
Replacement.append(node.getStart(this.sourceFile), '('),
Replacement.append(node.end, ')'),
]
: Replacement.append(pos, ' await'),
);
}
}
)) {
fix.push(Replacement.delete(grandparent.getStart(this.sourceFile), grandparent.arguments[0].pos - 1));
} else {
fix.push(
Replacement.delete(grandparent.getStart(this.sourceFile), grandparent.arguments[0].getStart(this.sourceFile)),
Replacement.delete(grandparent.end - 1, grandparent.end),
);
}
if (expressionNeedsParens(fixed.left))
fix.push(
Replacement.append(grandparent.arguments[0].getStart(this.sourceFile), '('),
Replacement.append(grandparent.arguments[0].end, ')'),
);
if (expressionNeedsParens(fixed.right))
fix.push(
Replacement.append(grandparent.arguments[1].getStart(this.sourceFile), '('),
Replacement.append(grandparent.arguments[1].end, ')'),
);
this.addFailureAtNode(
grandparent,
"Prefer the exponentiation operator '**' over 'Math.pow'.",
fix,
);
}
}
}
function enforceClassicTypeAssertion(context: RuleContext) {
const re = /\bas\b/g;
let wrappedAst: WrappedAst | undefined;
for (let match = re.exec(context.sourceFile.text); match !== null; match = re.exec(context.sourceFile.text)) {
const {node} = getWrappedNodeAtPosition(wrappedAst || (wrappedAst = context.getWrappedAst()), match.index)!;
if (!isAsExpression(node) || node.type.pos !== re.lastIndex)
continue;
const parent = node.parent!;
const expressionNeedsParens = node.expression.kind === ts.SyntaxKind.BinaryExpression;
const needsParens = isBinaryExpression(parent) && parent.operatorToken.kind === ts.SyntaxKind.AsteriskAsteriskToken;
context.addFinding(match.index, node.end, "Use the classic type assertion style 'obj' instead.", [
Replacement.append(
node.getStart(context.sourceFile),
`${charIf(needsParens, '(')}<${node.type.getText(context.sourceFile)}>${charIf(expressionNeedsParens, '(')}`,
),
Replacement.replace(node.expression.end, node.end, charIf(expressionNeedsParens, ')') + charIf(needsParens, ')')),
]);
}
}