ripbug-ai-detector
Version:
🔥 RipBug AI Bug Detector - Built by an AI that rips its own bugs. Destroy AI-generated bugs before you commit.
278 lines • 10.7 kB
JavaScript
"use strict";
// Enhanced SimpleParser - gradually adding tree-sitter features
// Keeps working regex base while adding AST parsing incrementally
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SimpleParser = void 0;
const tree_sitter_1 = __importDefault(require("tree-sitter"));
const tree_sitter_javascript_1 = __importDefault(require("tree-sitter-javascript"));
const tree_sitter_typescript_1 = __importDefault(require("tree-sitter-typescript"));
class SimpleParser {
jsParser;
tsParser;
constructor() {
// Initialize parsers lazily for better performance
this.initializeParsers();
}
initializeParsers() {
try {
this.jsParser = new tree_sitter_1.default();
this.jsParser.setLanguage(tree_sitter_javascript_1.default);
this.tsParser = new tree_sitter_1.default();
this.tsParser.setLanguage(tree_sitter_typescript_1.default.typescript);
}
catch (error) {
console.warn('Tree-sitter initialization failed, falling back to regex:', error);
}
}
// Extract function definitions using regex (simplified approach)
extractFunctions(content, filePath) {
const functions = [];
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Match function declarations: function name(params) or export function name(params)
const funcMatch = line.match(/(?:export\s+)?function\s+(\w+)\s*\(([^)]*)\)/);
if (funcMatch) {
const [, name, paramsStr] = funcMatch;
const parameters = this.parseParameters(paramsStr);
functions.push({
name,
parameters,
file: filePath,
line: i + 1,
column: line.indexOf('function'),
isExported: line.includes('export'),
isAsync: line.includes('async'),
isArrow: false
});
}
// Match arrow functions: const name = (params) => or export const name = (params) =>
const arrowMatch = line.match(/(?:export\s+)?const\s+(\w+)\s*=\s*(?:async\s*)?\(([^)]*)\)\s*=>/);
if (arrowMatch) {
const [, name, paramsStr] = arrowMatch;
const parameters = this.parseParameters(paramsStr);
functions.push({
name,
parameters,
file: filePath,
line: i + 1,
column: line.indexOf('const'),
isExported: line.includes('export'),
isAsync: line.includes('async'),
isArrow: true
});
}
}
return functions;
}
// Extract function calls using regex
extractFunctionCalls(content, filePath) {
const calls = [];
const lines = content.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
// Match function calls: functionName(
const callMatches = line.matchAll(/(\w+)\s*\(/g);
for (const match of callMatches) {
const [, name] = match;
// Skip common keywords and built-ins
if (this.isBuiltinFunction(name)) {
continue;
}
calls.push({
name,
file: filePath,
line: i + 1,
column: match.index || 0,
context: line.trim()
});
}
}
return calls;
}
// Enhanced parameter parsing with optional tree-sitter fallback
parseParameters(paramsStr, content, isTypeScript) {
if (!paramsStr.trim()) {
return [];
}
// Try tree-sitter parsing for better accuracy (if available)
if (content && (this.jsParser || this.tsParser)) {
const astParams = this.parseParametersWithAST(content, isTypeScript || false);
if (astParams.length > 0) {
return astParams;
}
}
// Fallback to regex parsing (existing working code)
const parameters = [];
const params = paramsStr.split(',').map(p => p.trim());
for (const param of params) {
if (!param)
continue;
// Handle TypeScript types: name: type
const typeMatch = param.match(/(\w+)(\?)?:\s*([^=]+)(?:=(.+))?/);
if (typeMatch) {
const [, name, optional, type, defaultValue] = typeMatch;
parameters.push({
name,
type: type.trim(),
optional: !!optional,
defaultValue: defaultValue?.trim()
});
continue;
}
// Handle default values: name = value
const defaultMatch = param.match(/(\w+)\s*=\s*(.+)/);
if (defaultMatch) {
const [, name, defaultValue] = defaultMatch;
parameters.push({
name,
optional: true,
defaultValue: defaultValue.trim()
});
continue;
}
// Simple parameter: just name
const nameMatch = param.match(/(\w+)/);
if (nameMatch) {
parameters.push({
name: nameMatch[1],
optional: false
});
}
}
return parameters;
}
// Tree-sitter parameter parsing (enhanced accuracy)
parseParametersWithAST(content, isTypeScript) {
try {
const parser = isTypeScript ? this.tsParser : this.jsParser;
if (!parser)
return [];
const tree = parser.parse(content);
const parameters = [];
// Find function declarations in the AST
this.findFunctionParameters(tree.rootNode, parameters);
return parameters;
}
catch (error) {
// Silently fall back to regex parsing
return [];
}
}
// Safely traverse AST to find function parameters
findFunctionParameters(node, parameters) {
try {
// Look for function declarations
if (node.type === 'function_declaration' || node.type === 'arrow_function') {
const paramsNode = this.findParametersNode(node);
if (paramsNode) {
this.extractParametersFromNode(paramsNode, parameters);
}
}
// Recursively check child nodes (safely)
if (node.children && Array.isArray(node.children)) {
for (const child of node.children) {
if (child && typeof child === 'object') {
this.findFunctionParameters(child, parameters);
}
}
}
}
catch (error) {
// Skip this node if there's any error
}
}
// Find the parameters node in a function
findParametersNode(functionNode) {
try {
if (!functionNode.children)
return null;
for (const child of functionNode.children) {
if (child && child.type === 'formal_parameters') {
return child;
}
}
return null;
}
catch (error) {
return null;
}
}
// Extract parameters from the parameters node
extractParametersFromNode(paramsNode, parameters) {
try {
if (!paramsNode.children)
return;
for (const child of paramsNode.children) {
if (!child || child.type === '(' || child.type === ')' || child.type === ',') {
continue;
}
const param = this.parseParameterNode(child);
if (param) {
parameters.push(param);
}
}
}
catch (error) {
// Skip this parameter if there's any error
}
}
// Parse individual parameter node
parseParameterNode(node) {
try {
if (!node.text)
return null;
const text = node.text.trim();
// Handle TypeScript typed parameters: name: type
const typedMatch = text.match(/^(\w+)(\?)?:\s*([^=]+)(?:\s*=\s*(.+))?$/);
if (typedMatch) {
const [, name, optional, type, defaultValue] = typedMatch;
return {
name,
type: type.trim(),
optional: !!optional || !!defaultValue,
defaultValue: defaultValue?.trim()
};
}
// Handle parameters with default values: name = value
const defaultMatch = text.match(/^(\w+)\s*=\s*(.+)$/);
if (defaultMatch) {
const [, name, defaultValue] = defaultMatch;
return {
name,
optional: true,
defaultValue: defaultValue.trim()
};
}
// Simple parameter: just name
const nameMatch = text.match(/^(\w+)$/);
if (nameMatch) {
return {
name: nameMatch[1],
optional: false
};
}
return null;
}
catch (error) {
return null;
}
}
// Check if function name is a built-in
isBuiltinFunction(name) {
const builtins = [
'console', 'require', 'import', 'export', 'if', 'for', 'while',
'return', 'throw', 'try', 'catch', 'new', 'typeof', 'instanceof',
'parseInt', 'parseFloat', 'isNaN', 'isFinite', 'encodeURIComponent',
'decodeURIComponent', 'setTimeout', 'setInterval', 'clearTimeout',
'clearInterval', 'JSON', 'Object', 'Array', 'String', 'Number',
'Boolean', 'Date', 'Math', 'RegExp', 'Error', 'Promise'
];
return builtins.includes(name);
}
}
exports.SimpleParser = SimpleParser;
//# sourceMappingURL=simple-parser.js.map