"use strict";
/**
 * Use of this source code is governed by an MIT-style license that can be
 * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
 */
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;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.DateAdapterMigration = void 0;
const schematics_1 = require("@angular/cdk/schematics");
const ng_ast_utils_1 = require("@schematics/angular/utility/ng-ast-utils");
const app_config_1 = require("@schematics/angular/utility/standalone/app_config");
const util_1 = require("@schematics/angular/utility/standalone/util");
const ts = __importStar(require("typescript"));
/**
 * Migration that adds `provideNzDateFnsAdapter()` to root providers.
 *
 * Starting from v22, date components require an explicit `NzDateAdapter` provider.
 * This migration makes the previous default (date-fns) explicit in projects where it can do so safely.
 * Projects that already configure a date adapter are left unchanged.
 */
class DateAdapterMigration extends schematics_1.DevkitMigration {
    constructor() {
        super(...arguments);
        /** Provider APIs that indicate the project already has an explicit date adapter choice. */
        this.dateAdapterProviderPattern = /^(provideNzDateAdapter|provideNzDateFnsAdapter|provideNzNativeDateAdapter)$/;
        /** Always enabled; the migration is scoped by project target in postAnalysis. */
        this.enabled = true;
    }
    postAnalysis() {
        if (this.context.isTestTarget) {
            return;
        }
        const mainFile = (0, schematics_1.getProjectMainFile)(this.context.project);
        if (this.addProviderToStandaloneApp(mainFile)) {
            return;
        }
        this.addProviderToNgModuleApp(mainFile);
    }
    addProviderToStandaloneApp(mainFile) {
        try {
            const bootstrapCall = (0, util_1.findBootstrapApplicationCall)(this.context.tree, mainFile);
            const appConfig = (0, app_config_1.findAppConfig)(bootstrapCall, this.context.tree, mainFile);
            if (appConfig) {
                const appConfigSource = this.getSourceFile(appConfig.filePath);
                if (this.hasDateAdapterProvider(appConfigSource)) {
                    return true;
                }
                const providersLiteral = (0, util_1.findProvidersLiteral)(appConfig.node);
                const filePath = this.fileSystem.resolve(appConfig.filePath);
                this.insertProviderImport(appConfigSource, filePath);
                if (providersLiteral) {
                    this.addProviderToArray(providersLiteral, filePath);
                }
                else {
                    this.addProvidersProperty(appConfig.node, filePath);
                }
                return true;
            }
            const mainSource = this.getSourceFile(mainFile);
            if (this.hasDateAdapterProvider(mainSource)) {
                return true;
            }
            const filePath = this.fileSystem.resolve(mainFile);
            this.insertProviderImport(mainSource, filePath);
            this.addProviderToBootstrapCall(bootstrapCall, filePath);
            return true;
        }
        catch (_a) {
            return false;
        }
    }
    addProviderToBootstrapCall(bootstrapCall, filePath) {
        const providerConfig = `{\n  providers: [provideNzDateFnsAdapter()]\n}`;
        if (bootstrapCall.arguments.length === 1) {
            this.fileSystem.edit(filePath).insertRight(bootstrapCall.arguments[0].getEnd(), `, ${providerConfig}`);
            return;
        }
        const secondArgument = bootstrapCall.arguments[1];
        if ((0, util_1.isMergeAppConfigCall)(secondArgument)) {
            const separator = secondArgument.arguments.length === 0 ? '' : ', ';
            this.fileSystem.edit(filePath).insertRight(secondArgument.getEnd() - 1, `${separator}${providerConfig}`);
            return;
        }
        this.failures.push({
            filePath,
            message: 'Could not statically analyze bootstrapApplication config to add provideNzDateFnsAdapter().'
        });
    }
    addProviderToNgModuleApp(mainFile) {
        let appModulePath;
        try {
            appModulePath = (0, ng_ast_utils_1.getAppModulePath)(this.context.tree, mainFile);
        }
        catch (_a) {
            this.createFailureAtMainFile(mainFile, 'Could not find root providers to add provideNzDateFnsAdapter(). Please add it manually.');
            return;
        }
        const sourceFile = this.getSourceFile(appModulePath);
        if (this.hasDateAdapterProvider(sourceFile)) {
            return;
        }
        const ngModuleMetadata = this.findNgModuleMetadata(sourceFile);
        if (!ngModuleMetadata) {
            this.createFailureAtMainFile(appModulePath, 'Could not find NgModule metadata to add provideNzDateFnsAdapter(). Please add it manually.');
            return;
        }
        const filePath = this.fileSystem.resolve(appModulePath);
        const providersLiteral = this.findProvidersProperty(ngModuleMetadata);
        this.insertProviderImport(sourceFile, filePath);
        if (providersLiteral) {
            this.addProviderToArray(providersLiteral, filePath);
        }
        else {
            this.addProvidersProperty(ngModuleMetadata, filePath);
        }
    }
    hasDateAdapterProvider(sourceFile) {
        let hasProvider = false;
        const visit = (node) => {
            if (hasProvider) {
                return;
            }
            if (ts.isCallExpression(node)) {
                const expression = node.expression;
                if (ts.isIdentifier(expression) && this.dateAdapterProviderPattern.test(expression.text)) {
                    hasProvider = true;
                    return;
                }
            }
            if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name) && node.name.text === 'provide') {
                const initializer = node.initializer;
                if (ts.isIdentifier(initializer) && initializer.text === 'NzDateAdapter') {
                    hasProvider = true;
                    return;
                }
            }
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
        return hasProvider;
    }
    findNgModuleMetadata(sourceFile) {
        let metadata = null;
        const visit = (node) => {
            if (metadata) {
                return;
            }
            if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) {
                const expression = node.expression.expression;
                const args = node.expression.arguments;
                if (ts.isIdentifier(expression) &&
                    expression.text === 'NgModule' &&
                    args.length > 0 &&
                    ts.isObjectLiteralExpression(args[0])) {
                    metadata = args[0];
                    return;
                }
            }
            ts.forEachChild(node, visit);
        };
        visit(sourceFile);
        return metadata;
    }
    findProvidersProperty(metadata) {
        for (const property of metadata.properties) {
            if (ts.isPropertyAssignment(property) &&
                ts.isIdentifier(property.name) &&
                property.name.text === 'providers' &&
                ts.isArrayLiteralExpression(property.initializer)) {
                return property.initializer;
            }
        }
        return null;
    }
    addProvidersProperty(metadata, filePath) {
        const providerProperty = 'providers: [provideNzDateFnsAdapter()]';
        const properties = metadata.properties;
        if (properties.length === 0) {
            this.fileSystem.edit(filePath).insertRight(metadata.getStart() + 1, providerProperty);
            return;
        }
        const lastProperty = properties[properties.length - 1];
        this.fileSystem.edit(filePath).insertRight(lastProperty.getEnd(), `, ${providerProperty}`);
    }
    /** Add provider to array */
    addProviderToArray(arrayNode, filePath) {
        const elements = arrayNode.elements;
        for (const element of elements) {
            if (ts.isCallExpression(element)) {
                const expr = element.expression;
                if (ts.isIdentifier(expr) && expr.getText() === 'provideNzDateFnsAdapter') {
                    return;
                }
            }
        }
        const providerCall = 'provideNzDateFnsAdapter()';
        if (elements.length === 0) {
            this.fileSystem.edit(filePath).insertRight(arrayNode.getStart() + 1, providerCall);
        }
        else {
            const lastElement = elements[elements.length - 1];
            this.fileSystem.edit(filePath).insertRight(lastElement.getEnd(), `, ${providerCall}`);
        }
    }
    insertProviderImport(sourceFile, filePath) {
        if (this.hasNamedImport(sourceFile, 'provideNzDateFnsAdapter', 'ng-zorro-antd/core/time')) {
            return;
        }
        let lastImport = null;
        ts.forEachChild(sourceFile, node => {
            if (ts.isImportDeclaration(node)) {
                lastImport = node;
            }
        });
        const importToAdd = `\nimport { provideNzDateFnsAdapter } from 'ng-zorro-antd/core/time';\n`;
        if (lastImport) {
            this.fileSystem.edit(filePath).insertRight(lastImport.getEnd(), importToAdd);
        }
        else {
            this.fileSystem.edit(filePath).insertRight(0, `${importToAdd}\n`);
        }
    }
    hasNamedImport(sourceFile, symbolName, moduleName) {
        var _a;
        for (const statement of sourceFile.statements) {
            if (!ts.isImportDeclaration(statement) ||
                !ts.isStringLiteralLike(statement.moduleSpecifier) ||
                statement.moduleSpecifier.text !== moduleName ||
                !((_a = statement.importClause) === null || _a === void 0 ? void 0 : _a.namedBindings) ||
                !ts.isNamedImports(statement.importClause.namedBindings)) {
                continue;
            }
            if (statement.importClause.namedBindings.elements.some(element => element.name.text === symbolName)) {
                return true;
            }
        }
        return false;
    }
    getSourceFile(filePath) {
        const sourceText = this.context.tree.readText(filePath);
        return ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true);
    }
    createFailureAtMainFile(filePath, message) {
        this.failures.push({
            filePath: this.fileSystem.resolve(filePath),
            message
        });
    }
}
exports.DateAdapterMigration = DateAdapterMigration;
//# sourceMappingURL=date-adapter.js.map