@paulohenriquevn/m2js
Version:
Transform TypeScript/JavaScript code into LLM-friendly Markdown summaries + Smart Dead Code Detection + Graph-Deep Diff Analysis. Extract exported functions, classes, and JSDoc comments for better AI context with 60%+ token reduction. Intelligent dead cod
479 lines • 17.2 kB
JavaScript
;
/* eslint-disable max-lines */
/* eslint-disable max-lines-per-function */
/* eslint-disable complexity */
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;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseFile = parseFile;
const parser_1 = require("@babel/parser");
const traverse_1 = __importDefault(require("@babel/traverse"));
const t = __importStar(require("@babel/types"));
const path_1 = __importDefault(require("path"));
const DEFAULT_PARSE_OPTIONS = {
sourceType: 'module',
plugins: ['typescript', 'jsx', 'decorators-legacy', 'classProperties'],
};
function parseFile(filePath, content) {
if (!content.trim()) {
throw new Error(`File is empty: ${filePath}`);
}
try {
const ast = (0, parser_1.parse)(content, DEFAULT_PARSE_OPTIONS);
const functions = extractExportedFunctions(ast);
const classes = extractExportedClasses(ast);
const exportMetadata = generateExportMetadata(functions, classes, ast);
return {
fileName: path_1.default.basename(filePath),
filePath: path_1.default.resolve(filePath),
functions,
classes,
exportMetadata,
};
}
catch (error) {
throw new Error(`Parse error in ${filePath}: ${error.message}`);
}
}
function extractExportedFunctions(ast) {
const functions = [];
(0, traverse_1.default)(ast, {
ExportNamedDeclaration(path) {
if (t.isFunctionDeclaration(path.node.declaration)) {
const func = parseFunctionDeclaration(path.node.declaration, false, path);
if (func) {
functions.push(func);
}
}
// Handle export const arrowFunction = () => {}
if (t.isVariableDeclaration(path.node.declaration)) {
path.node.declaration.declarations.forEach(declarator => {
if (t.isIdentifier(declarator.id) &&
(t.isArrowFunctionExpression(declarator.init) ||
t.isFunctionExpression(declarator.init))) {
const func = parseArrowFunction(declarator.id.name, declarator.init);
if (func) {
functions.push(func);
}
}
});
}
},
ExportDefaultDeclaration(path) {
if (t.isFunctionDeclaration(path.node.declaration)) {
const func = parseFunctionDeclaration(path.node.declaration, true, path);
if (func) {
functions.push(func);
}
}
},
});
return functions;
}
function extractExportedClasses(ast) {
const classes = [];
(0, traverse_1.default)(ast, {
ExportNamedDeclaration(path) {
if (t.isClassDeclaration(path.node.declaration)) {
const cls = parseClassDeclaration(path.node.declaration, path);
if (cls) {
classes.push(cls);
}
}
},
ExportDefaultDeclaration(path) {
if (t.isClassDeclaration(path.node.declaration)) {
const cls = parseClassDeclaration(path.node.declaration, path, true);
if (cls) {
classes.push(cls);
}
}
},
});
return classes;
}
function parseFunctionDeclaration(node, isDefault, path) {
if (!node.id && !isDefault) {
return null;
}
const name = isDefault ? 'default' : node.id?.name || 'anonymous';
const params = parseParameters(node.params);
const returnType = parseReturnType(node);
const signature = generateSignature(name, params, returnType, isDefault);
const jsDoc = path ? extractJSDoc(path) : undefined;
return {
name,
signature,
isDefault,
params,
returnType,
jsDoc,
};
}
function parseArrowFunction(name, node) {
const params = parseParameters(node.params);
const returnType = parseArrowReturnType(node);
const signature = `export const ${name} = (${params
.map(p => {
const optional = p.optional ? '?' : '';
const type = p.type ? `: ${p.type}` : '';
return `${p.name}${optional}${type}`;
})
.join(', ')})${returnType ? `: ${returnType}` : ''} => {}`;
return {
name,
signature,
isDefault: false,
params,
returnType,
};
}
function parseParameters(params) {
return params.map(param => {
if (t.isIdentifier(param)) {
return {
name: param.name,
type: param.typeAnnotation
? getTypeAnnotation(param.typeAnnotation)
: undefined,
optional: param.optional || false,
};
}
if (t.isAssignmentPattern(param) && t.isIdentifier(param.left)) {
return {
name: param.left.name,
type: param.left.typeAnnotation
? getTypeAnnotation(param.left.typeAnnotation)
: undefined,
optional: true,
};
}
return {
name: 'param',
optional: false,
};
});
}
function getTypeAnnotation(typeAnnotation) {
if (t.isTSTypeAnnotation(typeAnnotation)) {
return getTypeString(typeAnnotation.typeAnnotation);
}
return 'unknown';
}
function getTypeString(type) {
// Primitive types
if (t.isTSStringKeyword(type))
return 'string';
if (t.isTSNumberKeyword(type))
return 'number';
if (t.isTSBooleanKeyword(type))
return 'boolean';
if (t.isTSVoidKeyword(type))
return 'void';
if (t.isTSUndefinedKeyword(type))
return 'undefined';
if (t.isTSNullKeyword(type))
return 'null';
if (t.isTSAnyKeyword(type))
return 'any';
// Array types
if (t.isTSArrayType(type)) {
return `${getTypeString(type.elementType)}[]`;
}
// Promise and generic types
if (t.isTSTypeReference(type)) {
if (t.isIdentifier(type.typeName)) {
const typeName = type.typeName.name;
if (type.typeParameters && type.typeParameters.params.length > 0) {
const params = type.typeParameters.params
.map(param => getTypeString(param))
.join(', ');
return `${typeName}<${params}>`;
}
return typeName;
}
if (t.isTSQualifiedName(type.typeName)) {
return getQualifiedTypeName(type.typeName);
}
}
// Union types (e.g., 'light' | 'dark')
if (t.isTSUnionType(type)) {
const types = type.types.map(t => getTypeString(t)).join(' | ');
return types;
}
// Intersection types (e.g., User & { id: string })
if (t.isTSIntersectionType(type)) {
const types = type.types.map(t => getTypeString(t)).join(' & ');
return types;
}
// Literal types
if (t.isTSLiteralType(type)) {
if (t.isStringLiteral(type.literal)) {
return `'${type.literal.value}'`;
}
if (t.isNumericLiteral(type.literal)) {
return type.literal.value.toString();
}
if (t.isBooleanLiteral(type.literal)) {
return type.literal.value.toString();
}
}
// Object types
if (t.isTSTypeLiteral(type)) {
if (type.members.length === 0) {
return '{}';
}
// For complex objects, just return a simplified representation
return '{ ... }';
}
// Function types
if (t.isTSFunctionType(type)) {
const params = type.parameters
.map(param => {
if (t.isIdentifier(param) && param.typeAnnotation) {
const paramType = t.isTSTypeAnnotation(param.typeAnnotation)
? getTypeString(param.typeAnnotation.typeAnnotation)
: 'unknown';
return `${param.name}: ${paramType}`;
}
return 'param: unknown';
})
.join(', ');
const returnType = type.typeAnnotation
? getTypeString(type.typeAnnotation.typeAnnotation)
: 'unknown';
return `(${params}) => ${returnType}`;
}
// Tuple types
if (t.isTSTupleType(type)) {
const elements = type.elementTypes
.map(el => {
if (t.isTSNamedTupleMember(el)) {
return `${el.label.name}: ${getTypeString(el.elementType)}`;
}
return getTypeString(el);
})
.join(', ');
return `[${elements}]`;
}
// Conditional types and other complex types
if (t.isTSConditionalType(type)) {
return 'ConditionalType';
}
if (t.isTSMappedType(type)) {
return 'MappedType';
}
return 'unknown';
}
/**
* Helper function to extract qualified type names (e.g., React.Component)
*/
function getQualifiedTypeName(qualifiedName) {
if (t.isIdentifier(qualifiedName.left) &&
t.isIdentifier(qualifiedName.right)) {
return `${qualifiedName.left.name}.${qualifiedName.right.name}`;
}
if (t.isTSQualifiedName(qualifiedName.left) &&
t.isIdentifier(qualifiedName.right)) {
return `${getQualifiedTypeName(qualifiedName.left)}.${qualifiedName.right.name}`;
}
return 'QualifiedType';
}
function parseReturnType(node) {
if (node.returnType && t.isTSTypeAnnotation(node.returnType)) {
return getTypeString(node.returnType.typeAnnotation);
}
return undefined;
}
function parseArrowReturnType(node) {
if (node.returnType && t.isTSTypeAnnotation(node.returnType)) {
return getTypeString(node.returnType.typeAnnotation);
}
return undefined;
}
function generateSignature(name, params, returnType, isDefault = false) {
const paramStr = params
.map(p => {
const optional = p.optional ? '?' : '';
const type = p.type ? `: ${p.type}` : '';
return `${p.name}${optional}${type}`;
})
.join(', ');
const returnStr = returnType ? `: ${returnType}` : '';
const exportKeyword = isDefault
? 'export default function'
: 'export function';
const funcName = isDefault ? '' : ` ${name}`;
return `${exportKeyword}${funcName}(${paramStr})${returnStr}`;
}
function parseClassDeclaration(node, path, isDefault = false) {
if (!node.id && !isDefault) {
return null;
}
const name = isDefault ? 'default' : node.id?.name || 'anonymous';
const methods = parseClassMethods(node.body.body);
const jsDoc = extractJSDoc(path);
return {
name,
methods,
jsDoc,
};
}
function parseClassMethods(body) {
const methods = [];
body.forEach(member => {
if (t.isClassMethod(member) && member.kind === 'method') {
const method = parseClassMethod(member);
if (method) {
methods.push(method);
}
}
});
return methods;
}
function parseClassMethod(node) {
if (!t.isIdentifier(node.key)) {
return null;
}
const name = node.key.name;
const isPrivate = node.accessibility === 'private' || name.startsWith('_');
const params = parseParameters(node.params);
const returnType = parseMethodReturnType(node);
const signature = generateMethodSignature(name, params, returnType);
return {
name,
signature,
params,
returnType,
isPrivate,
jsDoc: undefined, // JSDoc for methods will be extracted separately if needed
};
}
function parseMethodReturnType(node) {
if (node.returnType && t.isTSTypeAnnotation(node.returnType)) {
return getTypeString(node.returnType.typeAnnotation);
}
return undefined;
}
function generateMethodSignature(name, params, returnType) {
const paramStr = params
.map(p => {
const optional = p.optional ? '?' : '';
const type = p.type ? `: ${p.type}` : '';
return `${p.name}${optional}${type}`;
})
.join(', ');
const returnStr = returnType ? `: ${returnType}` : '';
return `${name}(${paramStr})${returnStr}`;
}
function extractJSDoc(path) {
// For ExportNamedDeclaration, check the declaration's leading comments first
if (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
path.node.declaration &&
// eslint-disable-next-line @typescript-eslint/no-explicit-any
path.node.declaration.leadingComments) {
// Get the last JSDoc comment (the one immediately before the declaration)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const jsDocComments = path.node.declaration.leadingComments.filter((comment) => comment.type === 'CommentBlock' && comment.value.startsWith('*'));
if (jsDocComments.length > 0) {
const lastJsDoc = jsDocComments[jsDocComments.length - 1];
// Clean up the JSDoc value - remove leading * if present
const cleanValue = lastJsDoc.value.startsWith('*')
? lastJsDoc.value.substring(1)
: lastJsDoc.value;
return `/**${cleanValue}*/`;
}
}
// If no declaration comments, check the export node itself
if (path.node.leadingComments) {
const jsDocComments = path.node.leadingComments.filter((comment) => comment.type === 'CommentBlock' && comment.value.startsWith('*'));
if (jsDocComments.length > 0) {
const lastJsDoc = jsDocComments[jsDocComments.length - 1];
// Clean up the JSDoc value - remove leading * if present
const cleanValue = lastJsDoc.value.startsWith('*')
? lastJsDoc.value.substring(1)
: lastJsDoc.value;
return `/**${cleanValue}*/`;
}
}
return undefined;
}
function generateExportMetadata(functions, classes, ast) {
let hasDefaultExport = false;
let defaultExportType;
let defaultExportName;
// Check for default exports in functions
const defaultFunction = functions.find(f => f.isDefault);
if (defaultFunction) {
hasDefaultExport = true;
defaultExportType = 'function';
defaultExportName =
defaultFunction.name === 'default' ? 'function' : defaultFunction.name;
}
// Check for default exports in classes
const defaultClass = classes.find(c => c.name === 'default');
if (defaultClass) {
hasDefaultExport = true;
defaultExportType = 'class';
defaultExportName = 'class';
}
// If no default found in our parsed data, traverse AST to check for other default exports
if (!hasDefaultExport) {
(0, traverse_1.default)(ast, {
ExportDefaultDeclaration(path) {
hasDefaultExport = true;
if (t.isFunctionDeclaration(path.node.declaration)) {
defaultExportType = 'function';
defaultExportName = path.node.declaration.id?.name || 'function';
}
else if (t.isClassDeclaration(path.node.declaration)) {
defaultExportType = 'class';
defaultExportName = path.node.declaration.id?.name || 'class';
}
},
});
}
return {
totalFunctions: functions.length,
totalClasses: classes.length,
hasDefaultExport,
defaultExportType,
defaultExportName,
};
}
//# sourceMappingURL=parser.js.map