"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ZipOpenFS = void 0;
exports.getArchivePart = getArchivePart;
const fslib_1 = require("@yarnpkg/fslib");
const fslib_2 = require("@yarnpkg/fslib");
const libzip_1 = require("@yarnpkg/libzip");
/**
 * Extracts the archive part (ending in the first instance of `extension`) from a path.
 *
 * The indexOf-based implementation is ~3.7x faster than a RegExp-based implementation.
 */
function getArchivePart(path, extension) {
    let idx = path.indexOf(extension);
    if (idx <= 0)
        return null;
    let nextCharIdx = idx;
    while (idx >= 0) {
        nextCharIdx = idx + extension.length;
        if (path[nextCharIdx] === fslib_2.ppath.sep)
            break;
        // Disallow files named ".zip"
        if (path[idx - 1] === fslib_2.ppath.sep)
            return null;
        idx = path.indexOf(extension, nextCharIdx);
    }
    // The path either has to end in ".zip" or contain an archive subpath (".zip/...")
    if (path.length > nextCharIdx && path[nextCharIdx] !== fslib_2.ppath.sep)
        return null;
    return path.slice(0, nextCharIdx);
}
class ZipOpenFS extends fslib_1.MountFS {
    static async openPromise(fn, opts) {
        const zipOpenFs = new ZipOpenFS(opts);
        try {
            return await fn(zipOpenFs);
        }
        finally {
            zipOpenFs.saveAndClose();
        }
    }
    constructor(opts = {}) {
        const fileExtensions = opts.fileExtensions;
        const readOnlyArchives = opts.readOnlyArchives;
        const getMountPoint = typeof fileExtensions === `undefined`
            ? path => getArchivePart(path, `.zip`)
            : path => {
                for (const extension of fileExtensions) {
                    const result = getArchivePart(path, extension);
                    if (result) {
                        return result;
                    }
                }
                return null;
            };
        const factorySync = (baseFs, p) => {
            return new libzip_1.ZipFS(p, {
                baseFs,
                readOnly: readOnlyArchives,
                stats: baseFs.statSync(p),
            });
        };
        const factoryPromise = async (baseFs, p) => {
            const zipOptions = {
                baseFs,
                readOnly: readOnlyArchives,
                stats: await baseFs.statPromise(p),
            };
            return () => {
                return new libzip_1.ZipFS(p, zipOptions);
            };
        };
        super({
            ...opts,
            factorySync,
            factoryPromise,
            getMountPoint,
        });
    }
}
exports.ZipOpenFS = ZipOpenFS;
