commit f74d8990cb23ccf905d78fdabd0803017dcf89bf Author: windychen Date: Wed May 27 14:28:02 2026 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d8e09c --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Dependencies +node_modules/ + +# Build output +dist/ + +# OS files +.DS_Store +Thumbs.db + +# IDE +.vscode/ +.idea/ +*.swp +*.swo + +# Logs +*.log +npm-debug.log* + +# Environment +.env +.env.local diff --git a/.memory-bank/2026-05-25-session.md b/.memory-bank/2026-05-25-session.md new file mode 100644 index 0000000..8b0bebc --- /dev/null +++ b/.memory-bank/2026-05-25-session.md @@ -0,0 +1,173 @@ +# Windychen Utils 项目开发记录 + +**日期**: 2026-05-25 +**项目**: windychen-untils (v1.0.0) +**类型**: 轻量级 JavaScript 工具库 + +--- + +## 一、已完成功能模块 + +### 1. Object 扩展 (`object.js`) + +| 方法 | 功能 | 特性 | +|------|------|------| +| `getPro(path, defaultValue?)` | 安全获取嵌套属性 | 支持点分隔路径、特殊键名(含`.`)、混合路径、默认值回退 | +| `setPro(path, value)` | 设置嵌套路径值 | 自动创建中间对象,支持特殊键名 | + +**路径格式示例:** +```javascript +obj.getPro('a.b.c'); // 普通点分隔 +obj.getPro("['x.y'].z"); // 特殊键名 +obj.getPro("['a.b'].c['d']"); // 混合嵌套 +``` + +**优化点:** +- 提取 `_parsePath()` 公共函数消除重复代码 +- 使用正则 `\[['"]([^'"]+)['"]\]|[^.\[\]]+` 统一解析所有 key 格式 +- 最终代码量:26 行(原 47 行,精简 45%) + +--- + +### 2. Array 扩展 (`array.js`) + +6 个增强方法,均支持三种调用方式: + +| 方法 | 对应原生 | 说明 | +|------|---------|------| +| `findPro(a, b?)` | find() | 查找首个匹配项 | +| `filterPro(a, b?)` | filter() | 过滤所有匹配项 | +| `findIndexPro(a, b?)` | findIndex() | 返回索引 | +| `findLastPro(a, b?)` | findLast() | 从末尾查找 | +| **somePro(a, b?)** | some() | 任一满足 | +| **everyPro(a, b?)** | every() | 全部满足 | + +**三种调用模式:** +```javascript +// 模式1: 回调函数 +arr.findPro(item => item.id > 1); + +// 模式2: 单值精确匹配 +['aa','bb'].findPro('bb'); + +// 模式3: key-value 匹配(支持 getPro 嵌套路径) +arr.findPro('user.info.name', 'Alice'); +``` + +**优化点:** +- 提取 `_resolveMatcher()` 统一参数判断逻辑 +- 循环生成 6 个 Pro 方法,零重复代码 +- key-value 模式接入 `getPro` 支持深层路径访问 +- 处理 null/undefined 边界(`item != null && ...`) +- 最终代码量:12 行(原 64 行,精简 81%) + +--- + +### 3. Storage 存储 (`storage.js`) + +浏览器环境专用: + +| 类 | 存储后端 | 特点 | +|----|---------|------| +| `IDBStorage` | IndexedDB | 大容量存储 | +| `ILocalStorage` | localStorage + Map 缓存 | 兼容性好,启动时全量加载 | + +**自动选择策略:** +```javascript +window.indexedDB ? IDBStorage : (localStorage ? ILocalStorage : null) +``` + +**API:** +- `storage.set(key, value)` → Promise +- `storage.get(key, initValue)` → Promise + +--- + +## 二、工程化配置 + +### 构建系统 (Webpack) + +**配置文件**: `webpack.config.js`(单文件,多模式) + +```bash +npm run build # 全部 (CJS + ESM + UMD) +npm run build:cjs # CommonJS 格式 +npm run build:esm # ES Module 格式 +npm run build:umd # UMD 浏览器格式 +npm run dev # 开发模式 +``` + +**输出产物:** + +| 格式 | 文件 | 入口字段 | +|------|------|---------| +| CJS | dist/windychen-utils.cjs.js | main | +| ESM | dist/windychen-utils.esm.js | module | +| UMD | dist/windychen-utils.js | browser | + +**演进过程:** +1. 初始创建 3 个独立 webpack 配置文件 +2. 发现 `.esm.js` 后缀被 webpack-cli 误识别为 esm 加载器 +3. 重命名解决加载异常 +4. 发现 `experiments` 应在顶层而非 output 内 +5. **最终收敛为单文件 + --env 参数方案** + +--- + +### 项目结构 + +``` +e:\project\utils\ +├── index.js # 统一入口,聚合各模块 +├── object.js # Object 原型扩展 (getPro/setPro) +├── array.js # Array 原型扩展 (6个Pro方法) +├── storage.js # 浏览器存储封装 (IndexedDB/LS) +├── webpack.config.js # 打包配置 (单文件多模式) +├── package.json # 项目元信息 & 脚本 +├── .gitignore # Git 忽略规则 +├── test.js # Node/Bun 端测试 +├── index.html # 浏览器端测试页面 +├── README.md # 项目文档 +└── dist/ # 构建产物输出目录 +``` + +--- + +## 三、测试体系 + +### Node.js / Bun 测试 (`test.js`) +- 直接 require 源码运行 +- 彩色终端输出 (✓/✗) +- 覆盖全部 API 的核心场景 +- 失败时 process.exit(1) +- 命令: `npm test` + +### 浏览器测试 (`index.html`) +- 引入 dist/windychen-utils.js (UMD) +- 深色主题 UI 展示结果 +- 绿色通过 / 红色失败 +- 命令: `npm run build:umd && open index.html` + +**已修复 Bug:** +- array.js 中 `_resolveMatcher` 未处理 item 为 null/undefined 导致的 TypeError +- 修复: `item != null && item.getPro(...)` + +--- + +## 四、关键决策记录 + +1. **Prototype 扩展方式**: 直接扩展 Object/Array 原型,使用时无需导入,全局可用 +2. **路径解析设计**: 正则统一处理普通键和特殊键(含点号),避免分支逻辑 +3. **Array Pro 方法设计**: 参数重载(function/string+value/value)覆盖常见使用场景 +4. **Storage 自动降级**: IndexedDB → localStorage → null,最大化兼容性 +5. **Webpack 单配置**: 通过 --env format 参数控制输出,避免维护多个配置文件 + +--- + +## 五、待改进方向 + +- [ ] 添加单元测试框架(如 Jest/Vitest) +- [ ] 支持 TypeScript 类型声明 (.d.ts) +- [ ] Storage 模块添加 delete/clear 方法 +- [ ] 考虑添加更多工具方法(日期、字符串、数字等) +- [ ] CI/CD 自动化构建与发布 diff --git a/README.md b/README.md new file mode 100644 index 0000000..51b448d --- /dev/null +++ b/README.md @@ -0,0 +1,101 @@ +# Windychen Utils + +轻量级 JavaScript/TypeScript 工具库,提供对象、数组、存储等常用扩展方法。 + +## 安装 + +```bash +npm install windychen-untils +``` + +## 使用 + +### Node.js / Bun.js + +```javascript +require('windychen-untils'); + +// Object 扩展 +const obj = { a: { b: { c: 1 } } }; +obj.getPro('a.b.c'); // 1 +obj.setPro('x.y.z', 'hello'); + +// Array 扩展 +[{ id: '1' }, { id: '2' }].findPro('id', '2'); +``` + +### 浏览器 + +```html + +``` + +### ES Module + +```javascript +import from 'windychen-untils/dist/windychen-utils.esm.js'; +``` + +## API 参考 + +### Object + +| 方法 | 说明 | 示例 | +|------|------|------| +| `getPro(path, default?)` | 安全获取嵌套属性,支持特殊键名 | `obj.getPro('a.b.c')` / `obj.getPro("['x.y'].z")` | +| `setPro(path, value)` | 设置嵌套路径值,自动创建中间对象 | `obj.setPro('foo.bar', 1)` | + +**路径格式支持:** +- 普通点分隔:`'a.b.c'` +- 特殊键名:`"['key.with.dot']"` +- 混合:`"['a.b'].c['d.e']"` + +### Array + +| 方法 | 说明 | 示例 | +|------|------|------| +| `findPro(fn \| key, val?)` | 增强查找 | `arr.findPro('id', '2')` | +| `filterPro(fn \| key, val?)` | 增强过滤 | `arr.filterPro('user.name', 'Alice')` | +| `findIndexPro(fn \| key, val?)` | 增强索引查找 | `arr.findIndexPro('status', 1)` | +| `findLastPro(fn \| key, val?)` | 从末尾查找 | `arr.findLastPro('type', 'b')` | +| **somePro(fn \| key, val?)** | 任一匹配 | `arr.somePro('active', true)` | +| **everyPro(fn \| key, val?)** | 全部匹配 | `arr.everyPro('valid', true)` | + +**三种调用方式:** +```javascript +// 回调函数(同原生) +arr.findPro(item => item.id > 1); + +// 单值精确匹配 +['aa', 'bb'].findPro('bb'); + +// key-value 匹配(支持嵌套路径) +[{ user: { name: 'Bob' } }].findPro('user.name', 'Bob'); +``` + +### Storage(浏览器环境) + +自动选择存储后端: +- 支持 IndexedDB → 使用 `IDBStorage` +- 仅支持 localStorage → 使用 `ILocalStorage`(内存缓存) + +```javascript +import storage from 'windychen-untils'; + +await storage.set('key', { data: 123 }); +await storage.get('key', null); // { data: 123 } +``` + +## 构建 + +```bash +npm run build # 打包全部 (CJS + ESM + UMD) +npm run build:cjs # CommonJS +npm run build:esm # ES Module +npm run build:umd # UMD (浏览器) +npm test # 运行测试 +``` + +## License + +ISC diff --git a/array.js b/array.js new file mode 100644 index 0000000..48694ce --- /dev/null +++ b/array.js @@ -0,0 +1,46 @@ +/** + * 解析 Pro 方法的匹配器参数 + * @param {(Function|string|*)} a - 回调函数、属性键、或单值 + * @param {*=} b - 属性值(与 a 配合使用) + * @returns {function(*): boolean} 匹配函数 + * @private + */ +const _resolveMatcher = (a, b) => { + if (typeof a === 'function') return a; + if (typeof a === 'string' && b !== undefined) return (item) => item != null && item.getPro(a) === b; + return (item) => item === a; +}; + +/** @private @type {string[]} 支持增强方法的原始方法列表 */ +const _methods = ['find', 'filter', 'findIndex', 'findLast', 'some', 'every']; + +_methods.forEach((method) => { + /** + * 增强版数组遍历方法,支持三种调用模式 + * + * **模式1 - 回调函数**(同原生方法) + * @example + * arr.findPro(item => item.id > 1) + * arr.filterPro(item => item.active) + * + * **模式2 - 单值精确匹配** + * @example + * ['aa','bb','cc'].findPro('bb') + * [1,2,2,3].filterPro(2) + * + * **模式3 - key-value 匹配**(支持嵌套路径,通过 getPro 访问) + * @example + * [{ user: { name: 'Bob' } }].findPro('user.name', 'Bob') + * arr.filterPro('status', 1) + * + * @name ${method}Pro + * @memberof Array.prototype + * @method + * @param {(Function|string|*)} a - 回调函数、属性键、或单值 + * @param {*=} [b] - 属性值(当 a 为 string 时使用) + * @returns {*} 返回结果同对应原生方法 + */ + Array.prototype[`${method}Pro`] = function (a, b) { + return this[method](_resolveMatcher(a, b)); + }; +}); diff --git a/index.html b/index.html new file mode 100644 index 0000000..b0c8d70 --- /dev/null +++ b/index.html @@ -0,0 +1,120 @@ + + + + + Windychen Utils - 浏览器测试 + + + +

