mirror of
https://github.com/samiyev/puaros.git
synced 2025-12-28 07:16:53 +05:00
93 lines
2.6 KiB
TypeScript
93 lines
2.6 KiB
TypeScript
import Parser from "tree-sitter"
|
|
import { HardcodedValue, HardcodeType } from "../../domain/value-objects/HardcodedValue"
|
|
import { DETECTION_VALUES, HARDCODE_TYPES } from "../../shared/constants/rules"
|
|
import { AstContextChecker } from "./AstContextChecker"
|
|
|
|
/**
|
|
* AST-based analyzer for detecting magic booleans
|
|
*
|
|
* Detects boolean literals used as arguments without clear meaning.
|
|
* Example: doSomething(true, false, true) - hard to understand
|
|
* Better: doSomething({ sync: true, validate: false, cache: true })
|
|
*/
|
|
export class AstBooleanAnalyzer {
|
|
constructor(private readonly contextChecker: AstContextChecker) {}
|
|
|
|
/**
|
|
* Analyzes a boolean node and returns a violation if it's a magic boolean
|
|
*/
|
|
public analyze(node: Parser.SyntaxNode, lines: string[]): HardcodedValue | null {
|
|
if (!this.shouldDetect(node)) {
|
|
return null
|
|
}
|
|
|
|
const value = node.text === DETECTION_VALUES.BOOLEAN_TRUE
|
|
|
|
return this.createViolation(node, value, lines)
|
|
}
|
|
|
|
/**
|
|
* Checks if boolean should be detected
|
|
*/
|
|
private shouldDetect(node: Parser.SyntaxNode): boolean {
|
|
if (this.contextChecker.isInExportedConstant(node)) {
|
|
return false
|
|
}
|
|
|
|
if (this.contextChecker.isInTypeContext(node)) {
|
|
return false
|
|
}
|
|
|
|
if (this.contextChecker.isInTestDescription(node)) {
|
|
return false
|
|
}
|
|
|
|
const parent = node.parent
|
|
if (!parent) {
|
|
return false
|
|
}
|
|
|
|
if (parent.type === "arguments") {
|
|
return this.isInFunctionCallWithMultipleBooleans(parent)
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
/**
|
|
* Checks if function call has multiple boolean arguments
|
|
*/
|
|
private isInFunctionCallWithMultipleBooleans(argsNode: Parser.SyntaxNode): boolean {
|
|
let booleanCount = 0
|
|
|
|
for (const child of argsNode.children) {
|
|
if (child.type === "true" || child.type === "false") {
|
|
booleanCount++
|
|
}
|
|
}
|
|
|
|
return booleanCount >= 2
|
|
}
|
|
|
|
/**
|
|
* Creates a HardcodedValue violation from a boolean node
|
|
*/
|
|
private createViolation(
|
|
node: Parser.SyntaxNode,
|
|
value: boolean,
|
|
lines: string[],
|
|
): HardcodedValue {
|
|
const lineNumber = node.startPosition.row + 1
|
|
const column = node.startPosition.column
|
|
const context = lines[node.startPosition.row]?.trim() ?? ""
|
|
|
|
return HardcodedValue.create(
|
|
value,
|
|
HARDCODE_TYPES.MAGIC_BOOLEAN as HardcodeType,
|
|
lineNumber,
|
|
column,
|
|
context,
|
|
)
|
|
}
|
|
}
|