{"version":3,"sources":["jsdelivr-header.js","/npm/get-folder@0.1.1/dist/index.js"],"names":[],"mappings":"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","file":"/npm/get-folder@0.1.1/dist/index.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /npm/get-folder@0.1.1/dist/index.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","/*!\n * get-folder v0.1.1\n * High-Performance Folder Size Calculator.\n * Copyright (c) jl15988.\n * This source code is licensed under the MIT license.\n */\n'use strict';\n\nvar fs = require('fs');\nvar path$1 = require('path');\nvar bignumber_js = require('bignumber.js');\nvar path = require('node:path');\n\nfunction _interopNamespaceDefault(e) {\n  var n = Object.create(null);\n  if (e) {\n    Object.keys(e).forEach(function (k) {\n      if (k !== 'default') {\n        var d = Object.getOwnPropertyDescriptor(e, k);\n        Object.defineProperty(n, k, d.get ? d : {\n          enumerable: true,\n          get: function () { return e[k]; }\n        });\n      }\n    });\n  }\n  n.default = e;\n  return Object.freeze(n);\n}\n\nvar path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);\n\n/**\n * 简化的信号量类，用于控制并发数量\n *\n * 工作原理：\n * 1. 维护一个固定数量的\"令牌\"（tokens）\n * 2. 每个并发操作需要先获取令牌才能执行\n * 3. 没有令牌时，操作会被挂起等待\n * 4. 操作完成后释放令牌，唤醒等待的操作\n *\n * 这样确保同时运行的操作数量不会超过设定的并发限制，\n * 避免文件句柄耗尽、内存占用过高等问题\n */\nclass SimpleSemaphore {\n    /**\n     * 当前可用的令牌数量\n     */\n    available;\n    /**\n     * 等待队列：存储等待令牌的 resolve 函数\n     */\n    waiters = [];\n    /**\n     * 构造函数\n     * @param concurrency 最大并发数（令牌总数）\n     */\n    constructor(concurrency) {\n        this.available = concurrency;\n    }\n    /**\n     * 获取令牌（申请执行权限）\n     *\n     * 执行逻辑：\n     * 1. 如果有可用令牌，立即获取并返回\n     * 2. 如果没有令牌，创建 Promise 并加入等待队列\n     * 3. 当前操作会被挂起，直到有令牌释放时被唤醒\n     *\n     * @returns Promise<void> 当获得令牌时 resolve\n     */\n    async acquire() {\n        // 情况1：有可用令牌，立即获取\n        if (this.available > 0) {\n            // 消耗一个令牌\n            this.available--;\n            // 立即返回，继续执行\n            return;\n        }\n        // 情况2：没有可用令牌，需要等待\n        return new Promise((resolve) => {\n            // 将 resolve 函数包装后放入等待队列\n            // 当有令牌释放时，会调用这个函数唤醒等待者\n            this.waiters.push(() => {\n                // 消耗令牌\n                this.available--;\n                // 唤醒等待的 acquire() 调用\n                resolve();\n            });\n        });\n    }\n    /**\n     * 释放令牌（归还执行权限）\n     *\n     * 执行逻辑：\n     * 1. 优先唤醒等待队列中的第一个等待者\n     * 2. 如果没有等待者，增加可用令牌数\n     *\n     * 这样确保令牌总数始终保持不变\n     */\n    release() {\n        // 情况1：有等待者，立即唤醒第一个\n        if (this.waiters.length > 0) {\n            // 取出队列头部的 resolve 函数\n            const resolve = this.waiters.shift();\n            // 调用 resolve，唤醒对应的 acquire() 调用\n            resolve();\n            // 注意：这里不增加 available，因为令牌直接转给了等待者\n        }\n        // 情况2：没有等待者，归还令牌到令牌池\n        else {\n            // 增加可用令牌数\n            this.available++;\n        }\n    }\n}\n\n/**\n * 路径工具\n */\nclass PathUtil {\n    /**\n     * 判断文件路径是否为隐藏文件（简化实现，仅判断是否以'.'开头）\n     * @param filePath 文件路径\n     */\n    static isHiddenFile(filePath) {\n        const name = path__namespace.basename(filePath);\n        // 空文件名或当前目录/上级目录\n        if (!name || name === '.' || name === '..') {\n            return false;\n        }\n        // 跨平台检查：以 . 开头的文件\n        return name.startsWith('.');\n    }\n}\n\n/**\n * 正则工具\n */\nclass RegExpUtil {\n    /**\n     * 测试 val 是否符合 testRegs 规则\n     * @param testRegs 正则规则\n     * @param val 值\n     */\n    static tests(testRegs, val) {\n        return testRegs.some(pattern => pattern.test(val));\n    }\n}\n\nclass BaseScene {\n    /**\n     * 已处理的硬链接\n     */\n    processedInodes = new Set();\n    /**\n     * 检查是否应该忽略指定路径\n     * @param ignores 忽略列表\n     * @param itemPath 项目路径\n     * @param includeHidden 是否包含隐藏文件\n     * @returns 是否应该忽略\n     */\n    shouldIgnorePath(ignores, itemPath, includeHidden = true) {\n        // 检查隐藏文件\n        if (!includeHidden && PathUtil.isHiddenFile(itemPath)) {\n            return true;\n        }\n        if (ignores && ignores.length > 0) {\n            // 检查忽略模式\n            return RegExpUtil.tests(ignores, itemPath);\n        }\n        return false;\n    }\n    /**\n     * 获取inode关键值，如果stats为字符串让直接返回\n     * @param stats fs统计信息\n     */\n    getInodeKey(stats) {\n        if (typeof stats === \"string\") {\n            return stats;\n        }\n        return `${stats.dev}-${stats.ino}`;\n    }\n    /**\n     * 判断是否已有 inode\n     * @param inode inode\n     */\n    hasInode(inode) {\n        return this.processedInodes.has(this.getInodeKey(inode));\n    }\n    /**\n     * 添加 inode\n     * @param inode inode\n     */\n    addInode(inode) {\n        this.processedInodes.add(this.getInodeKey(inode));\n    }\n    /**\n     * 检查 inode，用于防止硬链接重复\n     *\n     * 如果已有inode将返回true，否则记录inode并返回false\n     * @param stats fs统计信息\n     */\n    checkInode(stats) {\n        const inodeKey = this.getInodeKey(stats);\n        if (this.hasInode(inodeKey)) {\n            return true;\n        }\n        this.addInode(inodeKey);\n        return false;\n    }\n    /**\n     * 清除 inode\n     */\n    clearInode() {\n        this.processedInodes.clear();\n    }\n}\n\n/**\n * 文件夹大小计算器类\n */\nclass FolderSize extends BaseScene {\n    options;\n    /**\n     * 快捷获取文件夹大小\n     * @param folderPath 文件夹路径\n     * @param options 大小计算选项\n     * @returns 文件夹大小结果 Promise\n     */\n    static getSize(folderPath, options = {}) {\n        return FolderSize.of(options).size(folderPath);\n    }\n    /**\n     * 与构造函数一致\n     * @param options 大小计算选项\n     */\n    static of(options = {}) {\n        return new FolderSize(options);\n    }\n    /**\n     * 构造函数\n     * @param options 大小计算选项\n     */\n    constructor(options = {}) {\n        super();\n        this.options = {\n            maxDepth: Number.MAX_SAFE_INTEGER,\n            ignores: [],\n            includeHidden: true,\n            includeLink: true,\n            concurrency: 2,\n            ignoreErrors: false,\n            inodeCheck: true,\n            // 默认继续\n            onError: () => true,\n            ...options\n        };\n    }\n    /**\n     * 计算文件夹大小\n     * @param folderPath 文件夹路径\n     * @returns 文件夹大小结果 Promise\n     */\n    async size(folderPath) {\n        this.clearInode();\n        const normalizePath = path__namespace.normalize(folderPath);\n        // 使用 Node.js 实现\n        return await this.calculateSizeNodeJs(normalizePath);\n    }\n    /**\n     * 计算文件夹大小\n     * @param folderPath 文件夹路径\n     * @returns 计算结果\n     */\n    async calculateSizeNodeJs(folderPath) {\n        let totalSize = new bignumber_js.BigNumber(0);\n        let fileCount = 0;\n        let directoryCount = 0;\n        let linkCount = 0;\n        /**\n         * 递归处理文件夹项目\n         * @param itemPath 项目路径\n         * @param depth 当前深度\n         */\n        const processItem = async (itemPath, depth = 0) => {\n            // 检查是否应该忽略此路径\n            if (this.shouldIgnorePath(this.options.ignores, itemPath, this.options.includeHidden)) {\n                return;\n            }\n            let stats;\n            try {\n                // 获取文件统计信息\n                stats = await fs.promises.lstat(itemPath, { bigint: true });\n            }\n            catch (error) {\n                return this.handleError(error, `无法获取文件信息: ${error.message}`, itemPath);\n            }\n            if (this.options.inodeCheck) {\n                if (this.checkInode(stats))\n                    return;\n            }\n            const isSymbolicLink = stats.isSymbolicLink();\n            const isDirectory = stats.isDirectory();\n            const isFile = stats.isFile();\n            const fileSize = stats.size;\n            if (isSymbolicLink) {\n                linkCount++;\n                if (this.options.includeLink) {\n                    totalSize = totalSize.plus(fileSize.toString());\n                }\n            }\n            else {\n                totalSize = totalSize.plus(fileSize.toString());\n            }\n            if (isDirectory) {\n                // 检查文件夹深度限制，只在递归进入子目录前检查\n                if (depth > this.options.maxDepth) {\n                    return;\n                }\n                if (itemPath !== folderPath) {\n                    // 排除当前文件夹\n                    directoryCount++;\n                }\n                let entries;\n                try {\n                    // 读取目录内容\n                    entries = await fs.promises.readdir(itemPath);\n                }\n                catch (error) {\n                    return this.handleError(error, `无法读取目录: ${error.message}`, itemPath);\n                }\n                // 简化的并发控制\n                const semaphore = new SimpleSemaphore(this.options.concurrency);\n                await Promise.all(entries.map(async (entry) => {\n                    await semaphore.acquire();\n                    try {\n                        const childPath = path$1.join(itemPath, entry);\n                        await processItem(childPath, depth + 1);\n                    }\n                    catch (error) {\n                        throw error;\n                    }\n                    finally {\n                        semaphore.release();\n                    }\n                }));\n            }\n            else if (isFile) {\n                fileCount++;\n            }\n        };\n        await processItem(folderPath);\n        return {\n            size: totalSize,\n            fileCount,\n            directoryCount,\n            linkCount\n        };\n    }\n    /**\n     * 处理错误\n     * @param error 错误对象\n     * @param message 错误消息\n     * @param path 错误路径\n     */\n    handleError(error, message, path) {\n        const errorRes = { error, message, path };\n        // 如果设置了错误回调，调用它\n        if (this.options.onError) {\n            const shouldContinue = this.options.onError(errorRes);\n            if (!shouldContinue) {\n                throw new Error(`计算被用户停止: ${message}`);\n            }\n        }\n        if (!this.options.ignoreErrors) {\n            throw new Error(message);\n        }\n    }\n}\n\n/**\n * 文件系统工具类\n * 提供常用的文件系统操作辅助功能\n */\nclass FileSystemUtils {\n    /**\n     * 格式化文件大小为人类可读的字符串\n     * @param bytes 字节大小\n     * @param decimals 小数位数\n     * @returns 格式化后的大小字符串\n     */\n    static formatFileSize(bytes, decimals = 2) {\n        if (!bytes) {\n            return '0 Bytes';\n        }\n        if (typeof bytes === 'string') {\n            if (bytes.length === 0 || bytes.trim().length === 0) {\n                return '0 Bytes';\n            }\n        }\n        const size = new bignumber_js.BigNumber(bytes);\n        // 如果大小为0，直接返回\n        if (size.isZero()) {\n            return '0 Bytes';\n        }\n        const k = new bignumber_js.BigNumber(1024);\n        const dm = decimals < 0 ? 0 : decimals;\n        const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];\n        // 计算单位级别\n        let i = 0;\n        let tempSize = size;\n        while (tempSize.gte(k) && i < sizes.length - 1) {\n            tempSize = tempSize.div(k);\n            i++;\n        }\n        // 计算最终结果\n        const result = size.div(k.pow(i));\n        return result.toFixed(dm) + ' ' + sizes[i];\n    }\n    /**\n     * 获取路径的相对路径\n     * @param basePath 基础路径\n     * @param targetPath 目标路径\n     * @returns 相对路径\n     */\n    static getRelativePath(basePath, targetPath) {\n        const normalize = (path) => path.replace(/[\\\\\\/]+/g, '/');\n        const base = normalize(basePath);\n        const target = normalize(targetPath);\n        if (target.startsWith(base)) {\n            const relative = target.substring(base.length);\n            return relative.startsWith('/') ? relative.substring(1) : relative;\n        }\n        return target;\n    }\n    /**\n     * 验证路径是否安全（防止路径遍历攻击）\n     * @param path 要验证的路径\n     * @returns 是否安全\n     */\n    static isPathSafe(path) {\n        // 检查路径遍历攻击模式\n        const dangerousPatterns = [\n            /\\.\\.\\//, // ../\n            /\\.\\.\\\\/, // ..\\\n            /^\\/+/, // 绝对路径\n            /^[a-zA-Z]:\\\\/ // Windows 绝对路径\n        ];\n        return !dangerousPatterns.some(pattern => pattern.test(path));\n    }\n}\n\nexports.FileSystemUtils = FileSystemUtils;\nexports.FolderSize = FolderSize;\nexports.SimpleSemaphore = SimpleSemaphore;\n"]}