UNPKG

@slippy-lint/slippy

Version:

A simple but powerful linter for Solidity

152 lines 5.54 kB
import { Block, DoWhileStatement, ElseBranch, ForStatement, IfStatement, WhileStatement, } from "@nomicfoundation/slang/ast"; import { assertNonterminalNode, NonterminalKind, TerminalKind, TerminalKindExtensions, } from "@nomicfoundation/slang/cst"; const name = "curly"; export const Curly = { name, recommended: false, create: function () { return new CurlyRule(this.name); }, }; class CurlyRule { constructor(name) { this.name = name; } run({ file }) { const diagnostics = []; const cursor = file.createTreeCursor(); while (cursor.goToNextNonterminalWithKinds([ NonterminalKind.IfStatement, NonterminalKind.ElseBranch, NonterminalKind.WhileStatement, NonterminalKind.ForStatement, NonterminalKind.DoWhileStatement, ])) { if (cursor.node.kind === NonterminalKind.IfStatement) { diagnostics.push(...this.checkIfStatement(cursor.spawn(), file)); } else if (cursor.node.kind === NonterminalKind.ElseBranch) { diagnostics.push(...this.checkElseBranch(cursor.spawn(), file)); } else if (cursor.node.kind === NonterminalKind.WhileStatement) { diagnostics.push(...this.checkWhileStatement(cursor.spawn(), file)); } else if (cursor.node.kind === NonterminalKind.ForStatement) { diagnostics.push(...this.checkForStatement(cursor.spawn(), file)); } else if (cursor.node.kind === NonterminalKind.DoWhileStatement) { diagnostics.push(...this.checkDoWhileStatement(cursor.spawn(), file)); } } return diagnostics; } checkIfStatement(cursor, file) { assertNonterminalNode(cursor.node, NonterminalKind.IfStatement); const ifStatement = new IfStatement(cursor.node); if (ifStatement.body.variant instanceof Block) { return []; } if (!cursor.goToNextTerminalWithKind(TerminalKind.CloseParen)) { return []; } ignoreTrivia(cursor); return [ { rule: this.name, sourceId: file.id, line: cursor.textRange.start.line, column: cursor.textRange.start.column, message: "Expected { after 'if' condition", }, ]; } checkElseBranch(cursor, file) { assertNonterminalNode(cursor.node, NonterminalKind.ElseBranch); const elseBranch = new ElseBranch(cursor.node); if (elseBranch.body.variant instanceof Block || elseBranch.body.variant instanceof IfStatement) { return []; } if (!cursor.goToNextTerminalWithKind(TerminalKind.ElseKeyword)) { return []; } ignoreTrivia(cursor); return [ { rule: this.name, sourceId: file.id, line: cursor.textRange.start.line, column: cursor.textRange.start.column, message: "Expected { after 'else'", }, ]; } checkWhileStatement(cursor, file) { assertNonterminalNode(cursor.node, NonterminalKind.WhileStatement); const whileStatement = new WhileStatement(cursor.node); if (whileStatement.body.variant instanceof Block) { return []; } if (!cursor.goToNextTerminalWithKind(TerminalKind.CloseParen)) { return []; } ignoreTrivia(cursor); return [ { rule: this.name, sourceId: file.id, line: cursor.textRange.start.line, column: cursor.textRange.start.column, message: "Expected { after 'while' condition", }, ]; } checkForStatement(cursor, file) { assertNonterminalNode(cursor.node, NonterminalKind.ForStatement); const forStatement = new ForStatement(cursor.node); if (forStatement.body.variant instanceof Block) { return []; } if (!cursor.goToNextTerminalWithKind(TerminalKind.CloseParen)) { return []; } ignoreTrivia(cursor); return [ { rule: this.name, sourceId: file.id, line: cursor.textRange.start.line, column: cursor.textRange.start.column, message: "Expected { after 'for' condition", }, ]; } checkDoWhileStatement(cursor, file) { assertNonterminalNode(cursor.node, NonterminalKind.DoWhileStatement); const doWhileStatement = new DoWhileStatement(cursor.node); if (doWhileStatement.body.variant instanceof Block) { return []; } if (!cursor.goToNextTerminalWithKind(TerminalKind.DoKeyword)) { return []; } ignoreTrivia(cursor); return [ { rule: this.name, sourceId: file.id, line: cursor.textRange.start.line, column: cursor.textRange.start.column, message: "Expected { after 'do'", }, ]; } } function ignoreTrivia(cursor) { while (cursor.goToNextTerminal() && cursor.node.isTerminalNode() && TerminalKindExtensions.isTrivia(cursor.node.kind)) { // Skip trivia } } //# sourceMappingURL=curly.js.map