"use strict";
/*
 * Copyright (c) 2020, salesforce.com, inc.
 * All rights reserved.
 * Licensed under the BSD 3-Clause license.
 * For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseGenerator = void 0;
exports.setCustomTemplatesRootPathOrGitRepo = setCustomTemplatesRootPathOrGitRepo;
exports.getDefaultApiVersion = getDefaultApiVersion;
const tslib_1 = require("tslib");
const nodeFs = require("fs");
const path = require("path");
const ejs_1 = require("ejs");
const i18n_1 = require("../i18n");
const constants_1 = require("../utils/constants");
function setCustomTemplatesRootPathOrGitRepo(pathOrRepoUri_1) {
    return tslib_1.__awaiter(this, arguments, void 0, function* (pathOrRepoUri, forceLoadingRemoteRepo = false, fs = nodeFs) {
        if (pathOrRepoUri === undefined) {
            return;
        }
        try {
            // if pathOrRepoUri is valid url, load the repo
            const url = new URL(pathOrRepoUri);
            if (process.env.ESBUILD_PLATFORM !== 'web' && url) {
                const { loadCustomTemplatesGitRepo } = yield Promise.resolve().then(() => require('../service/gitRepoUtils'));
                return yield loadCustomTemplatesGitRepo(url, forceLoadingRemoteRepo, fs);
            }
        }
        catch (error) {
            const err = error;
            if (err.code !== 'ERR_INVALID_URL') {
                throw error;
            }
            const localTemplatesPath = pathOrRepoUri;
            if (fs.existsSync(localTemplatesPath)) {
                return localTemplatesPath;
            }
            else {
                throw new Error(i18n_1.nls.localize('localCustomTemplateDoNotExist', localTemplatesPath));
            }
        }
    });
}
/**
 * Look up package version of @salesforce/templates package to supply a default API version
 */
