"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readTreeFile = readTreeFile;
exports.loadSourceFile = loadSourceFile;
exports.saveSourceFile = saveSourceFile;
exports.throwIfNotFound = throwIfNotFound;
exports.propertyExists = propertyExists;
exports.findFirstClass = findFirstClass;
exports.findFirstConstructor = findFirstConstructor;
exports.findSuperCall = findSuperCall;
exports.getObjectLiteralFromFirstArg = getObjectLiteralFromFirstArg;
const ts_morph_1 = require("ts-morph");
/* -------------------------------------------
 * Utilities
 * -----------------------------------------*/
/**
 * Reads the content of a file from the Nx Tree.
 * Throws an error if the file cannot be read.
 */
function readTreeFile(tree, filePath) {
    const content = tree.read(filePath, 'utf-8');
    if (!content) {
        throw new Error(`Could not read file at ${filePath}`);
    }
    return content;
}
/**
 * Loads a file from the Nx Tree into a ts-morph Project.
 * Uses `readTreeFile` to get content.
 */
function loadSourceFile(tree, filePath, project) {
    const content = readTreeFile(tree, filePath);
    return project.createSourceFile(filePath, content, { overwrite: true });
}
/**
 * Saves the updated source file content back to the Nx Tree.
 */
function saveSourceFile(tree, filePath, sourceFileContent) {
    tree.write(filePath, sourceFileContent);
    console.log(`✅ Updated ${filePath}`);
}
/**
 * Throws an error if the provided item is null or undefined.
 * Returns the item with a non-null/undefined type assertion.
 */
function throwIfNotFound(item, message) {
    if (item === null || item === undefined) {
        throw new Error(message);
    }
    return item;
}
/**
 * Checks if a property exists in an ObjectLiteralExpression, handling quoted keys.
 */
function propertyExists(objectLiteral, propName) {
    return objectLiteral.getProperties().some((prop) => {
        if (prop.getKind() === ts_morph_1.SyntaxKind.PropertyAssignment) {
            const assignment = prop;
            // Get the text of the property name node, and remove any quotes
            const name = assignment.getNameNode().getText().replace(/['"]/g, '');
            return name === propName;
        }
        return false;
    });
}
/**
 * Finds the first ClassDeclaration in a SourceFile.
 */
function findFirstClass(sourceFile) {
    const clazz = sourceFile.getClasses()[0];
    return throwIfNotFound(clazz, `No class found in ${sourceFile.getFilePath()}`);
}
/**
 * Finds the first ConstructorDeclaration in a ClassDeclaration.
 */
function findFirstConstructor(clazz) {
    const constructor = clazz.getConstructors()[0];
    return throwIfNotFound(constructor, `No constructor found in class ${clazz.getName() || ''}`);
}
/**
 * Finds the `super()` CallExpression within a ConstructorDeclaration.
 */
function findSuperCall(constructor) {
    const superCall = constructor
        .getDescendantsOfKind(ts_morph_1.SyntaxKind.CallExpression)
        .find((call) => call.getExpression().getKind() === ts_morph_1.SyntaxKind.SuperKeyword);
    return throwIfNotFound(superCall, `Could not find super() call in constructor.`);
}
/**
 * Gets the first argument of a CallExpression, asserting it's an ObjectLiteralExpression.
 */
function getObjectLiteralFromFirstArg(callExpression) {
    const args = callExpression.getArguments();
    throwIfNotFound(args.length, `Call expression has no arguments.`);
    const objectLiteral = args[0];
    throwIfNotFound(objectLiteral &&
        objectLiteral.getKind() === ts_morph_1.SyntaxKind.ObjectLiteralExpression, `First argument is not an object literal.`);
    return objectLiteral;
}
