"use strict";
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 };
    }
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.demo = exports.demoMarkupRegex = exports.CommentType = void 0;
var gluegun_1 = require("gluegun");
var pathlib = require("path");
var CommentType;
(function (CommentType) {
    CommentType["REMOVE_FILE"] = "@demo remove-file";
    CommentType["REMOVE_CURRENT_LINE"] = "@demo remove-current-line";
    CommentType["REMOVE_NEXT_LINE"] = "@demo remove-next-line";
    CommentType["REMOVE_BLOCK_START"] = "@demo remove-block-start";
    CommentType["REMOVE_BLOCK_END"] = "@demo remove-block-end";
})(CommentType = exports.CommentType || (exports.CommentType = {}));
/**
 * Regex pattern to find the various types of // @demo remove-x comments
 *
 * NOTE: This currently will _NOT_ remove a multiline comment
 */
exports.demoMarkupRegex = /\s*\/\/\s*@demo.*|{?\/.*@demo.*\/}?/gm;
/**
 * Take the file content as a string and remove any
 * line of code with an `// @demo remove-current-line` comment
 */
function removeCurrentLine(contents, comment) {
    if (comment === void 0) { comment = CommentType.REMOVE_CURRENT_LINE; }
    var lines = contents.split("\n");
    var result = lines.filter(function (line) { return !line.includes(comment); });
    return result.join("\n");
}
/**
 * Take the file content as a string and remove the next line
 * of code with an `// @demo remove-next-line` comment before it
 */
function removeNextLine(contents, comment) {
    if (comment === void 0) { comment = CommentType.REMOVE_NEXT_LINE; }
    var lines = contents.split("\n");
    var result = lines.filter(function (line, index) {
        var prevLine = lines[index - 1];
        var preserveCurrent = line.includes(comment) === false;
        var preservePrevious = prevLine !== undefined && prevLine.includes(comment) === false;
        if (index === 0) {
            // if we are on the first line, there is no previous line to check
            return preserveCurrent;
        }
        // keep current line if there is no comment in current or previous line
        var keepLine = preserveCurrent && preservePrevious;
        return keepLine;
    });
    return result.join("\n");
}
/**
 * Take the file content as a string and remove the lines of code between
 * `// @demo remove-block-start` and `// @demo remove-block-end` comments
 */
function removeBlock(contents, comment) {
    if (comment === void 0) { comment = { start: CommentType.REMOVE_BLOCK_START, end: CommentType.REMOVE_BLOCK_END }; }
    var start = comment.start, end = comment.end;
    var lines = contents.split("\n");
    var findIndex = function (l, c) {
        return l.findIndex(function (line) { return line.includes(c); });
    };
    var NOT_FOUND = -1;
    var blockStartIndex = findIndex(lines, start);
    var blockEndIndex = findIndex(lines, end);
    var blockExists = findIndex(lines, start) !== NOT_FOUND && blockEndIndex !== NOT_FOUND;
    if (blockExists) {
        var blockLength = blockEndIndex - blockStartIndex + 1;
        lines.splice(blockStartIndex, blockLength); // mutates `lines`
    }
    var updateContents = lines.join("\n");
    var anotherBlockExists = findIndex(lines, start) !== NOT_FOUND && findIndex(lines, end) !== NOT_FOUND;
    if (anotherBlockExists) {
        return removeBlock(updateContents, comment);
    }
    return updateContents;
}
/**
 * Perform all remove operations possible in a file
 * @param contents The file contents as a string
 * @return The file contents with all remove operations performed
 */
function remove(contents) {
    var result = removeBlock(removeNextLine(removeCurrentLine(contents)));
    return result;
}
/**
 * Perform replace on all types of @demo markup
 * @param contents The file contents as a string
 * @return The file contents with all @demo related CommentType removed
 */