Windychen Utils 测试结果

+
+ + + + + diff --git a/index.js b/index.js new file mode 100644 index 0000000..0e6909b --- /dev/null +++ b/index.js @@ -0,0 +1,4 @@ +require('./object'); +require('./array'); + +try { require('./storage'); } catch (e) {} // 仅浏览器环境生效 diff --git a/object.js b/object.js new file mode 100644 index 0000000..6b30941 --- /dev/null +++ b/object.js @@ -0,0 +1,74 @@ +/** + * 获取值的类型字符串 + * @param {*} val - 任意值 + * @returns {string} 类型名称,如 'String' 'Number' 'Array' 'Null' 'Undefined' + * @example + * Object.getTypeString('hello') // 'String' + * Object.getTypeString(123) // 'Number' + * Object.getTypeString(null) // 'Null' + */ +Object.getTypeString = function (val) { + return Object.prototype.toString.call(val).replace(/\[object |]/g, ''); +}; + +/** + * 解析路径字符串为键数组 + * @param {string} path - 路径字符串,支持点分隔、特殊键名、混合格式 + * @returns {string[]} 键数组 + * @private + */ +const _parsePath = (path) => { + const keys = []; + const keyRegex = /\[['"]([^'"]+)['"]\]|[^.\[\]]+/g; + let match; + while ((match = keyRegex.exec(path)) !== null) { + keys.push(match[1] || match[0]); + } + return keys; +}; + +/** + * 安全获取对象嵌套属性 + * @param {string} path - 属性路径,支持多种格式: + * - 普通点分隔: 'a.b.c' + * - 特殊键名: "['key.with.dot']" + * - 混合: "['a.b'].c['d.e']" + * @param {*=} defaultValue - 路径不存在或值为 undefined 时返回的默认值 + * @returns {*} 找到的属性值或默认值 + * @example + * { a: { b: { c: 1 } } }.getPro('a.b.c') // 1 + * { a: { b: { c: 1 } } }.getPro('a.x.y', 'default') // 'default' + * { 'x.y': { z: 2 } }.getPro("['x.y'].z") // 2 + */ +Object.prototype.getPro = function (path, defaultValue) { + let result = this; + for (const key of _parsePath(path)) { + if (result == null) return defaultValue; + result = result[key]; + } + return result !== undefined ? result : defaultValue; +}; + +/** + * 设置对象嵌套路径值(自动创建中间对象) + * @param {string} path - 属性路径,格式同 getPro + * @param {*} value - 要设置的值 + * @returns {void} + * @example + * const obj = {}; + * obj.setPro('a.b.c', 1); // obj => { a: { b: { c: 1 } } } + * obj.setPro("['x.y'].z", 2); // obj => { a: {...}, 'x.y': { z: 2 } } + */ +Object.prototype.setPro = function (path, value) { + const keys = _parsePath(path); + let target = this; + + for (let i = 0; i < keys.length - 1; i++) { + if (target[keys[i]] == null || typeof target[keys[i]] !== 'object') { + target[keys[i]] = {}; + } + target = target[keys[i]]; + } + + target[keys[keys.length - 1]] = value; +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..58dc1ed --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "windychen-untils", + "version": "1.0.0", + "main": "dist/windychen-utils.cjs.js", + "module": "dist/windychen-utils.esm.js", + "browser": "dist/windychen-utils.js", + "scripts": { + "build": "webpack --mode production", + "build:cjs": "webpack --mode production --env format=cjs", + "build:esm": "webpack --mode production --env format=esm", + "build:umd": "webpack --mode production --env format=umd", + "dev": "webpack --mode development", + "test": "node test.js" + }, + "author": "windychen", + "license": "ISC", + "description": "", + "devDependencies": { + "webpack": "^5.90.0", + "webpack-cli": "^5.1.4" + } +} \ No newline at end of file diff --git a/storage.js b/storage.js new file mode 100644 index 0000000..b247bb1 --- /dev/null +++ b/storage.js @@ -0,0 +1,168 @@ +/** @type {Function} 日志输出 */ +var log = console.warn; + +/** + * 判断值是否为 String 类型 + * @param {*} str - 待检测值 + * @returns {boolean} + * @private + */ +var isString = function (str) { return Object.getTypeString(str) === 'String'; }; + +/** + * IndexedDB 存储实现(大容量存储优先选择) + * + * @class IDBStorage + * @example + * const storage = new IDBStorage('myDb', 'myStore', 1); + * await storage.set('key', { data: 123 }); + * await storage.get('key', null); + */ +class IDBStorage { + /** + * 创建 IndexedDB 存储实例 + * @param {string} [dbName='dbName'] - 数据库名称 + * @param {string} [storeName='storeName'] - 对象存储名称 + * @param {number} [version=1] - 数据库版本号 + */ + constructor(dbName, storeName, version) { + /** @type {number} 数据库版本号 */ + this.version = version || 1; + /** @type {string} 数据库名称 */ + this.dbName = dbName || 'dbName'; + /** @type {string} 对象存储名称 */ + this.storeName = storeName || 'storeName'; + + var request = indexedDB.open(this.dbName, this.version); + /** @type {Promise} 数据库连接 Promise */ + this.requestPromise = new Promise(function (resolve, reject) { + request.onupgradeneeded = function (e) { + if (e && e.target && !request.result.objectStoreNames.contains(this.storeName)) { + request.result.createObjectStore(this.storeName, { keyPath: 'key' }) + .createIndex('key', 'key', { unique: false }); + } + log('[Index][open]-upgrade'); + resolve(request.result); + }.bind(this); + request.onsuccess = function () { log('[IndexDB][open]-success'); resolve(request.result); }; + request.onerror = function (e) { log('[IndexDB][open]-error', 2); reject(e); }; + }.bind(this)); + } + + /** + * 获取存储值 + * @template T + * @param {string} key - 键名 + * @param {T} initValue - 默认值(未找到时返回) + * @returns {Promise} 存储的值或默认值 + */ + get(key, initValue) { + var _this = this; + return new Promise(async function (resolve) { + var db = await _this.requestPromise; + var transaction = db.transaction(_this.storeName, 'readonly'); + var objectStore = transaction.objectStore(_this.storeName); + var req = objectStore.get(key); + req.onsuccess = function () { resolve(req.result ? req.result.value : (initValue || null)); }; + req.onerror = function (e) { log('[indexDB][get]-error', 2, e); resolve(initValue || null); }; + }); + } + + /** + * 设置存储值 + * @template T + * @param {string} key - 键名 + * @param {T} value - 要存储的值 + * @returns {Promise} 返回写入的值 + */ + set(key, value) { + var _this = this; + return new Promise(async function (resolve) { + var db = await _this.requestPromise; + var transaction = db.transaction(_this.storeName, 'readwrite'); + var objectStore = transaction.objectStore(_this.storeName); + var req = objectStore.put({ key: key, value: value }); + req.onsuccess = function () { resolve(value); }; + req.onerror = function (e) { log('[indexDB][set]-error', 2, e); resolve(value); }; + }); + } +} + +/** + * localStorage 存储实现(兼容性好,带内存缓存) + * + * @class ILocalStorage + * @example + * const storage = new ILocalStorage(); + * await storage.set('key', { data: 456 }); + * await storage.get('key', null); + */ +class ILocalStorage { + constructor() { + /** @type {Map} 内存缓存 */ + this.cache = new Map(); + this.load(); + } + + /** 从 localStorage 全量加载到缓存 */ + load() { + var _this = this; + Object.entries(localStorage).forEach(function (entry) { + var key = entry[0], value = entry[1]; + try { + _this.cache.set(key, JSON.parse(value)); + } catch (error) { + log('[localStorage][load]-error', 2, error, key, value); + } + }); + } + + /** + * 从缓存获取值 + * @template T + * @param {string} key - 键名 + * @param {T} initValue - 默认值 + * @returns {Promise} 缓存的值或默认值 + */ + get(key, initValue) { + return new Promise(function (resolve) { + resolve(this.cache.get(key) !== undefined ? this.cache.get(key) : initValue); + }.bind(this)); + } + + /** + * 写入 localStorage 并更新缓存 + * @template T + * @param {string} key - 键名 + * @param {T} value - 要存储的值 + * @returns {Promise} 返回写入的值 + */ + set(key, value) { + return new Promise(function (resolve) { + var _value = isString(value) ? value : ''; + try { + _value = JSON.stringify(value); + } catch (e) { + log('[localStorage][set]-error', 2, e); + } + localStorage.setItem(key, _value); + this.cache.set(key, _value); + resolve(value); + }.bind(this)); + } +} + +// 浏览器环境自动选择存储方式 +if (typeof window !== 'undefined') { + /** + * 当前环境可用的存储类(IDBStorage 或 ILocalStorage) + * @type {Function|null} + * @global + */ + window.IStorage = window.indexedDB ? IDBStorage : (window.localStorage ? ILocalStorage : null); + if (typeof module !== 'undefined') { + module.exports = new window.IStorage(); + } +} else if (typeof module !== 'undefined') { + module.exports = null; +} diff --git a/test.js b/test.js new file mode 100644 index 0000000..ddadf89 --- /dev/null +++ b/test.js @@ -0,0 +1,67 @@ +require('./index'); + +let passed = 0; +let failed = 0; + +function assert(desc, condition) { + if (condition) { + console.log(`\x1b[32m ✓ ${desc}\x1b[0m`); + passed++; + } else { + console.log(`\x1b[31m ✗ ${desc}\x1b[0m`); + failed++; + } +} + +function group(name) { + console.log(`\n\x1b[36m─── ${name} ───\x1b[0m`); +} + +// ===== Object.getPro ===== +group('Object.getPro'); +const obj = { a: { b: { c: 1 } }, 'x.y': { z: 2 } }; +assert("getPro('a.b.c') === 1", obj.getPro('a.b.c') === 1); +assert("getPro('a.b.d', 'default') === 'default'", obj.getPro('a.b.d', 'default') === 'default'); +assert("getPro(\"['x.y'].z\") === 2", obj.getPro("['x.y'].z") === 2); +assert("getPro('missing', 42) === 42", obj.getPro('missing', 42) === 42); + +// ===== Object.setPro ===== +group('Object.setPro'); +const obj2 = {}; +obj2.setPro('foo.bar.baz', 'hello'); +assert("setPro 嵌套赋值", obj2.foo.bar.baz === 'hello'); +obj2.setPro("['a.b'].c", 99); +assert("setPro 特殊键名", obj2['a.b'].c === 99); + +// ===== Array Pro 方法 ===== +const arr = [ + { user: { name: 'Alice' } }, + { user: { name: 'Bob' } }, + null, + { user: { name: 'Charlie' } }, +]; + +group('Array.findPro'); +assert("回调 findPro(t=>t>1)", [1, 2, 3].findPro((t) => t > 1) === 2); +assert("key-value findPro('user.name','Bob')", arr.findPro('user.name', 'Bob').user.name === 'Bob'); +assert("单值 findPro('cc')", ['aa', 'bb', 'cc'].findPro('cc') === 'cc'); + +group('Array.filterPro'); +assert("key-value filterPro", arr.filterPro('user.name', 'Alice').length === 1); +assert("单值 filterPro(2)", [1, 2, 2, 3].filterPro(2).length === 2); + +group('Array.findIndexPro'); +assert("findIndexPro", arr.findIndexPro('user.name', 'Charlie') === 3); + +group('Array.findLastPro'); +assert("findLastPro", arr.findLastPro('user.name', 'Bob').user.name === 'Bob'); + +group('Array.somePro / everyPro'); +assert("somePro", arr.somePro('user.name', 'Alice') === true); +assert("everyPro false", arr.everyPro('user.name', 'Alice') === false); +assert("everyPro true", ['a', 'a'].everyPro('a') === true); + +// 汇总 +console.log(`\n\x1b[33m共 ${passed + failed} 项,${passed} 通过,${failed} 失败\x1b[0m`); + +process.exit(failed > 0 ? 1 : 0); diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..cf1c28a --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,44 @@ +const path = require('path'); + +const configs = { + cjs: { + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'windychen-utils.cjs.js', + libraryTarget: 'commonjs2', + }, + }, + esm: { + experiments: { outputModule: true }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'windychen-utils.esm.js', + libraryTarget: 'module', + }, + }, + umd: { + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'windychen-utils.js', + library: { name: 'WindychenUtils', type: 'umd', export: 'default' }, + }, + }, +}; + +module.exports = (env = {}) => { + const format = env.format; + + if (!format || format === 'all') { + return Object.keys(configs).map((key) => ({ + name: key, + entry: './index.js', + ...configs[key], + })); + } + + if (!configs[format]) { + throw new Error(`不支持的格式: ${format},可选值: cjs, esm, umd`); + } + + return { entry: './index.js', ...configs[format] }; +};