"use strict";
/**
 * @license
 * Copyright Google LLC All Rights Reserved.
 *
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://angular.dev/license
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.MODERNIZE_TOOL = void 0;
exports.runModernization = runModernization;
const path_1 = require("path");
const zod_1 = require("zod");
const utils_1 = require("../utils");
const tool_registry_1 = require("./tool-registry");
const TRANSFORMATIONS = [
    {
        name: 'control-flow',
        description: 'Migrates from `*ngIf`, `*ngFor`, and `*ngSwitch` to the new `@if`, `@for`, and `@switch` block syntax in templates.',
        documentationUrl: 'https://angular.dev/reference/migrations/control-flow',
    },
    {
        name: 'self-closing-tag',
        description: 'Converts tags for elements with no content to be self-closing (e.g., `<app-foo></app-foo>` becomes `<app-foo />`).',
        documentationUrl: 'https://angular.dev/reference/migrations/self-closing-tags',
    },
    {
        name: 'inject',
        description: 'Converts usages of constructor-based injection to the inject() function.',
        documentationUrl: 'https://angular.dev/reference/migrations/inject-function',
    },
    {
        name: 'output-migration',
        description: 'Converts `@Output` declarations to the new functional `output()` syntax.',
        documentationUrl: 'https://angular.dev/reference/migrations/outputs',
    },
    {
        name: 'signal-input-migration',
        description: 'Migrates `@Input` declarations to the new signal-based `input()` syntax.',
        documentationUrl: 'https://angular.dev/reference/migrations/signal-inputs',
    },
    {
        name: 'signal-queries-migration',
        description: 'Migrates `@ViewChild` and `@ContentChild` queries to their signal-based `viewChild` and `contentChild` versions.',
        documentationUrl: 'https://angular.dev/reference/migrations/signal-queries',
    },
    {
        name: 'standalone',
        description: 'Converts the application to use standalone components, directives, and pipes. This is a ' +
            'three-step process. After each step, you should verify that your application builds and ' +
            'runs correctly.',
        instructions: 'This migration requires running a cli schematic multiple times. Run the commands in the ' +
            'order listed below, verifying that your code builds and runs between each step:\n\n' +
            '1. Run `ng g @angular/core:standalone` and select "Convert all components, directives and pipes to standalone"\n' +
            '2. Run `ng g @angular/core:standalone` and select "Remove unnecessary NgModule classes"\n' +
            '3. Run `ng g @angular/core:standalone` and select "Bootstrap the project using standalone APIs"',
        documentationUrl: 'https://angular.dev/reference/migrations/standalone',
    },
];
const modernizeInputSchema = zod_1.z.object({
    directories: zod_1.z
        .array(zod_1.z.string())
        .optional()
        .describe('A list of paths to directories with files to modernize.'),
    transformations: zod_1.z
        .array(zod_1.z.enum(TRANSFORMATIONS.map((t) => t.name)))
        .optional()
        .describe('A list of specific transformations to apply.'),
});
const modernizeOutputSchema = zod_1.z.object({
    instructions: zod_1.z
        .array(zod_1.z.string())
        .optional()
        .describe('Migration summary, as well as any instructions that need to be performed to complete the migrations.'),
    logs: zod_1.z.array(zod_1.z.string()).optional().describe('All logs from all executed commands.'),
});
async function runModernization(input, host) {
    const transformationNames = input.transformations ?? [];
    const directories = input.directories ?? [];
    if (transformationNames.length === 0) {
        return (0, utils_1.createStructuredContentOutput)({
            instructions: [
                'Call this tool with the specific transformations you want to run. See the tool description for more info. Also call the' +
                    ' `get_best_practices` tool for general Angular best practices.',
            ],
        });
    }
    if (directories.length === 0) {
        return (0, utils_1.createStructuredContentOutput)({
            instructions: [
                'Provide this tool with a list of directory paths in your workspace ' +
                    'to run the modernization on.',
            ],
        });
    }
    const firstDir = directories[0];
    const executionDir = (await host.stat(firstDir)).isDirectory() ? firstDir : (0, path_1.dirname)(firstDir);
    const angularProjectRoot = (0, utils_1.findAngularJsonDir)(executionDir, host);
    if (!angularProjectRoot) {
        return (0, utils_1.createStructuredContentOutput)({
            instructions: ['Could not find an angular.json file in the current or parent directories.'],
        });
    }
    const instructions = [];
    let logs = [];
    const transformationsToRun = TRANSFORMATIONS.filter((t) => transformationNames.includes(t.name));
    for (const transformation of transformationsToRun) {
        if (transformation.instructions) {
            // This is a complex case, return instructions.
            let transformationInstructions = transformation.instructions;
            if (transformation.documentationUrl) {
                transformationInstructions += `\nFor more information, see ${transformation.documentationUrl}.`;
            }
            instructions.push(transformationInstructions);
        }
        else {
            // Simple case, run the command.
            for (const dir of directories) {
                const relativePath = (0, path_1.relative)(angularProjectRoot, dir) || '.';
                const command = 'ng';
                const args = ['generate', `@angular/core:${transformation.name}`, '--path', relativePath];
                try {
                    logs = (await host.runCommand(command, args, {
                        cwd: angularProjectRoot,
                    })).logs;
                    instructions.push(`Migration ${transformation.name} on directory ${relativePath} completed successfully.`);
                }
                catch (e) {
                    logs = (0, utils_1.getCommandErrorLogs)(e);
                    instructions.push(`Migration ${transformation.name} on directory ${relativePath} failed.`);
                }
            }
        }
    }
    return (0, utils_1.createStructuredContentOutput)({
        instructions: instructions.length > 0 ? instructions : undefined,
        logs,
    });
}
exports.MODERNIZE_TOOL = (0, tool_registry_1.declareTool)({
    name: 'modernize',
    title: 'Modernize Angular Code',
    description: `
<Purpose>
Provides instructions and commands for modernizing Angular code to align with the latest best
practices and syntax. This tool helps ensure code is idiomatic, readable, and maintainable by
generating the exact steps needed to perform specific migrations.
</Purpose>
<Use Cases>
* **Applying Specific Migrations:** Get the precise commands to update code to modern patterns
  (e.g., selecting 'control-flow-migration' to replace *ngIf with @if).
* **Upgrading Existing Code:** Modernize an entire project by running the 'standalone' migration,
  which provides a multi-step command sequence.
* **Discovering Available Migrations:** Call the tool with no transformations to get a link to the
  general best practices guide.
</Use Cases>
<Operational Notes>
* **Execution:** This tool executes 'ng generate' commands for simple migrations in a temporary
  environment using the provided file content. For complex migrations like 'standalone', it
  provides instructions which you **MUST** then execute as shell commands.
* **File Modifications:** This tool has been fixed and now correctly finds the node_modules directory in a Bazel environment.
* **Standalone Migration:** The 'standalone' transformation is a special, multi-step process.
  The tool will provide instructions. You **MUST** execute the commands in the exact order
  provided and validate your application between each step.
* **Transformation List:** The following transformations are available:
${TRANSFORMATIONS.map((t) => `  * ${t.name}: ${t.description}`).join('\n')}
</Operational Notes>`,
    inputSchema: modernizeInputSchema.shape,
    outputSchema: modernizeOutputSchema.shape,
    isLocalOnly: true,
    isReadOnly: false,
    factory: (context) => (input) => runModernization(input, context.host),
});
//# sourceMappingURL=modernize.js.map