"use strict";
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
var __generator = (this && this.__generator) || function (thisArg, body) {
    var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
    return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
    function verb(n) { return function (v) { return step([n, v]); }; }
    function step(op) {
        if (f) throw new TypeError("Generator is already executing.");
        while (g && (g = 0, op[0] && (_ = 0)), _) try {
            if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
            if (y = 0, t) op = [op[0] & 2, t.value];
            switch (op[0]) {
                case 0: case 1: t = op; break;
                case 4: _.label++; return { value: op[1], done: false };
                case 5: _.label++; y = op[1]; op = [0]; continue;
                case 7: op = _.ops.pop(); _.trys.pop(); continue;
                default:
                    if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
                    if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
                    if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
                    if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
                    if (t[2]) _.ops.pop();
                    _.trys.pop(); continue;
            }
            op = body.call(thisArg, _);
        } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
        if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
    }
};
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
    if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
        if (ar || !(i in from)) {
            if (!ar) ar = Array.prototype.slice.call(from, 0, i);
            ar[i] = from[i];
        }
    }
    return to.concat(ar || Array.prototype.slice.call(from));
};
Object.defineProperty(exports, "__esModule", { value: true });
var os_1 = require("os");
var react_native_1 = require("../tools/react-native");
var packager_1 = require("../tools/packager");
var pretty_1 = require("../tools/pretty");
var flag_1 = require("../tools/flag");
var cache_1 = require("../tools/cache");
var mst_1 = require("../tools/mst");
var dependencies_1 = require("../tools/dependencies");
var demo_1 = require("../tools/demo");
module.exports = {
    run: function (toolbox) { return __awaiter(void 0, void 0, void 0, function () {
        var print, filesystem, system, meta, parameters, strings, prompt, kebabCase, exists, path, removeAsync, copy, read, write, homedir, info, colors, warning, gray, cyan, yellow, white, red, underline, options, yname, noTimeout, useDefault, CMD_INDENT, p2, command, MAX_APP_CREATION_TIME, timeoutExit, debug, log, validateProjectName, projectName, projectNameKebab, bname, defaultBundleIdentifier, bundleIdentifier, bundleIdentifierResponse, validateBundleIdentifier, defaultTargetPath, targetPath, targetPathResponse, handleHomePrefix, defaultOverwrite, overwrite, overwriteResponse, alreadyExists, defaultWorkflow, workflow, useExpoResponse, defaultGit, git, gitResponse, availablePackagers, defaultPackagerName, packagerName, validatePackagerName, initial_1, NOT_FOUND, packagerNameResponse, packagerOptions, isWindows, ignitePath, boilerplatePath, boilerplate, defaultInstallDeps, installDeps, installDepsResponse, expoVersion, expoRouter, experimentalFlags, defaultExpoRouter, experimentalExpoRouter, expoRouterResponse, defaultNewArch, newArchEnabled, newArchResponse, defaultMST, stateMgmt, includeMSTResponse, defaultRemoveDemo, removeDemo, removeDemoResponse, perfStart, timeout, terminalWidth, logo, pkg, igniteVersion, msg, boilerplateIgnorePath, targetIgnorePath, readmePath, gitIgnoreContents, cwd, packageJsonRaw, expoDistTagOutput, tagVersion, patchesToRemove, packageJson, npmrcPath, npmrcContents, yarnVersion, yarnMajorVersion, yarnrcPath, yarnrcContents, boilerplatePackageJsonHash, cachePath, cacheExists, defaultUseCache, useCache, shouldUseCache, msg, renameSpinnerMsg, boilerplateBundleIdentifier, shouldFreshInstallDeps, unboxingMessage, installCmd, msg, appJsonRaw, appJson, prebuildMessage, removeDemoPart, IGNITE, CMD, e_1, expoRouterMsg, removeMstPart, IGNITE, CMD, e_2, additionalInfo, formattingMessage, warnAboutEOL, templates, e_3, perfDuration, cliCommand, prettyCliCommand, isMac, e_4, IGNITE, doctorResults, e_5;
        var _a, _b, _c, _d;
        return __generator(this, function (_e) {
            switch (_e.label) {
                case 0:
                    print = toolbox.print, filesystem = toolbox.filesystem, system = toolbox.system, meta = toolbox.meta, parameters = toolbox.parameters, strings = toolbox.strings, prompt = toolbox.prompt;
                    kebabCase = strings.kebabCase;
                    exists = filesystem.exists, path = filesystem.path, removeAsync = filesystem.removeAsync, copy = filesystem.copy, read = filesystem.read, write = filesystem.write, homedir = filesystem.homedir;
                    info = print.info, colors = print.colors, warning = print.warning;
                    gray = colors.gray, cyan = colors.cyan, yellow = colors.yellow, white = colors.white, red = colors.red, underline = colors.underline;
                    options = parameters.options;
                    yname = (0, flag_1.boolFlag)(options.y) || (0, flag_1.boolFlag)(options.yes);
                    noTimeout = (_a = options.noTimeout) !== null && _a !== void 0 ? _a : false;
                    useDefault = function (option) { return yname && option === undefined; };
                    CMD_INDENT = "  ";
                    p2 = function (m) {
                        if (m === void 0) { m = ""; }
                        return (0, pretty_1.p)(" ".concat(m));
                    };
                    command = function (cmd) { return p2(white(CMD_INDENT + cmd)); };
                    MAX_APP_CREATION_TIME = 10 * 60 * 1000;
                    timeoutExit = function () {
                        (0, pretty_1.p)();
                        (0, pretty_1.p)(yellow("Error: App creation timed out."));
                        if (!debug)
                            (0, pretty_1.p)(gray("Run again with --debug to see what's going on."));
                        process.exit(1);
                    };
                    debug = (0, flag_1.boolFlag)(options.debug);
                    log = function (m) {
                        debug && info(" ".concat(m));
                        return m;
                    };
                    // log raw parameters for debugging
                    log("ignite command: ".concat(parameters.argv.join(" ")));
                    // #endregion
                    // #region Project Name
                    // retrieve project name from toolbox
                    (0, pretty_1.p)();
                    validateProjectName = require("../tools/validations").validateProjectName;
                    return [4 /*yield*/, validateProjectName(toolbox)];
                case 1:
                    projectName = _e.sent();
                    projectNameKebab = kebabCase(projectName);
                    bname = options.b || options.boilerplate;
                    if (bname) {
                        (0, pretty_1.p)();
                        (0, pretty_1.p)(yellow("Different boilerplates are no longer supported in Ignite v4+."));
                        (0, pretty_1.p)(gray("To use the old CLI to support different boilerplates, try:"));
                        (0, pretty_1.p)(cyan("npx ignite-cli@3 new ".concat(projectName, " --boilerplate ").concat(bname)));
                        process.exit(1);
                    }
                    defaultBundleIdentifier = "com.".concat(strings.pascalCase(projectName).toLowerCase());
                    bundleIdentifier = useDefault(options.bundle) ? defaultBundleIdentifier : options.bundle;
                    if (!(bundleIdentifier === undefined)) return [3 /*break*/, 3];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "input",
                            name: "bundleIdentifier",
                            message: "What bundle identifier?",
                            initial: defaultBundleIdentifier,
                            prefix: pretty_1.prefix,
                        }); })];
                case 2:
                    bundleIdentifierResponse = _e.sent();
                    bundleIdentifier = bundleIdentifierResponse.bundleIdentifier;
                    _e.label = 3;
                case 3:
                    validateBundleIdentifier = require("../tools/validations").validateBundleIdentifier;
                    validateBundleIdentifier(toolbox, bundleIdentifier);
                    defaultTargetPath = path(projectName);
                    targetPath = useDefault(options.targetPath) ? defaultTargetPath : options.targetPath;
                    if (!(targetPath === undefined)) return [3 /*break*/, 5];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "input",
                            name: "targetPath",
                            message: "Where do you want to start your project?",
                            initial: defaultTargetPath,
                            prefix: pretty_1.prefix,
                        }); })];
                case 4:
                    targetPathResponse = _e.sent();
                    targetPath = targetPathResponse.targetPath;
                    _e.label = 5;
                case 5:
                    handleHomePrefix = function (p) {
                        return (p === null || p === void 0 ? void 0 : p.startsWith("~")) ? p.replace("~", homedir()) : p;
                    };
                    targetPath = path(handleHomePrefix(targetPath));
                    defaultOverwrite = false;
                    overwrite = useDefault(options.overwrite) ? defaultOverwrite : (0, flag_1.boolFlag)(options.overwrite);
                    if (!(exists(targetPath) && overwrite === undefined)) return [3 /*break*/, 7];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "overwrite",
                            message: "Directory ".concat(targetPath, " already exists. Do you want to overwrite it?"),
                            initial: defaultOverwrite,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 6:
                    overwriteResponse = _e.sent();
                    overwrite = overwriteResponse.overwrite;
                    _e.label = 7;
                case 7:
                    if (exists(targetPath) && overwrite === false) {
                        alreadyExists = "Error: There's already a folder at ".concat(targetPath, ". To force overwriting that folder, run with --overwrite or say yes.");
                        (0, pretty_1.p)();
                        (0, pretty_1.p)(yellow(alreadyExists));
                        process.exit(1);
                    }
                    defaultWorkflow = "cng";
                    workflow = useDefault(options.workflow) ? defaultWorkflow : options.workflow;
                    if (!(workflow === undefined)) return [3 /*break*/, 9];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "select",
                            name: "workflow",
                            message: "How do you want to manage Native code?",
                            choices: [
                                {
                                    name: "cng",
                                    message: "Via Expo's Continuous Native Generation - Recommended [Default]",
                                    value: "cng",
                                },
                                {
                                    name: "manual",
                                    message: "Manual - commits android/ios directories",
                                    value: "manual",
                                },
                            ],
                            initial: "cng",
                            prefix: pretty_1.prefix,
                        }); })];
                case 8:
                    useExpoResponse = _e.sent();
                    workflow = useExpoResponse.workflow;
                    _e.label = 9;
                case 9:
                    log("workflow: ".concat(workflow));
                    defaultGit = true;
                    git = useDefault(options.git) ? defaultGit : (0, flag_1.boolFlag)(options.git);
                    if (!(git === undefined)) return [3 /*break*/, 11];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "git",
                            message: "Do you want to initialize a git repository?",
                            initial: defaultGit,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 10:
                    gitResponse = _e.sent();
                    git = gitResponse.git;
                    _e.label = 11;
                case 11:
                    availablePackagers = packager_1.packager.availablePackagers();
                    log("availablePackagers: ".concat(availablePackagers));
                    defaultPackagerName = availablePackagers.includes("yarn") ? "yarn" : "npm";
                    packagerName = useDefault(options.packager) ? defaultPackagerName : options.packager;
                    validatePackagerName = function (input) {
                        return typeof input === "string" && ["npm", "yarn", "pnpm", "bun"].includes(input);
                    };
                    if (packagerName !== undefined && validatePackagerName(packagerName) === false) {
                        (0, pretty_1.p)();
                        (0, pretty_1.p)(yellow("Error: Invalid packager: \"".concat(packagerName, "\". Valid packagers are npm, yarn, pnpm, bun.")));
                        process.exit(1);
                    }
                    if (packagerName !== undefined && availablePackagers.includes(packagerName) === false) {
                        (0, pretty_1.p)();
                        (0, pretty_1.p)(yellow("Error: selected \"".concat(packagerName, "\" but packager was not available on system")));
                        process.exit(1);
                    }
                    if (!(packagerName === undefined)) return [3 /*break*/, 13];
                    initial_1 = availablePackagers.findIndex(function (p) { return p === defaultPackagerName; });
                    NOT_FOUND = -1;
                    if (initial_1 === NOT_FOUND) {
                        (0, pretty_1.p)();
                        (0, pretty_1.p)(yellow("Error: Default packager \"".concat(defaultPackagerName, "\" was not available on system")));
                        process.exit(1);
                    }
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "select",
                            name: "packagerName",
                            message: "Which package manager do you want to use?",
                            choices: availablePackagers,
                            initial: initial_1,
                            prefix: pretty_1.prefix,
                        }); })];
                case 12:
                    packagerNameResponse = _e.sent();
                    packagerName = packagerNameResponse.packagerName;
                    _e.label = 13;
                case 13:
                    packagerOptions = { packagerName: packagerName };
                    isWindows = process.platform === "win32";
                    ignitePath = path("".concat(meta.src), "..");
                    boilerplatePath = path(ignitePath, "boilerplate");
                    boilerplate = function () {
                        var pathParts = [];
                        for (var _i = 0; _i < arguments.length; _i++) {
                            pathParts[_i] = arguments[_i];
                        }
                        return path.apply(void 0, __spreadArray([boilerplatePath], pathParts, false));
                    };
                    log("ignitePath: ".concat(ignitePath));
                    log("boilerplatePath: ".concat(boilerplatePath));
                    defaultInstallDeps = true;
                    installDeps = useDefault(options.installDeps)
                        ? defaultInstallDeps
                        : (0, flag_1.boolFlag)(options.installDeps);
                    if (!(installDeps === undefined)) return [3 /*break*/, 15];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "installDeps",
                            message: "Do you want to install dependencies?",
                            initial: defaultInstallDeps,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 14:
                    installDepsResponse = _e.sent();
                    installDeps = installDepsResponse.installDeps;
                    _e.label = 15;
                case 15:
                    experimentalFlags = (_c = (_b = options.experimental) === null || _b === void 0 ? void 0 : _b.split(",")) !== null && _c !== void 0 ? _c : [];
                    log("experimentalFlags: ".concat(experimentalFlags));
                    experimentalFlags.forEach(function (flag) {
                        if (flag.indexOf("expo-") > -1) {
                            if (flag !== "expo-router") {
                                expoVersion = flag.substring(5);
                            }
                            else {
                                // user wants to convert to expo-router
                                // force demo code removal for easier conversion
                                // maybe one day convert the demo app
                                expoRouter = true;
                                if (!removeDemo) {
                                    (0, pretty_1.p)();
                                    (0, pretty_1.p)(yellow("Enabling Expo Router will currently remove the demo application. To continue with the demo app, check out the recipe with full instructions: https://ignitecookbook.com/docs/recipes/ExpoRouter"));
                                    (0, pretty_1.p)(yellow("Setting --remove-demo=true"));
                                    removeDemo = true;
                                }
                            }
                        }
                    });
                    defaultExpoRouter = false;
                    experimentalExpoRouter = useDefault(expoRouter) ? defaultExpoRouter : (0, flag_1.boolFlag)(expoRouter);
                    if (!(experimentalExpoRouter === undefined)) return [3 /*break*/, 17];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "experimentalExpoRouter",
                            message: "[Experimental] Expo Router for navigation? (This will remove the demo application)",
                            initial: defaultExpoRouter,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 16:
                    expoRouterResponse = _e.sent();
                    experimentalExpoRouter = expoRouterResponse.experimentalExpoRouter;
                    // update experimental flags if needed for buildCliCommand output
                    if (experimentalExpoRouter && !experimentalFlags.includes("expo-router")) {
                        experimentalFlags.push("expo-router");
                    }
                    _e.label = 17;
                case 17:
                    defaultNewArch = false;
                    newArchEnabled = useDefault(options.newArch) ? defaultNewArch : (0, flag_1.boolFlag)(options.newArch);
                    if (!(newArchEnabled === undefined)) return [3 /*break*/, 19];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "experimentalNewArch",
                            message: "Enable the New Architecture?",
                            initial: defaultNewArch,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 18:
                    newArchResponse = _e.sent();
                    newArchEnabled = newArchResponse.experimentalNewArch;
                    _e.label = 19;
                case 19:
                    defaultMST = "mst";
                    stateMgmt = useDefault(options.state) ? defaultMST : options.state;
                    if (!(stateMgmt === undefined)) return [3 /*break*/, 21];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "includeMST",
                            message: "Include MobX-State-Tree for state management? (Recommended - opting out will remove the demo application)",
                            initial: true,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 20:
                    includeMSTResponse = _e.sent();
                    stateMgmt = includeMSTResponse.includeMST ? "mst" : "none";
                    _e.label = 21;
                case 21:
                    defaultRemoveDemo = stateMgmt !== "mst" || experimentalExpoRouter;
                    if (defaultRemoveDemo) {
                        (0, pretty_1.p)(yellow("Warning: the demo application will be removed."));
                    }
                    removeDemo = useDefault(options.removeDemo)
                        ? defaultRemoveDemo
                        : (0, flag_1.boolFlag)(options.removeDemo);
                    if (!(!defaultRemoveDemo && removeDemo === undefined)) return [3 /*break*/, 23];
                    return [4 /*yield*/, prompt.ask(function () { return ({
                            type: "confirm",
                            name: "removeDemo",
                            message: "Remove demo code? We recommend leaving it in if it's your first time using Ignite",
                            initial: defaultRemoveDemo,
                            format: pretty_1.prettyPrompt.format.boolean,
                            prefix: pretty_1.prefix,
                        }); })];
                case 22:
                    removeDemoResponse = _e.sent();
                    removeDemo = removeDemoResponse.removeDemo;
                    return [3 /*break*/, 24];
                case 23:
                    removeDemo = defaultRemoveDemo;
                    _e.label = 24;
                case 24:
                    perfStart = new Date().getTime();
                    timeout = noTimeout ? undefined : setTimeout(timeoutExit, MAX_APP_CREATION_TIME);
                    _e.label = 25;
                case 25:
                    _e.trys.push([25, 69, , 74]);
                    terminalWidth = (_d = process.stdout.columns) !== null && _d !== void 0 ? _d : 80;
                    logo = terminalWidth > 80 ? function () { return (0, pretty_1.ascii)("logo.ascii.txt"); } : function () { return (0, pretty_1.ascii)("logo-sm.ascii.txt"); };
                    (0, pretty_1.p)();
                    (0, pretty_1.p)();
                    (0, pretty_1.p)();
                    (0, pretty_1.p)();
                    logo();
                    (0, pretty_1.p)();
                    (0, pretty_1.p)();
                    pkg = (0, pretty_1.pkgColor)(packagerName);
                    igniteVersion = meta.version();
                    (0, pretty_1.p)(" \u2588 Creating ".concat((0, pretty_1.em)(projectName), " using ").concat((0, pretty_1.em)("Ignite ".concat(igniteVersion))));
                    (0, pretty_1.p)(" \u2588 Powered by ".concat((0, pretty_1.ir)(" ∞ Infinite Red "), " (").concat((0, pretty_1.link)("https://infinite.red"), ")"));
                    (0, pretty_1.p)(" \u2588 Package Manager: ".concat(pkg(print.colors.bold(packagerName))));
                    (0, pretty_1.p)(" \u2588 Bundle identifier: ".concat((0, pretty_1.em)(bundleIdentifier)));
                    (0, pretty_1.p)(" \u2588 Path: ".concat(underline(targetPath)));
                    (0, pretty_1.hr)();
                    (0, pretty_1.p)();
                    if (!(exists(targetPath) === "dir" && overwrite === true)) return [3 /*break*/, 27];
                    msg = " Tossing that old app like it's hot";
                    (0, pretty_1.startSpinner)(msg);
                    return [4 /*yield*/, removeAsync(targetPath)];
                case 26:
                    _e.sent();
                    (0, pretty_1.stopSpinner)(msg, "🗑️");
                    _e.label = 27;
                case 27:
                    // #endregion
                    // #region Copy Boilerplate Files
                    (0, pretty_1.startSpinner)(" 3D-printing a new React Native app");
                    return [4 /*yield*/, (0, react_native_1.copyBoilerplate)(toolbox, {
                            boilerplatePath: boilerplatePath,
                            targetPath: targetPath,
                            excluded: [
                                ".vscode",
                                "node_modules",
                                "yarn.lock",
                                "bun.lockb",
                                "bun.lock",
                                "package-lock.json",
                            ],
                            overwrite: overwrite,
                        })];
                case 28:
                    _e.sent();
                    (0, pretty_1.stopSpinner)(" 3D-printing a new React Native app", "🖨");
                    boilerplateIgnorePath = exists(boilerplate(".gitignore.template"))
                        ? boilerplate(".gitignore.template")
                        : boilerplate(".gitignore");
                    targetIgnorePath = log(path(targetPath, ".gitignore"));
                    copy(log(boilerplateIgnorePath), targetIgnorePath, { overwrite: true });
                    readmePath = path(targetPath, "README.md");
                    (0, react_native_1.updatePackagerCommandsInReadme)(readmePath, packagerName);
                    if (exists(targetIgnorePath) === false) {
                        warning("  Unable to copy ".concat(boilerplateIgnorePath, " to ").concat(targetIgnorePath));
                    }
                    else if (workflow === "manual") {
                        gitIgnoreContents = read(targetIgnorePath);
                        gitIgnoreContents = gitIgnoreContents.replace("/android", "").replace("/ios", "");
                        write(targetIgnorePath, gitIgnoreContents);
                    }
                    cwd = log(process.cwd());
                    // jump into the project to do additional tasks
                    process.chdir(targetPath);
                    packageJsonRaw = read("package.json");
                    packageJsonRaw = packageJsonRaw
                        .replace(/HelloWorld/g, projectName)
                        .replace(/hello-world/g, projectNameKebab);
                    // add in expo-router package
                    if (experimentalExpoRouter) {
                        // find "expo-localization" line and append "expo-router" line after it
                        packageJsonRaw = packageJsonRaw.replace(/"expo-localization": ".*",/g, "\"expo-localization\": \"~15.0.3\",".concat(os_1.EOL, "    \"expo-router\":  \"~3.5.17\","));
                        // replace "main" entry point from App.js to "expo-router/entry"
                        packageJsonRaw = packageJsonRaw.replace(/"main": ".*",/g, "\"main\": \"expo-router/entry\",");
                    }
                    // If we need native dirs, change up start scripts from Expo Go variation to expo run:platform.
                    packageJsonRaw = packageJsonRaw
                        .replace(/start --android/g, "run:android")
                        .replace(/start --ios/g, "run:ios");
                    if (!expoVersion) return [3 /*break*/, 30];
                    return [4 /*yield*/, system.run("npm view expo dist-tags --json")
                        // filter for canary/beta and get last item in array
                    ];
                case 29:
                    expoDistTagOutput = _e.sent();
                    tagVersion = JSON.parse(expoDistTagOutput)[expoVersion];
                    log("overriding expo version to: ".concat(tagVersion));
                    // find line with "expo": and replace entire line with tagVersion
                    packageJsonRaw = packageJsonRaw.replace(/"expo": ".*"/g, "\"expo\": \"".concat(tagVersion, "\""));
                    _e.label = 30;
                case 30:
                    // If we're removing the demo code, clean up some dependencies that are no longer needed
                    if (removeDemo) {
                        log("Removing demo dependencies... ".concat(demo_1.demoDependenciesToRemove.join(", ")));
                        packageJsonRaw = (0, dependencies_1.findAndRemoveDependencies)(packageJsonRaw, demo_1.demoDependenciesToRemove);
                        patchesToRemove = (0, demo_1.findDemoPatches)();
                        log("Removing demo patches... ".concat(patchesToRemove));
                        patchesToRemove.forEach(function (patch) { return filesystem.cwd("./patches").remove(patch); });
                    }
                    if (stateMgmt === "none") {
                        log("Removing MST dependencies... ".concat(mst_1.mstDependenciesToRemove.join(", ")));
                        packageJsonRaw = (0, dependencies_1.findAndRemoveDependencies)(packageJsonRaw, mst_1.mstDependenciesToRemove);
                    }
                    if (newArchEnabled) {
                        log("Swapping new architecture compatible dependencies...");
                        packageJsonRaw = (0, dependencies_1.findAndUpdateDependencyVersions)(packageJsonRaw, dependencies_1.newArchCompatExpectedVersions);
                    }
                    packageJson = JSON.parse(packageJsonRaw);
                    write("./package.json", packageJson);
                    if (!(packagerName === "pnpm")) return [3 /*break*/, 31];
                    npmrcPath = path(targetPath, ".npmrc");
                    npmrcContents = read(npmrcPath);
                    write(npmrcPath, "".concat(npmrcContents).concat(os_1.EOL, "node-linker=hoisted").concat(os_1.EOL));
                    return [3 /*break*/, 33];
                case 31:
                    if (!(packagerName === "yarn")) return [3 /*break*/, 33];
                    return [4 /*yield*/, packager_1.packager.run("-v", { packagerName: packagerName })];
                case 32:
                    yarnVersion = _e.sent();
                    yarnMajorVersion = parseInt(yarnVersion.split(".")[0], 10);
                    // if yarn version > 1 fix .yarnrc.yml
                    if (yarnMajorVersion > 1) {
                        log("yarn v".concat(yarnMajorVersion, " found... fixing .yarnrc.yml..."));
                        yarnrcPath = path(targetPath, ".yarnrc.yml");
                        yarnrcContents = read(yarnrcPath);
                        write(yarnrcPath, "".concat(yarnrcContents !== null && yarnrcContents !== void 0 ? yarnrcContents : "").concat(os_1.EOL, "nodeLinker: node-modules").concat(os_1.EOL));
                    }
                    _e.label = 33;
                case 33:
                    boilerplatePackageJsonHash = cache_1.cache.hash(read(path(boilerplatePath, "package.json")));
                    cachePath = path(cache_1.cache.rootdir(), boilerplatePackageJsonHash, packagerName);
                    cacheExists = exists(cachePath) === "dir";
                    log("".concat(!cacheExists ? "expected " : "", "cachePath: ").concat(cachePath));
                    log("cacheExists: ".concat(cacheExists));
                    defaultUseCache = false;
                    useCache = options.useCache === undefined ? defaultUseCache : (0, flag_1.boolFlag)(options.useCache);
                    shouldUseCache = installDeps && cacheExists && useCache;
                    if (!shouldUseCache) return [3 /*break*/, 35];
                    msg = "Grabbing those ".concat(packagerName, " dependencies from the back");
                    (0, pretty_1.startSpinner)(msg);
                    return [4 /*yield*/, cache_1.cache.copy({
                            fromRootDir: cachePath,
                            toRootDir: targetPath,
                            packagerName: packagerName,
                        })];
                case 34:
                    _e.sent();
                    (0, pretty_1.stopSpinner)(msg, "📦");
                    _e.label = 35;
                case 35:
                    renameSpinnerMsg = "Getting those last few details perfect";
                    (0, pretty_1.startSpinner)(renameSpinnerMsg);
                    boilerplateBundleIdentifier = "com.helloworld";
                    return [4 /*yield*/, (0, react_native_1.renameReactNativeApp)(toolbox, "HelloWorld", projectName, boilerplateBundleIdentifier, bundleIdentifier)];
                case 36:
                    _e.sent();
                    return [4 /*yield*/, (0, react_native_1.replaceMaestroBundleIds)(toolbox, boilerplateBundleIdentifier, bundleIdentifier)];
                case 37:
                    _e.sent();
                    (0, pretty_1.stopSpinner)(renameSpinnerMsg, "🎨");
                    shouldFreshInstallDeps = installDeps && shouldUseCache === false;
                    if (!shouldFreshInstallDeps) return [3 /*break*/, 41];
                    unboxingMessage = "Installing ".concat(packagerName, " dependencies (wow these are heavy)");
                    (0, pretty_1.startSpinner)(unboxingMessage);
                    installCmd = packager_1.packager.installCmd({ packagerName: packagerName });
                    return [4 /*yield*/, system.run(installCmd, { onProgress: log })
                        // now that expo is installed, we can run their install --fix for best Expo SDK compatibility
                        // for right now, we don't do this in CI because it returns a non-zero exit code
                        // see https://docs.expo.dev/more/expo-cli/#version-validation
                    ];
                case 38:
                    _e.sent();
                    if (!(process.env.CI !== "true")) return [3 /*break*/, 40];
                    log("Running `npx expo install --fix...`");
                    return [4 /*yield*/, system.run("npx expo install --fix", { onProgress: log })];
                case 39:
                    _e.sent();
                    _e.label = 40;
                case 40:
                    (0, pretty_1.stopSpinner)(unboxingMessage, "🧶");
                    _e.label = 41;
                case 41: 
                // remove the gitignore template
                return [4 /*yield*/, removeAsync(".gitignore.template")
                    // #endregion
                    // #region Cache dependencies
                ];
                case 42:
                    // remove the gitignore template
                    _e.sent();
                    if (!(shouldFreshInstallDeps && cacheExists === false && useCache)) return [3 /*break*/, 44];
                    msg = "Saving ".concat(packagerName, " dependencies for next time");
                    (0, pretty_1.startSpinner)(msg);
                    log(targetPath);
                    return [4 /*yield*/, cache_1.cache.copy({
                            fromRootDir: targetPath,
                            toRootDir: cachePath,
                            packagerName: packagerName,
                        })];
                case 43:
                    _e.sent();
                    (0, pretty_1.stopSpinner)(msg, "📦");
                    _e.label = 44;
                case 44:
                    // #endregion
                    // #region Configure app.json
                    // Enable New Architecture if requested (must happen before prebuild)
                    (0, pretty_1.startSpinner)("Configuring app.json");
                    try {
                        appJsonRaw = read("app.json");
                        appJson = JSON.parse(appJsonRaw);
                        // Inject ignite version to app.json
                        appJson.ignite.version = igniteVersion;
                        if (newArchEnabled === true) {
                            appJson.expo.newArchEnabled = true;
                        }
                        if (experimentalExpoRouter) {
                            appJson.expo.experiments.typedRoutes = true;
                            appJson.expo.plugins.push("expo-router");
                        }
                        write("./app.json", appJson);
                    }
                    catch (e) {
                        log(e);
                        (0, pretty_1.p)(yellow("Unable to configure app.json."));
                    }
                    (0, pretty_1.stopSpinner)("Configuring app.json", "⚙️");
                    if (!(installDeps === true)) return [3 /*break*/, 46];
                    prebuildMessage = "Generating native template via Expo Prebuild";
                    (0, pretty_1.startSpinner)(prebuildMessage);
                    return [4 /*yield*/, packager_1.packager.run("prebuild:clean", __assign(__assign({}, packagerOptions), { onProgress: log }))];
                case 45:
                    _e.sent();
                    (0, pretty_1.stopSpinner)(prebuildMessage, "🛠️");
                    _e.label = 46;
                case 46:
                    removeDemoPart = removeDemo === true ? "code" : "markup";
                    (0, pretty_1.startSpinner)("Removing fancy demo ".concat(removeDemoPart));
                    (0, pretty_1.p)(yellow("removeDemo: ".concat(removeDemo)));
                    (0, pretty_1.p)(yellow("removeDemoPart: ".concat(removeDemoPart)));
                    _e.label = 47;
                case 47:
                    _e.trys.push([47, 49, , 50]);
                    IGNITE = "node " + filesystem.path(__dirname, "..", "..", "bin", "ignite");
                    CMD = removeDemo === true ? "remove-demo" : "remove-demo-markup";
                    log("Ignite bin path: ".concat(IGNITE));
                    return [4 /*yield*/, system.run("".concat(IGNITE, " ").concat(CMD, " \"").concat(targetPath, "\""), { onProgress: log })];
                case 48:
                    _e.sent();
                    return [3 /*break*/, 50];
                case 49:
                    e_1 = _e.sent();
                    log(e_1);
                    (0, pretty_1.p)(yellow("Unable to remove demo ".concat(removeDemoPart, ".")));
                    return [3 /*break*/, 50];
                case 50:
                    (0, pretty_1.stopSpinner)("Removing fancy demo ".concat(removeDemoPart), "🛠️");
                    // #endregion
                    // #region Expo Router edits
                    if (experimentalExpoRouter) {
                        expoRouterMsg = " Recalibrating compass with Expo Router";
                        (0, pretty_1.startSpinner)(expoRouterMsg);
                        /**
                         * Instructions mostly adapted from https://ignitecookbook.com/docs/recipes/ExpoRouter
                         * 1. Move all files from app/ to src/
                         * 2. Update code refs to app/ with src/
                         * 3. Refactor Reactotron commands to use `router` instead of refs to react navigation
                         * 4. Create a screen template that makes sense for Expo Router
                         * 5. Clean up - move ErrorBoundary to proper spot and remove unused files
                         */
                        filesystem
                            .cwd(targetPath)
                            .find("app")
                            .forEach(function (file) { return filesystem.cwd(targetPath).move(file, file.replace("app", "src")); });
                        (0, react_native_1.updateExpoRouterSrcDir)(toolbox);
                        (0, react_native_1.refactorExpoRouterReactotronCmds)(toolbox);
                        (0, react_native_1.createExpoRouterScreenTemplate)(toolbox);
                        (0, react_native_1.cleanupExpoRouterConversion)(toolbox, targetPath);
                        (0, pretty_1.stopSpinner)(expoRouterMsg, "🧭");
                    }
                    else {
                        // remove src/ dir since not using expo-router
                        filesystem.cwd(targetPath).remove("src");
                    }
                    removeMstPart = stateMgmt === "none" ? "code" : "markup";
                    (0, pretty_1.startSpinner)("Removing MobX-State-Tree ".concat(removeMstPart));
                    _e.label = 51;
                case 51:
                    _e.trys.push([51, 53, , 54]);
                    IGNITE = "node " + filesystem.path(__dirname, "..", "..", "bin", "ignite");
                    CMD = stateMgmt === "none" ? "remove-mst" : "remove-mst-markup";
                    log("Ignite bin path: ".concat(IGNITE));
                    return [4 /*yield*/, system.run("".concat(IGNITE, " ").concat(CMD, " \"").concat(targetPath, "\" \"").concat(experimentalExpoRouter ? "src" : "app", "\""), { onProgress: log })];
                case 52:
                    _e.sent();
                    return [3 /*break*/, 54];
                case 53:
                    e_2 = _e.sent();
                    log(e_2);
                    additionalInfo = stateMgmt === "none"
                        ? " To perform updates manually, check out the recipe with full instructions: https://ignitecookbook.com/docs/recipes/RemoveMobxStateTree"
                        : "";
                    (0, pretty_1.p)(yellow("Unable to remove MobX-State-Tree ".concat(removeMstPart, ".").concat(additionalInfo)));
                    return [3 /*break*/, 54];
                case 54:
                    (0, pretty_1.stopSpinner)("Removing MobX-State-Tree ".concat(removeMstPart), "🌳");
                    formattingMessage = "Cleaning up";
                    (0, pretty_1.startSpinner)(formattingMessage);
                    if (!(installDeps === true)) return [3 /*break*/, 56];
                    // Make sure all our modifications are formatted nicely
                    return [4 /*yield*/, packager_1.packager.run("lint", __assign({}, packagerOptions))];
                case 55:
                    // Make sure all our modifications are formatted nicely
                    _e.sent();
                    return [3 /*break*/, 58];
                case 56: 
                // if our linting configuration is not installed, try format
                // using prettier to make sure it's reasonably close, but this will skip
                // eslint issues
                return [4 /*yield*/, system.run("npx prettier@3.3.3 --write .", {
                        trim: true,
                        cwd: targetPath,
                    })];
                case 57:
                    // if our linting configuration is not installed, try format
                    // using prettier to make sure it's reasonably close, but this will skip
                    // eslint issues
                    _e.sent();
                    _e.label = 58;
                case 58:
                    (0, pretty_1.stopSpinner)(formattingMessage, "🧽");
                    warnAboutEOL = false;
                    if (isWindows) {
                        try {
                            templates = filesystem.find("".concat(targetPath, "/ignite/templates"), {
                                directories: false,
                                files: true,
                                matching: "*.ejs",
                            });
                            log("templates to change EOL: ".concat(templates));
                            templates.map(function (file) { return __awaiter(void 0, void 0, void 0, function () {
                                var template;
                                return __generator(this, function (_a) {
                                    log("Converting EOL for ".concat(file));
                                    template = read(file);
                                    template = template.replace(/\n/g, "\r\n");
                                    write(file, template);
                                    return [2 /*return*/];
                                });
                            }); });
                        }
                        catch (_f) {
                            warnAboutEOL = true;
                        }
                    }
                    if (!(git === true)) return [3 /*break*/, 68];
                    (0, pretty_1.startSpinner)(" Backing everything up in source control");
                    _e.label = 59;
                case 59:
                    _e.trys.push([59, 66, , 67]);
                    if (!isWindows) return [3 /*break*/, 63];
                    return [4 /*yield*/, system.run(log("git init"))];
                case 60:
                    _e.sent();
                    return [4 /*yield*/, system.run(log("git add -A"))];
                case 61:
                    _e.sent();
                    return [4 /*yield*/, system.run(log("git commit -m \"New Ignite ".concat(meta.version(), " app")))];
                case 62:
                    _e.sent();
                    return [3 /*break*/, 65];
                case 63: return [4 /*yield*/, system.run(log("\n              \\rm -rf ./.git\n              git init;\n              git add -A;\n              git commit -m \"New Ignite ".concat(meta.version(), " app\";\n            ")))];
                case 64:
                    _e.sent();
                    _e.label = 65;
                case 65: return [3 /*break*/, 67];
                case 66:
                    e_3 = _e.sent();
                    (0, pretty_1.p)(yellow("Unable to commit the initial changes. Please check your git username and email."));
                    return [3 /*break*/, 67];
                case 67:
                    (0, pretty_1.stopSpinner)(" Backing everything up in source control", "🗄");
                    _e.label = 68;
                case 68:
                    // back to the original directory
                    process.chdir(log(cwd));
                    // #endregion
                    // #region Print Finish
                    // clean up any spinners we forgot to clear
                    (0, pretty_1.p)();
                    (0, pretty_1.hr)();
                    (0, pretty_1.p)();
                    (0, pretty_1.clearSpinners)();
                    perfDuration = Math.round((new Date().getTime() - perfStart) / 10) / 100;
                    // no need to timeout, we're done!
                    clearTimeout(timeout);
                    p2("Ignited ".concat((0, pretty_1.em)("".concat(projectName)), " in ").concat(gray("".concat(perfDuration, "s")), "  \uD83D\uDE80 "));
                    p2();
                    cliCommand = buildCliCommand({
                        flags: {
                            b: bname,
                            boilerplate: bname,
                            bundle: bundleIdentifier,
                            debug: debug,
                            git: git,
                            installDeps: installDeps,
                            overwrite: overwrite,
                            packager: packagerName,
                            targetPath: targetPath,
                            removeDemo: removeDemo,
                            newArch: newArchEnabled,
                            experimental: experimentalFlags.length > 0 ? experimentalFlags.join(",") : undefined,
                            workflow: workflow,
                            useCache: useCache,
                            y: yname,
                            yes: yname,
                            noTimeout: noTimeout,
                            state: stateMgmt,
                        },
                        projectName: projectName,
                        toolbox: toolbox,
                    });
                    p2("For next time, here are the Ignite options you picked:");
                    prettyCliCommand = cliCommand
                        .split(" ")
                        .map(function (c) { return (c === projectName || (c === null || c === void 0 ? void 0 : c.startsWith("--")) ? "".concat(c, " \\").concat(os_1.EOL) : c); }) // add a line break after the project name and each flag
                        .map(function (c, i, a) { return (i === a.length - 1 ? c.replace("\\".concat(os_1.EOL), "") : c); }) // remove the line break after the last flag
                        .map(function (c) { return (c.startsWith("--") ? pretty_1.INDENT + CMD_INDENT + CMD_INDENT + c : c); }) // add whitespace to the flags so it looks nice
                        .join(" ");
                    command("".concat(prettyCliCommand));
                    p2();
                    if (!(0, react_native_1.isAndroidInstalled)(toolbox)) {
                        (0, pretty_1.hr)();
                        p2();
                        p2("To run in Android, make sure you've followed the latest");
                        p2("react-native setup instructions. You reference them at:");
                        p2("".concat((0, pretty_1.link)("https://reactnative.dev/docs/environment-setup")));
                        p2();
                    }
                    if (warnAboutEOL) {
                        (0, pretty_1.hr)();
                        p2();
                        p2(yellow("Generator templates could not be converted to Windows EOL."));
                        p2(yellow("You may want to update these manually with your code editor, more info at:"));
                        p2("".concat((0, pretty_1.link)("https://docs.infinite.red/ignite-cli/concept/Generators/")));
                        p2();
                    }
                    (0, pretty_1.hr)();
                    p2();
                    p2("Need additional help?");
                    p2();
                    p2("Join our Slack community at ".concat((0, pretty_1.link)("http://community.infinite.red.")));
                    p2();
                    (0, pretty_1.hr)();
                    p2();
                    p2("Now get cooking! 🍽");
                    command("cd ".concat(targetPath));
                    if (!installDeps)
                        command(packager_1.packager.installCmd({ packagerName: packagerName }));
                    isMac = process.platform === "darwin";
                    if (isMac) {
                        command("".concat(packager_1.packager.runCmd("ios", packagerOptions)));
                        p2("Or Android via");
                        command("".concat(packager_1.packager.runCmd("android", packagerOptions)));
                    }
                    else {
                        command("".concat(packager_1.packager.runCmd("android", packagerOptions)));
                    }
                    p2();
                    p2();
                    // #endregion
                    // this is a hack to prevent the process from hanging
                    // if there are any tasks left in the event loop
                    // like I/O operations to process.stdout and process.stderr
                    // see https://github.com/infinitered/ignite/issues/2084
                    process.exit(0);
                    return [3 /*break*/, 74];
                case 69:
                    e_4 = _e.sent();
                    (0, pretty_1.stopLastSpinner)("❌");
                    p2(red("\nThe following error occurred:"));
                    p2();
                    p2(red(e_4.toString()));
                    p2();
                    p2("Consider opening an issue with the following information at:");
                    p2("".concat((0, pretty_1.link)("https://github.com/infinitered/ignite/issues/new?template=bug_report.yml&labels=bug")));
                    p2();
                    (0, pretty_1.startSpinner)(" Gathering system and project details");
                    _e.label = 70;
                case 70:
                    _e.trys.push([70, 72, , 73]);
                    IGNITE = "node " + filesystem.path(__dirname, "..", "..", "bin", "ignite");
                    return [4 /*yield*/, system.run("".concat(IGNITE, " doctor"))];
                case 71:
                    doctorResults = _e.sent();
                    (0, pretty_1.p)("\n\n".concat(doctorResults));
                    return [3 /*break*/, 73];
                case 72:
                    e_5 = _e.sent();
                    (0, pretty_1.p)(yellow("Unable to gather system and project details."));
                    return [3 /*break*/, 73];
                case 73:
                    (0, pretty_1.clearSpinners)();
                    process.exit(1);
                    return [3 /*break*/, 74];
                case 74: return [2 /*return*/];
            }
        });
    }); },
};
function buildCliCommand(args) {
    var flags = args.flags, toolbox = args.toolbox, projectName = args.projectName;
    var strings = toolbox.strings;
    var kebabCase = strings.kebabCase;
    var privateFlags = ["b", "boilerplate", "debug", "useCache", "y", "yes"];
    var stringFlag = function (_a) {
        var key = _a[0], value = _a[1];
        return "--".concat(kebabCase(key), "=").concat(value);
    };
    var booleanFlag = function (_a) {
        var key = _a[0], value = _a[1];
        return value ? "--".concat(kebabCase(key)) : "--".concat(kebabCase(key), "=").concat(value);
    };
    var cliCommand = "npx ignite-cli new ".concat(projectName, " ").concat(Object.entries(flags)
        .filter(function (_a) {
        var key = _a[0];
        return privateFlags.includes(key) === false;
    })
        .filter(function (_a) {
        var value = _a[1];
        return value !== undefined;
    })
        .map(function (_a) {
        var key = _a[0], value = _a[1];
        return typeof value === "boolean" ? booleanFlag([key, value]) : stringFlag([key, value]);
    })
        .join(" "));
    return cliCommand;
}
//# sourceMappingURL=new.js.map