function getDefaultApiVersion() {
    return constants_1.DEFAULT_API_VERSION;
}
class NotYeoman {
    constructor(context, cwd) {
        var _a, _b;
        this.changes = {
            created: [],
            conflicted: [],
            identical: [],
            forced: [],
        };
        this._fs = (_a = context === null || context === void 0 ? void 0 : context.fs) !== null && _a !== void 0 ? _a : nodeFs;
        this._cwd = cwd !== null && cwd !== void 0 ? cwd : process.cwd();
        const defaultTemplatesRoot = (_b = context === null || context === void 0 ? void 0 : context.templatesRootPath) !== null && _b !== void 0 ? _b : constants_1.dirnameTemplatesDefault;
        this._sourceRoot = this.sourceRoot(defaultTemplatesRoot);
        this._destinationRoot = this.destinationRoot(this._cwd);
    }
    destinationPath(...dest) {
        let filepath = path.join(...dest);
        if (!path.isAbsolute(filepath)) {
            filepath = path.join(this.destinationRoot(), filepath);
        }
        return filepath;
    }
    destinationRoot(rootPath) {
        if (typeof rootPath === 'string') {
            this._destinationRoot = path.resolve(rootPath);
            if (!this._fs.existsSync(this._destinationRoot)) {
                this._fs.mkdirSync(this._destinationRoot, { recursive: true });
            }
        }
        return this._destinationRoot || this._cwd;
    }
    sourceRoot(rootPath) {
        if (rootPath) {
            this._sourceRoot = path.resolve(rootPath);
        }
        return this._sourceRoot;
    }
    templatePath(...dest) {
        let filepath = path.join(...dest);
        if (!path.isAbsolute(filepath)) {
            filepath = path.join(this.sourceRoot(), filepath);
        }
        return filepath;
    }
    render(source, destination, data) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            const template = yield this._fs.promises.readFile(source, 'utf8');
            const rendered = (0, ejs_1.render)(template, data !== null && data !== void 0 ? data : {});
            if (rendered) {
                const relativePath = path.relative(this._cwd, destination);
                const existing = yield this._fs.promises
                    .readFile(destination, 'utf8')
                    .catch(() => null);
                if (existing) {
                    if (rendered.trim() === existing.trim()) {
                        this.register('identical', relativePath);
                        return;
                    }
                    else {
                        this.register('conflicted', relativePath);
                        this.register('forced', relativePath);
                    }
                }
                else {
                    this.register('created', relativePath);
                }
                const dir = path.dirname(destination);
                yield this._fs.promises.mkdir(dir, { recursive: true });
                yield this._fs.promises.writeFile(destination, rendered);
            }
        });
    }
    register(verb, file) {
        this.changes[verb].push(file);
    }
}
class BaseGenerator extends NotYeoman {
    /**
     * The constructor for the SfGenerator.
     *
     * @param options SfGenerator specific options.
     * @param context optional generator context for fs and template path injection
     */
    constructor(options, context, cwd) {
        var _a, _b;
        super(context, cwd);
        this.options = options;
        this.templatesRootPath = context === null || context === void 0 ? void 0 : context.templatesRootPath;
        this.apiversion = (_a = options.apiversion) !== null && _a !== void 0 ? _a : getDefaultApiVersion();
        this.outputdir = (_b = options.outputdir) !== null && _b !== void 0 ? _b : this._cwd;
        this.validateOptions();
    }
    /**
     * Set source root to built-in templates or custom templates root if available.
     * @param partialPath the relative path from the templates folder to templates root folder.
     */
    sourceRootWithPartialPath(partialPath) {
        var _a, _b;
        this.builtInTemplatesRootPath = path.join((_b = (_a = this.templatesRootPath) !== null && _a !== void 0 ? _a : constants_1.dirnameTemplatesDefault) !== null && _b !== void 0 ? _b : '', partialPath);
        // set generator source directory to custom templates root if available
        if (!this.customTemplatesRootPath) {
            this.sourceRoot(path.join(this.builtInTemplatesRootPath));
        }
        else {
            if (this._fs.existsSync(path.join(this.customTemplatesRootPath, partialPath))) {
                this.sourceRoot(path.join(this.customTemplatesRootPath, partialPath));
            }
        }
    }
    templatePath(...paths) {
        // The template paths are relative to the generator's source root
        // If we have set a custom template root, the source root should have already been set.
        // Otherwise we'll fallback to the built-in templates
        const customPath = super.templatePath(...paths);
        if (this._fs.existsSync(customPath)) {
            return customPath;
        }
        else {
            // files that are builtin and not in the custom template folder
            return super.templatePath(path.join(this.builtInTemplatesRootPath, ...paths));
        }
    }
    run(opts) {
        return tslib_1.__awaiter(this, void 0, void 0, function* () {
            var _a, _b, _c, _d, _e;
            const cwd = (_a = opts === null || opts === void 0 ? void 0 : opts.cwd) !== null && _a !== void 0 ? _a : this._cwd;
            this.customTemplatesRootPath = yield setCustomTemplatesRootPathOrGitRepo(opts === null || opts === void 0 ? void 0 : opts.customTemplatesRootPathOrGitRepo, false, this._fs);
            yield this.generate();
            const created = [...this.changes.created, ...this.changes.forced];
            const outputDir = path.resolve(cwd, this.outputdir);
            const rawOutput = i18n_1.nls.localize('RawOutput', [
                outputDir,
                [
                    ...((_b = this.changes.created) !== null && _b !== void 0 ? _b : []).map((file) => `  create ${file}`),
                    ...((_c = this.changes.identical) !== null && _c !== void 0 ? _c : []).map((file) => `  identical ${file}`),
                    ...((_d = this.changes.conflicted) !== null && _d !== void 0 ? _d : []).map((file) => `  conflict ${file}`),
                    ...((_e = this.changes.forced) !== null && _e !== void 0 ? _e : []).map((file) => `  force ${file}`),
                ].join('\n') + '\n',
            ]);
            return {
                outputDir,
                created,
                rawOutput,
            };
        });
    }
}
exports.BaseGenerator = BaseGenerator;
//# sourceMappingURL=baseGenerator.js.map