function sanitize(contents) {
    var result = contents.replace(exports.demoMarkupRegex, "");
    return result;
}
function find(targetDir, matching) {
    var MATCHING_GLOBS = [
        "!**/.DS_Store",
        "!**/.expo{,/**}",
        "!**/.git{,/**}",
        "!**/.vscode{,/**}",
        "!**/node_modules{,/**}",
        "!**/ios/build{,/**}",
        "!**/ios/Pods{,/**}",
        "!**/ios/*.xcworkspace{,/**}",
        "!**/android/build{,/**}",
        "!**/android/app/build{,/**}",
    ];
    var filePaths = gluegun_1.filesystem
        .cwd(targetDir)
        .find({
        matching: matching !== null && matching !== void 0 ? matching : MATCHING_GLOBS,
        recursive: true,
        files: true,
        directories: false,
    })
        .map(function (path) { return pathlib.join(targetDir, path); });
    return filePaths;
}
function update(_a) {
    var filePaths = _a.filePaths, _b = _a.dryRun, dryRun = _b === void 0 ? true : _b, _c = _a.onlyMarkup, onlyMarkup = _c === void 0 ? false : _c;
    return __awaiter(this, void 0, void 0, function () {
        var demoCommentResults;
        var _this = this;
        return __generator(this, function (_d) {
            switch (_d.label) {
                case 0: return [4 /*yield*/, Promise.allSettled(filePaths.map(function (path) { return __awaiter(_this, void 0, void 0, function () {
                        var exists, update, read, _a, REMOVE_CURRENT_LINE, REMOVE_NEXT_LINE, REMOVE_BLOCK_START, REMOVE_BLOCK_END, REMOVE_FILE, comments, operations, shouldUpdate, before_1;
                        return __generator(this, function (_b) {
                            switch (_b.label) {
                                case 0:
                                    exists = gluegun_1.patching.exists, update = gluegun_1.patching.update;
                                    read = gluegun_1.filesystem.read;
                                    _a = exports.demo.CommentType, REMOVE_CURRENT_LINE = _a.REMOVE_CURRENT_LINE, REMOVE_NEXT_LINE = _a.REMOVE_NEXT_LINE, REMOVE_BLOCK_START = _a.REMOVE_BLOCK_START, REMOVE_BLOCK_END = _a.REMOVE_BLOCK_END, REMOVE_FILE = _a.REMOVE_FILE;
                                    comments = [];
                                    return [4 /*yield*/, exists(path, REMOVE_FILE)];
                                case 1:
                                    if (_b.sent()) {
                                        if (!dryRun && !onlyMarkup)
                                            gluegun_1.filesystem.remove(path);
                                        comments.push(REMOVE_FILE);
                                        return [2 /*return*/, { path: path, comments: comments }];
                                    }
                                    operations = [
                                        REMOVE_CURRENT_LINE,
                                        REMOVE_NEXT_LINE,
                                        REMOVE_BLOCK_START,
                                        REMOVE_BLOCK_END,
                                    ];
                                    shouldUpdate = onlyMarkup
                                        ? RegExp(exports.demoMarkupRegex, "gm")
                                        : RegExp(operations.join("|"), "g");
                                    return [4 /*yield*/, exists(path, shouldUpdate)];
                                case 2:
                                    if (!_b.sent()) return [3 /*break*/, 4];
                                    before_1 = read(path);
                                    operations.forEach(function (operation) {
                                        if (before_1.includes(operation)) {
                                            comments.push(operation);
                                        }
                                    });
                                    if (!!dryRun) return [3 /*break*/, 4];
                                    return [4 /*yield*/, update(path, onlyMarkup ? exports.demo.sanitize : exports.demo.remove)];
                                case 3:
                                    _b.sent();
                                    _b.label = 4;
                                case 4: return [2 /*return*/, { path: path, comments: comments }];
                            }
                        });
                    }); }))];
                case 1:
                    demoCommentResults = _d.sent();
                    return [2 /*return*/, demoCommentResults];
            }
        });
    });
}
exports.demo = {
    CommentType: CommentType,
    removeCurrentLine: removeCurrentLine,
    removeNextLine: removeNextLine,
    removeBlock: removeBlock,
    remove: remove,
    sanitize: sanitize,
    find: find,
    update: update,
};
//# sourceMappingURL=demo.js.map