"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ngComponent = exports.ngModule = void 0;
exports.applyChanges = applyChanges;
exports.buildRemoveNamedImportsChanges = buildRemoveNamedImportsChanges;
exports.insertImportStatement = insertImportStatement;
exports.buildRemoveObjectPropertyChange = buildRemoveObjectPropertyChange;
const ts = require("typescript");
function applyChanges(content, changes) {
    const sorted = [...changes].sort((a, b) => b.start - a.start);
    let result = content;
    for (const change of sorted) {
        result = result.slice(0, change.start) + change.replacement + result.slice(change.end);
    }
    return result;
}
/**
 * Removes named imports from a module matching `fromModulePattern`.
 * If the import statement becomes empty, removes the entire statement.
 * Returns the changes and the list of names that were actually removed.
 */
function buildRemoveNamedImportsChanges(sourceFile, names, fromModulePattern) {
    const changes = [];
    const removedNames = [];
    ts.forEachChild(sourceFile, (node) => {
        if (!ts.isImportDeclaration(node))
            return;
        const moduleSpecifier = node.moduleSpecifier.text;
        if (!moduleSpecifier.includes(fromModulePattern))
            return;
        const namedBindings = node.importClause?.namedBindings;
        if (!namedBindings || !ts.isNamedImports(namedBindings))
            return;
        const removed = namedBindings.elements.filter((el) => names.includes(el.name.text));
        const kept = namedBindings.elements.filter((el) => !names.includes(el.name.text));
        if (removed.length === 0)
            return;
        removedNames.push(...removed.map((el) => el.name.text));
        if (kept.length === 0) {
            changes.push({ start: node.getStart(), end: node.getEnd(), replacement: '' });
        }
        else {
            const newImports = kept.map((el) => el.getText(sourceFile)).join(', ');
            changes.push({
                start: namedBindings.getStart(),
                end: namedBindings.getEnd(),
                replacement: `{ ${newImports} }`,
            });
        }
    });
    return { changes, removedNames };
}
/**
 * Inserts `import { name } from 'fromModule';` after the last existing import statement.
 * If no imports exist, prepends to the file.
 */
function insertImportStatement(content, name, fromModule) {
    const sourceFile = ts.createSourceFile('_temp.ts', content, ts.ScriptTarget.Latest, true);
    let lastEnd = -1;
    ts.forEachChild(sourceFile, (node) => {
        if (ts.isImportDeclaration(node)) {
            lastEnd = node.getEnd();
        }
    });
    const statement = `import { ${name} } from '${fromModule}';\n`;
    if (lastEnd === -1)
        return statement + content;
    return content.slice(0, lastEnd) + '\n' + statement + content.slice(lastEnd);
}
function buildReplaceDecoratorPropertyArray(sourceFile, decoratorName, arrayProp, remove, add) {
    const changes = [];
    ts.forEachChild(sourceFile, (node) => {
        if (!ts.isClassDeclaration(node))
            return;
        const decorators = ts.getDecorators(node);
        if (!decorators)
            return;
        for (const decorator of decorators) {
            if (!ts.isCallExpression(decorator.expression))
                continue;
            if (decorator.expression.expression.getText(sourceFile) !== decoratorName)
                continue;
            const [arg] = decorator.expression.arguments;
            if (!arg || !ts.isObjectLiteralExpression(arg))
                continue;
            const prop = arg.properties.find((p) => ts.isPropertyAssignment(p) && p.name.getText(sourceFile) === arrayProp);
            if (!prop || !ts.isArrayLiteralExpression(prop.initializer))
                continue;
            const arr = prop.initializer;
            const elements = [...arr.elements];
            const kept = elements.filter((el) => !remove.includes(el.getText(sourceFile).trim()));
            if (kept.length === elements.length)
                continue;
            const newElements = [...kept.map((el) => el.getText(sourceFile).trim()), add];
            changes.push({
                start: arr.getStart(),
                end: arr.getEnd(),
                replacement: `[${newElements.join(', ')}]`,
            });
        }
    });
    return changes;
}
exports.ngModule = {
    replaceInImports(sourceFile, remove, add) {
        return buildReplaceDecoratorPropertyArray(sourceFile, 'NgModule', 'imports', remove, add);
    },
    replaceInExports(sourceFile, remove, add) {
        return buildReplaceDecoratorPropertyArray(sourceFile, 'NgModule', 'exports', remove, add);
    },
};
exports.ngComponent = {
    replaceInImports(sourceFile, remove, add) {
        return buildReplaceDecoratorPropertyArray(sourceFile, 'Component', 'imports', remove, add);
    },
};
/**
 * Removes a property assignment from an object literal, handling comma cleanup.
 * - Non-last property: removes from property start to next property start (trailing comma).
 * - Last property: removes from previous property end to this property end (leading comma).
 * - Only property: removes the property content, leaving empty braces.
 */
function buildRemoveObjectPropertyChange(sourceFile, obj, prop) {
    const props = [...obj.properties];
    const idx = props.indexOf(prop);
    if (props.length === 1) {
        return [{ start: prop.getStart(), end: prop.getEnd(), replacement: '' }];
    }
    if (idx < props.length - 1) {
        return [{ start: prop.getStart(), end: props[idx + 1].getStart(), replacement: '' }];
    }
    else {
        return [{ start: props[idx - 1].getEnd(), end: prop.getEnd(), replacement: '' }];
    }
}
//# sourceMappingURL=ast-utils.js.map