Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
this.addFinding(
start,
node.end,
"'try' statement is unnecessary because the 'try' block is empty.",
hasFinally ? deleteStatementLeavingBlock(node, finallyBlock!, this.sourceFile) : deleteStatement(node),
);
} else if (catchClause !== undefined && isRethrow(catchClause)) {
// reminder for myself: empty catch clause can be used to simply ignore errors and is never redundant
this.addFinding(
start,
node.end,
`${
hasFinally ? "'catch' clause" : "'try' statement"
} is unnecessary because the 'catch' clause only rethrows the error.`,
hasFinally
? Replacement.delete(catchClause.getStart(this.sourceFile), finallyBlock!.pos - 'finally'.length)
: deleteStatementLeavingBlock(node, tryBlock, this.sourceFile),
);
} else if (finallyBlock !== undefined && finallyBlock.statements.length === 0) {
if (catchClause === undefined) {
this.addFinding(
start,
node.end,
"'try' statement is unnecessary because the 'finally' block is empty.",
deleteStatementLeavingBlock(node, tryBlock, this.sourceFile),
);
} else {
this.addFinding(
finallyBlock!.pos - 'finally'.length,
node.end,
"Empty 'finally' clause is unnecessary.",
Replacement.delete(catchClause.end, finallyBlock.end),
private createFinding(message: string, severity: Severity, location: ts.TextRange, fixLocation = location): Finding {
return {
ruleName: 'useless-line-switch',
severity, // tslint:disable-line:object-shorthand-properties-first
message, // tslint:disable-line:object-shorthand-properties-first
start: this.createPosition(location.pos),
end: this.createPosition(location.end),
fix: {replacements: [Replacement.delete(fixLocation.pos, fixLocation.end)]},
};
}
}
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(
// remove open brace
Replacement.delete(start, start + 1),
// remove trailing comma if exists and close brace
Replacement.delete(arg.properties[arg.properties.length - 1].end, arg.end),
);
removedPrevious = false;
}
}
return fix;
}
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(
public apply() {
for (const node of this.context.getFlatAst()) {
if (isElementAccessExpression(node) &&
// for compatiblity with typescript@<2.9.0
node.argumentExpression !== undefined && // wotan-disable-line no-useless-predicate
isTextualLiteral(node.argumentExpression) && isValidPropertyAccess(node.argumentExpression.text)) {
const property = node.argumentExpression.text;
this.addFailureAtNode(
node.argumentExpression,
`Prefer 'obj.${property}' over 'obj[${node.argumentExpression.getText(this.sourceFile)}]'.`,
Replacement.replace(node.expression.end, node.end, '.' + property),
);
}
}
}
}
for (let match = re.exec(this.sourceFile.text); match !== null; match = re.exec(this.sourceFile.text)) {
if (match[1].length & 1) // only check if backslash is not escaped
continue;
const {node} = getWrappedNodeAtPosition(wrappedAst || (wrappedAst = this.context.getWrappedAst()), match.index)!;
switch (node.kind) {
case ts.SyntaxKind.StringLiteral:
case ts.SyntaxKind.NoSubstitutionTemplateLiteral:
case ts.SyntaxKind.TemplateHead:
case ts.SyntaxKind.TemplateMiddle:
case ts.SyntaxKind.TemplateTail:
if (match.index >= node.getStart(this.sourceFile))
this.addFinding(
match.index + match[1].length,
re.lastIndex,
'Octal escape sequences are deprecated and not allowed in strict mode.',
Replacement.replace(
match.index + match[1].length + 1,
re.lastIndex,
`x${toHexSequence(parseInt(match[0].substr(match[1].length + 1), 8))}`,
),
);
}
}
}
}
nodir: true,
realpathCache: {},
statCache: {},
symlinks: {},
};
for (const pattern of patterns) {
let matched = pattern.hasMagic;
for (const normalized of pattern.normalized) {
const match = glob.sync(normalized, globOptions);
if (match.length !== 0) {
matched = true;
result.push(...match);
}
}
if (!matched && !isExcluded(pattern.normalized[0], exclude.map((p) => new Minimatch(p, {dot: true}))))
throw new ConfigurationError(`'${pattern.normalized[0]}' does not exist.`);
}
return new Set(result.map(unixifyPath)); // deduplicate files
}
public format(fileName: string, summary: FileSummary): undefined {
this.fixed += summary.fixes;
if (summary.failures.length === 0)
return;
const mapped: FailureInfo[] = [];
for (const failure of summary.failures.slice().sort(Failure.compare)) {
if (failure.fix !== undefined)
++this.fixable;
if (failure.severity.length > this.maxSeverityWidth)
this.maxSeverityWidth = failure.severity.length;
if (failure.ruleName.length > this.maxNameWidth)
this.maxNameWidth = failure.ruleName.length;
let {character, line} = failure.start;
if (line !== 0 || character === 0 || !summary.content.startsWith('\uFEFF'))
character += 1; // avoid incrementing the character position on the first line if BOM is present, editors ignore BOM
const position = `${line + 1}:${character}`;
if (position.length > this.maxPositionWidth)
this.maxPositionWidth = position.length;
mapped.push({
position,
severity: failure.severity,
ruleName: failure.ruleName,
public loadFormatter(name: string): FormatterConstructor {
let formatter: FormatterConstructor | undefined;
if (/^[a-zA-Z-]+$/.test(name))
formatter = this.host.loadCoreFormatter(name);
if (formatter === undefined)
formatter = this.host.loadCustomFormatter(name, this.directories.getCurrentDirectory());
if (formatter === undefined)
throw new ConfigurationError(`Cannot find formatter '${name}' relative to '${this.directories.getCurrentDirectory()}'.`);
return formatter;
}
}
export function createBaseline(summary: FileSummary): string {
if (summary.findings.length === 0)
return summary.content;
const findings = summary.findings.slice().sort(Finding.compare);
const lines: string[] = [];
let lineStart = 0;
let findingPosition = 0;
let pendingFindings: Finding[] = [];
for (const line of summary.content.split(/\n/g)) {
lines.push(line);
const nextLineStart = lineStart + line.length + 1;
const lineLength = line.length - (line.endsWith('\r') ? 1 : 0);
const pending: Finding[] = [];
for (const finding of pendingFindings)
lines.push(formatFinding(finding, lineStart, lineLength, nextLineStart, pending));
pendingFindings = pending;
for (; findingPosition < findings.length && findings[findingPosition].start.position < nextLineStart; ++findingPosition)
lines.push(formatFinding(findings[findingPosition], lineStart, lineLength, nextLineStart, pendingFindings));