sicua
Version:
A tool for analyzing project structure and dependencies
151 lines (150 loc) • 6.41 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractPropTypes = extractPropTypes;
exports.findPropDefaultValue = findPropDefaultValue;
const typescript_1 = __importDefault(require("typescript"));
const ASTUtils_1 = require("../../../utils/ast/ASTUtils");
/**
* Extracts prop types from a component node
* @param node Component AST node
* @param sourceFile Source file containing the component
* @returns Array of prop signatures
*/
function extractPropTypes(node, sourceFile) {
const props = [];
// Handle arrow functions with destructured props
if (typescript_1.default.isVariableDeclaration(node) &&
node.initializer &&
typescript_1.default.isArrowFunction(node.initializer)) {
extractPropsFromArrowFunction(node.initializer, props);
}
// Handle function declarations
else if (typescript_1.default.isFunctionDeclaration(node) && node.parameters.length > 0) {
const firstParam = node.parameters[0];
if (typescript_1.default.isParameter(firstParam)) {
extractPropsFromParameter(firstParam, props);
}
}
// Also check for interface declarations
extractPropsFromInterfaces(sourceFile, props);
return props;
}
/**
* Extracts props from arrow function parameters
* @param arrowFunc Arrow function node
* @param props Props array to populate
*/
function extractPropsFromArrowFunction(arrowFunc, props) {
// Get the first parameter
const firstParam = arrowFunc.parameters[0];
if (firstParam && typescript_1.default.isParameter(firstParam)) {
extractPropsFromParameter(firstParam, props);
}
}
/**
* Extracts props from function parameter
* @param param Parameter node
* @param props Props array to populate
*/
function extractPropsFromParameter(param, props) {
// Handle destructured parameter
if (typescript_1.default.isObjectBindingPattern(param.name)) {
const bindingPattern = param.name;
// Get the type annotation of the parameter
const typeAnnotation = param.type;
if (typeAnnotation && typescript_1.default.isTypeLiteralNode(typeAnnotation)) {
// Extract props from type literal
typeAnnotation.members.forEach((member) => {
if (typescript_1.default.isPropertySignature(member)) {
const propName = member.name.getText();
const propType = member.type?.getText() ?? "any";
const isOptional = !!member.questionToken;
props.push({
name: propName,
type: propType,
required: !isOptional,
});
}
});
}
// Also check binding elements for default values
bindingPattern.elements.forEach((element) => {
if (typescript_1.default.isBindingElement(element) && typescript_1.default.isIdentifier(element.name)) {
const existingProp = props.find((p) => p.name === element.name.getText());
if (existingProp && element.initializer) {
// If there's a default value, mark as optional
existingProp.required = false;
}
else if (!existingProp && element.initializer) {
// If prop wasn't found from type but has a binding element, add it
props.push({
name: element.name.getText(),
type: element.initializer.getText(),
required: false,
});
}
}
});
}
}
/**
* Extracts props from interface declarations
* @param sourceFile Source file to search
* @param props Props array to populate
*/
function extractPropsFromInterfaces(sourceFile, props) {
ASTUtils_1.ASTUtils.findNodes(sourceFile, typescript_1.default.isInterfaceDeclaration).forEach((interfaceDecl) => {
if (interfaceDecl.name.text.includes("Props")) {
interfaceDecl.members.forEach((member) => {
if (typescript_1.default.isPropertySignature(member)) {
props.push({
name: member.name.getText(),
type: member.type?.getText() ?? "any",
required: !member.questionToken,
});
}
});
}
});
}
/**
* Finds the default value for a prop in a component
* @param propName Name of the prop
* @param componentNode Component AST node
* @returns Default value string if found
*/
function findPropDefaultValue(propName, componentNode) {
if (typescript_1.default.isVariableDeclaration(componentNode) &&
componentNode.initializer &&
typescript_1.default.isArrowFunction(componentNode.initializer)) {
const param = componentNode.initializer.parameters[0];
if (param &&
typescript_1.default.isParameter(param) &&
typescript_1.default.isObjectBindingPattern(param.name)) {
const element = param.name.elements.find((el) => typescript_1.default.isBindingElement(el) &&
typescript_1.default.isIdentifier(el.name) &&
el.name.text === propName &&
el.initializer);
if (element && typescript_1.default.isBindingElement(element) && element.initializer) {
return element.initializer.getText();
}
}
}
else if (typescript_1.default.isFunctionDeclaration(componentNode) &&
componentNode.parameters.length > 0) {
const param = componentNode.parameters[0];
if (typescript_1.default.isParameter(param) && typescript_1.default.isObjectBindingPattern(param.name)) {
const element = param.name.elements.find((el) => typescript_1.default.isBindingElement(el) &&
typescript_1.default.isIdentifier(el.name) &&
el.name.text === propName &&
el.initializer);
if (element && typescript_1.default.isBindingElement(element) && element.initializer) {
return element.initializer.getText();
}
}
}
return undefined;
}