sicua
Version:
A tool for analyzing project structure and dependencies
281 lines (280 loc) • 9.5 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParameterParser = void 0;
const typescript_1 = __importDefault(require("typescript"));
/**
* Utility class for parsing function parameters comprehensively
*/
class ParameterParser {
/**
* Parses function parameters and returns detailed information
* @param node The function-like declaration
* @returns Array of parameter name strings (for backward compatibility)
*/
parseParameters(node) {
return node.parameters.map((param) => this.parseParameter(param).name);
}
/**
* Parses function parameters with detailed information
* @param node The function-like declaration
* @returns Array of detailed parameter information
*/
parseParametersDetailed(node) {
return node.parameters.map((param) => this.parseParameter(param));
}
/**
* Parses a single parameter node
* @param param The parameter declaration
* @returns Detailed parameter information
*/
parseParameter(param) {
const result = {
name: this.extractParameterName(param),
type: this.extractParameterType(param),
isOptional: this.isOptionalParameter(param),
hasDefaultValue: !!param.initializer,
defaultValue: this.extractDefaultValue(param),
isRestParameter: !!param.dotDotDotToken,
isDestructured: this.isDestructuredParameter(param),
destructuredProperties: this.extractDestructuredProperties(param),
};
return result;
}
/**
* Extracts the parameter name, handling destructuring and rest parameters
*/
extractParameterName(param) {
try {
// Handle rest parameters
if (param.dotDotDotToken) {
const name = this.getNameFromBindingName(param.name);
return `...${name}`;
}
// Handle destructuring patterns
if (typescript_1.default.isObjectBindingPattern(param.name)) {
return this.formatObjectDestructuring(param.name);
}
if (typescript_1.default.isArrayBindingPattern(param.name)) {
return this.formatArrayDestructuring(param.name);
}
// Handle simple identifier
if (typescript_1.default.isIdentifier(param.name)) {
return param.name.text;
}
return "unknown";
}
catch (error) {
return "unknown";
}
}
/**
* Extracts parameter type information
*/
extractParameterType(param) {
try {
if (param.type) {
return param.type.getText().trim();
}
return "unknown";
}
catch (error) {
return "unknown";
}
}
/**
* Checks if a parameter is optional
*/
isOptionalParameter(param) {
return !!param.questionToken || !!param.initializer;
}
/**
* Extracts the default value of a parameter if it exists
*/
extractDefaultValue(param) {
try {
if (param.initializer) {
return param.initializer.getText().trim();
}
return null;
}
catch (error) {
return null;
}
}
/**
* Checks if a parameter uses destructuring
*/
isDestructuredParameter(param) {
return (typescript_1.default.isObjectBindingPattern(param.name) ||
typescript_1.default.isArrayBindingPattern(param.name));
}
/**
* Extracts properties from destructured parameters
*/
extractDestructuredProperties(param) {
const properties = [];
if (typescript_1.default.isObjectBindingPattern(param.name)) {
param.name.elements.forEach((element) => {
if (typescript_1.default.isBindingElement(element)) {
const name = this.getNameFromBindingName(element.name);
if (name) {
properties.push(name);
}
}
});
}
if (typescript_1.default.isArrayBindingPattern(param.name)) {
param.name.elements.forEach((element) => {
if (element && typescript_1.default.isBindingElement(element)) {
const name = this.getNameFromBindingName(element.name);
if (name) {
properties.push(name);
}
}
});
}
return properties;
}
/**
* Formats object destructuring pattern for display
*/
formatObjectDestructuring(pattern) {
try {
const elements = pattern.elements
.map((element) => {
if (typescript_1.default.isBindingElement(element)) {
const name = this.getNameFromBindingName(element.name);
const propertyName = element.propertyName
? this.getNameFromPropertyName(element.propertyName)
: null;
if (propertyName && propertyName !== name) {
return `${propertyName}: ${name}`;
}
return name;
}
return "unknown";
})
.filter(Boolean);
return `{ ${elements.join(", ")} }`;
}
catch (error) {
return "{ ... }";
}
}
/**
* Safely extracts name from property name node
*/
getNameFromPropertyName(name) {
try {
if (typescript_1.default.isIdentifier(name)) {
return name.text;
}
if (typescript_1.default.isStringLiteral(name) || typescript_1.default.isNumericLiteral(name)) {
return name.text;
}
if (typescript_1.default.isComputedPropertyName(name)) {
return `[${name.expression.getText()}]`;
}
return "unknown";
}
catch (error) {
return "unknown";
}
}
/**
* Formats array destructuring pattern for display
*/
formatArrayDestructuring(pattern) {
try {
const elements = pattern.elements.map((element) => {
if (element && typescript_1.default.isBindingElement(element)) {
return this.getNameFromBindingName(element.name);
}
return "_"; // Hole in array destructuring
});
return `[ ${elements.join(", ")} ]`;
}
catch (error) {
return "[ ... ]";
}
}
/**
* Safely extracts name from binding name node
*/
getNameFromBindingName(name) {
try {
if (typescript_1.default.isIdentifier(name)) {
return name.text;
}
if (typescript_1.default.isObjectBindingPattern(name)) {
return this.formatObjectDestructuring(name);
}
if (typescript_1.default.isArrayBindingPattern(name)) {
return this.formatArrayDestructuring(name);
}
return "unknown";
}
catch (error) {
return "unknown";
}
}
/**
* Gets parameter count including rest parameters
*/
getParameterCount(node) {
return node.parameters.length;
}
/**
* Gets required parameter count (excluding optional and rest parameters)
*/
getRequiredParameterCount(node) {
return node.parameters.filter((param) => !param.questionToken && !param.initializer && !param.dotDotDotToken).length;
}
/**
* Checks if function has destructured parameters
*/
hasDestructuredParameters(node) {
return node.parameters.some((param) => this.isDestructuredParameter(param));
}
/**
* Checks if function has rest parameters
*/
hasRestParameters(node) {
return node.parameters.some((param) => !!param.dotDotDotToken);
}
/**
* Checks if function has optional parameters
*/
hasOptionalParameters(node) {
return node.parameters.some((param) => this.isOptionalParameter(param));
}
/**
* Gets the complexity score for parameters (for analysis purposes)
*/
getParameterComplexity(node) {
let complexity = 0;
node.parameters.forEach((param) => {
// Base complexity per parameter
complexity += 1;
// Additional complexity for destructuring
if (this.isDestructuredParameter(param)) {
complexity += 2;
const properties = this.extractDestructuredProperties(param);
complexity += properties.length * 0.5;
}
// Additional complexity for optional parameters
if (this.isOptionalParameter(param)) {
complexity += 1;
}
// Additional complexity for rest parameters
if (param.dotDotDotToken) {
complexity += 1;
}
});
return Math.round(complexity * 10) / 10; // Round to 1 decimal place
}
}
exports.ParameterParser = ParameterParser;