refakts
Version:
TypeScript refactoring tool built for AI coding agents to perform precise refactoring operations via command line instead of requiring complete code regeneration.
162 lines • 6.49 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.VariableLocatorCommand = void 0;
const variable_locator_1 = require("../locators/variable-locator");
const location_parser_1 = require("../core/location-parser");
const ast_service_1 = require("../services/ast-service");
const path = __importStar(require("path"));
class VariableLocatorCommand {
constructor() {
this.name = 'variable-locator';
this.description = 'Find variable declarations and all their usages';
this.complete = true;
this.astService = new ast_service_1.ASTService();
}
async execute(target, options) {
const finalOptions = this.processTarget(target, options);
this.validateOptions(finalOptions);
try {
await this.executeLocatorOperation(finalOptions);
}
catch (error) {
this.handleExecutionError(error);
}
}
async executeLocatorOperation(options) {
const result = await this.performLocatorOperation(options);
this.outputResults(result);
}
async performLocatorOperation(options) {
const location = options.location;
const node = await this.findTargetNode(location);
const variableName = this.getVariableName(node);
return await this.findAndFormatReferences(location, variableName);
}
async findTargetNode(location) {
const node = await this.astService.findNodeByLocation(location);
if (!node) {
throw new Error('Could not find node at specified location');
}
return node;
}
async findAndFormatReferences(location, variableName) {
const locator = new variable_locator_1.VariableLocator();
const result = await locator.findVariableReferences(location.file, variableName);
const fileName = path.basename(location.file);
return this.formatAsLocations(result, fileName);
}
handleExecutionError(error) {
process.stderr.write(`Error: ${error}\n`);
process.exit(1);
}
validateOptions(options) {
if (!options.location) {
throw new Error('Location format must be specified');
}
}
getHelpText() {
return '\nExamples:\n refakts variable-locator "[src/file.ts 10:5-10:10]"\n refakts variable-locator "[src/file.ts 3:15-3:20]"';
}
processTarget(target, options) {
if (location_parser_1.LocationParser.isLocationFormat(target)) {
const location = location_parser_1.LocationParser.parseLocation(target);
return { ...options, location };
}
return { ...options, target };
}
formatAsLocations(result, fileName) {
const locations = [];
this.addDeclarationLocation(result, fileName, locations);
this.addUsageLocations(result, fileName, locations);
return locations;
}
addDeclarationLocation(result, fileName, locations) {
if (result.declaration) {
const decl = result.declaration;
locations.push(`[${fileName} ${decl.line}:${decl.column}-${decl.line}:${decl.column + decl.text.length}] ${decl.text}`);
}
}
addUsageLocations(result, fileName, locations) {
if (result.usages) {
for (const usage of result.usages) {
locations.push(`[${fileName} ${usage.line}:${usage.column}-${usage.line}:${usage.column + usage.text.length}] ${usage.text}`);
}
}
}
outputResults(results) {
// eslint-disable-next-line no-console
results.forEach(result => console.log(result));
}
getVariableName(node) {
return this.isIdentifierNode(node)
? node.getText()
: this.extractCandidateNameOrThrow(node);
}
extractCandidateNameOrThrow(node) {
const candidateName = this.extractCandidateName(node);
if (!candidateName) {
throw new Error('Could not extract variable name from node');
}
return candidateName;
}
isIdentifierNode(node) {
return node.getKind() === 75;
}
extractCandidateName(node) {
return this.trySimpleTextExtraction(node) ||
this.tryVariableDeclarationExtraction(node) ||
this.tryIdentifierDescendantExtraction(node);
}
trySimpleTextExtraction(node) {
const text = node.getText().trim();
return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(text) ? text : null;
}
tryVariableDeclarationExtraction(node) {
if (node.getKind() === 261) {
const symbol = node.getSymbol();
const declarations = symbol?.getDeclarations();
const variableDeclaration = declarations?.[0];
return variableDeclaration ? variableDeclaration.getText() : null;
}
return null;
}
tryIdentifierDescendantExtraction(node) {
const identifiers = node.getDescendantsOfKind(75);
return identifiers.length > 0 ? identifiers[0].getText() : null;
}
}
exports.VariableLocatorCommand = VariableLocatorCommand;
//# sourceMappingURL=variable-locator-command.js.map