@simplysm/core-node 13.0.0-beta.45 → 13.0.0-beta.47
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/features/fs-watcher.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/utils/fs.js.map +0 -1
- package/dist/utils/path.js.map +0 -1
- package/dist/worker/create-worker.js.map +0 -1
- package/dist/worker/types.js.map +0 -1
- package/dist/worker/worker.js.map +0 -1
- package/package.json +4 -3
- package/src/features/fs-watcher.ts +176 -0
- package/src/index.ts +11 -0
- package/src/utils/fs.ts +550 -0
- package/src/utils/path.ts +128 -0
- package/src/worker/create-worker.ts +141 -0
- package/src/worker/types.ts +86 -0
- package/src/worker/worker.ts +209 -0
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/features/fs-watcher.ts"],
|
|
4
|
-
"sourcesContent": ["import { DebounceQueue } from \"@simplysm/core-common\";\nimport * as chokidar from \"chokidar\";\nimport consola from \"consola\";\nimport type { EventName } from \"chokidar/handler.js\";\nimport { type NormPath, pathNorm } from \"../utils/path\";\n\n//#region Types\n\n/**\n * \uC9C0\uC6D0\uD558\uB294 \uD30C\uC77C \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uD0C0\uC785 \uBAA9\uB85D.\n */\nconst FS_WATCHER_EVENTS = [\"add\", \"addDir\", \"change\", \"unlink\", \"unlinkDir\"] as const;\n\n/**\n * \uD30C\uC77C \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uD0C0\uC785.\n */\nexport type FsWatcherEvent = (typeof FS_WATCHER_EVENTS)[number];\n\n/**\n * \uD30C\uC77C \uBCC0\uACBD \uC815\uBCF4.\n */\nexport interface FsWatcherChangeInfo {\n /** \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uD0C0\uC785 */\n event: FsWatcherEvent;\n /** \uBCC0\uACBD\uB41C \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC \uACBD\uB85C (\uC815\uADDC\uD654\uB428) */\n path: NormPath;\n}\n\n//#endregion\n\n//#region FsWatcher\n\n/**\n * chokidar \uAE30\uBC18 \uD30C\uC77C \uC2DC\uC2A4\uD15C \uAC10\uC2DC \uB798\uD37C.\n * \uC9E7\uC740 \uC2DC\uAC04 \uB0B4 \uBC1C\uC0DD\uD55C \uC774\uBCA4\uD2B8\uB97C \uBCD1\uD569\uD558\uC5EC \uCF5C\uBC31 \uD638\uCD9C.\n *\n * **\uC8FC\uC758**: chokidar\uC758 `ignoreInitial` \uC635\uC158\uC740 \uB0B4\uBD80\uC801\uC73C\uB85C \uD56D\uC0C1 `true`\uB85C \uC124\uC815\uB41C\uB2E4.\n * `options.ignoreInitial: false`\uB97C \uC804\uB2EC\uD558\uBA74 `onChange` \uCCAB \uD638\uCD9C \uC2DC \uBE48 \uBC30\uC5F4\uB85C\n * \uCF5C\uBC31\uC774 \uD638\uCD9C\uB418\uC9C0\uB9CC, \uC2E4\uC81C \uCD08\uAE30 \uD30C\uC77C \uBAA9\uB85D\uC740 \uD3EC\uD568\uB418\uC9C0 \uC54A\uB294\uB2E4.\n * \uC774\uB294 \uC774\uBCA4\uD2B8 \uBCD1\uD569 \uB85C\uC9C1\uACFC\uC758 \uCDA9\uB3CC\uC744 \uBC29\uC9C0\uD558\uAE30 \uC704\uD55C \uC758\uB3C4\uB41C \uB3D9\uC791\uC774\uB2E4.\n *\n * @example\n * const watcher = await FsWatcher.watch([\"src/**\\/*.ts\"]);\n * watcher.onChange({ delay: 300 }, (changes) => {\n * for (const { path, event } of changes) {\n * console.log(`${event}: ${path}`);\n * }\n * });\n *\n * // \uC885\uB8CC\n * await watcher.close();\n */\nexport class FsWatcher {\n /**\n * \uD30C\uC77C \uAC10\uC2DC \uC2DC\uC791 (\uBE44\uB3D9\uAE30).\n * ready \uC774\uBCA4\uD2B8\uAC00 \uBC1C\uC0DD\uD560 \uB54C\uAE4C\uC9C0 \uB300\uAE30.\n *\n * @param paths - \uAC10\uC2DC\uD560 \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC \uACBD\uB85C \uB610\uB294 glob \uD328\uD134 \uBC30\uC5F4\n * @param options - chokidar \uC635\uC158\n */\n static async watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher> {\n return new Promise<FsWatcher>((resolve, reject) => {\n const watcher = new FsWatcher(paths, options);\n watcher._watcher.on(\"ready\", () => {\n resolve(watcher);\n });\n watcher._watcher.on(\"error\", reject);\n });\n }\n\n private readonly _watcher: chokidar.FSWatcher;\n private readonly _ignoreInitial: boolean = true;\n private readonly _debounceQueues: DebounceQueue[] = [];\n\n private readonly _logger = consola.withTag(\"sd-fs-watcher\");\n\n private constructor(paths: string[], options?: chokidar.ChokidarOptions) {\n this._watcher = chokidar.watch(paths, {\n persistent: true,\n ...options,\n ignoreInitial: true,\n });\n this._ignoreInitial = options?.ignoreInitial ?? this._ignoreInitial;\n\n // \uAC10\uC2DC \uC911 \uBC1C\uC0DD\uD558\uB294 \uC5D0\uB7EC \uB85C\uAE45\n this._watcher.on(\"error\", (err) => {\n this._logger.error(\"FsWatcher error:\", err);\n });\n }\n\n /**\n * \uD30C\uC77C \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uD578\uB4E4\uB7EC \uB4F1\uB85D.\n * \uC9C0\uC815\uB41C delay \uC2DC\uAC04 \uB3D9\uC548 \uC774\uBCA4\uD2B8\uB97C \uBAA8\uC544\uC11C \uD55C \uBC88\uC5D0 \uCF5C\uBC31 \uD638\uCD9C.\n *\n * @param opt.delay - \uC774\uBCA4\uD2B8 \uBCD1\uD569 \uB300\uAE30 \uC2DC\uAC04 (ms)\n * @param cb - \uBCC0\uACBD \uC774\uBCA4\uD2B8 \uCF5C\uBC31\n */\n onChange(opt: { delay?: number }, cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>): this {\n const fnQ = new DebounceQueue(opt.delay);\n this._debounceQueues.push(fnQ);\n\n let changeInfoMap = new Map<string, EventName>();\n\n // ignoreInitial\uC774 false\uBA74 \uCD08\uAE30\uC5D0 \uBE48 \uBC30\uC5F4\uB85C \uCF5C\uBC31 \uD638\uCD9C\n if (!this._ignoreInitial) {\n fnQ.run(async () => {\n await cb([]);\n });\n }\n\n this._watcher.on(\"all\", (event, filePath) => {\n // \uC9C0\uC6D0\uD558\uB294 \uC774\uBCA4\uD2B8\uB9CC \uCC98\uB9AC\n if (!FS_WATCHER_EVENTS.includes(event as FsWatcherEvent)) return;\n\n /*\n * \uC774\uBCA4\uD2B8 \uBCD1\uD569 \uC804\uB7B5:\n * \uC9E7\uC740 \uC2DC\uAC04 \uB0B4 \uAC19\uC740 \uD30C\uC77C\uC5D0 \uB300\uD574 \uC5EC\uB7EC \uC774\uBCA4\uD2B8\uAC00 \uBC1C\uC0DD\uD558\uBA74 \uCD5C\uC885 \uC0C1\uD0DC\uB9CC \uC804\uB2EC\uD55C\uB2E4.\n * - add + change \u2192 add (\uC0DD\uC131 \uC9C1\uD6C4 \uC218\uC815\uC740 \uC0DD\uC131\uC73C\uB85C \uAC04\uC8FC)\n * - add + unlink \u2192 \uC0AD\uC81C (\uC0DD\uC131 \uD6C4 \uC989\uC2DC \uC0AD\uC81C\uB294 \uBCC0\uACBD \uC5C6\uC74C)\n * - unlink + add \u2192 add (\uC0AD\uC81C \uD6C4 \uC7AC\uC0DD\uC131\uC740 \uC0DD\uC131\uC73C\uB85C \uAC04\uC8FC)\n * - \uADF8 \uC678 \u2192 \uCD5C\uC2E0 \uC774\uBCA4\uD2B8\uB85C \uB36E\uC5B4\uC500\n */\n if (!changeInfoMap.has(filePath)) {\n changeInfoMap.set(filePath, event);\n }\n const prevEvent = changeInfoMap.get(filePath)!;\n\n if (prevEvent === \"add\" && event === \"change\") {\n // add \uD6C4 change \u2192 add \uC720\uC9C0\n changeInfoMap.set(filePath, \"add\");\n } else if ((prevEvent === \"add\" && event === \"unlink\") || (prevEvent === \"addDir\" && event === \"unlinkDir\")) {\n // add \uD6C4 unlink \u2192 \uBCC0\uACBD \uC5C6\uC74C (\uC0AD\uC81C)\n changeInfoMap.delete(filePath);\n } else if (prevEvent === \"unlink\" && (event === \"add\" || event === \"change\")) {\n // unlink \uD6C4 add/change \u2192 add (\uD30C\uC77C \uC7AC\uC0DD\uC131)\n changeInfoMap.set(filePath, \"add\");\n } else if (prevEvent === \"unlinkDir\" && event === \"addDir\") {\n // unlinkDir \uD6C4 addDir \u2192 addDir (\uB514\uB809\uD1A0\uB9AC \uC7AC\uC0DD\uC131)\n changeInfoMap.set(filePath, \"addDir\");\n } else {\n changeInfoMap.set(filePath, event);\n }\n\n fnQ.run(async () => {\n if (changeInfoMap.size === 0) return;\n\n const currChangeInfoMap = changeInfoMap;\n changeInfoMap = new Map<string, EventName>();\n\n const changeInfos = Array.from(currChangeInfoMap.entries()).map(\n ([path, evt]): FsWatcherChangeInfo => ({\n path: pathNorm(path),\n event: evt as FsWatcherEvent,\n }),\n );\n\n await cb(changeInfos);\n });\n });\n\n return this;\n }\n\n /**\n * \uD30C\uC77C \uAC10\uC2DC \uC885\uB8CC.\n */\n async close(): Promise<void> {\n for (const q of this._debounceQueues) {\n q.dispose();\n }\n this._debounceQueues.length = 0;\n await this._watcher.close();\n }\n}\n\n//#endregion\n"],
|
|
5
4
|
"mappings": "AAAA,SAAS,qBAAqB;AAC9B,YAAY,cAAc;AAC1B,OAAO,aAAa;AAEpB,SAAwB,gBAAgB;AAOxC,MAAM,oBAAoB,CAAC,OAAO,UAAU,UAAU,UAAU,WAAW;AAyCpE,MAAM,UAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrB,aAAa,MAAM,OAAiB,SAAwD;AAC1F,WAAO,IAAI,QAAmB,CAAC,SAAS,WAAW;AACjD,YAAM,UAAU,IAAI,UAAU,OAAO,OAAO;AAC5C,cAAQ,SAAS,GAAG,SAAS,MAAM;AACjC,gBAAQ,OAAO;AAAA,MACjB,CAAC;AACD,cAAQ,SAAS,GAAG,SAAS,MAAM;AAAA,IACrC,CAAC;AAAA,EACH;AAAA,EAEiB;AAAA,EACA,iBAA0B;AAAA,EAC1B,kBAAmC,CAAC;AAAA,EAEpC,UAAU,QAAQ,QAAQ,eAAe;AAAA,EAElD,YAAY,OAAiB,SAAoC;AACvE,SAAK,WAAW,SAAS,MAAM,OAAO;AAAA,MACpC,YAAY;AAAA,MACZ,GAAG;AAAA,MACH,eAAe;AAAA,IACjB,CAAC;AACD,SAAK,iBAAiB,SAAS,iBAAiB,KAAK;AAGrD,SAAK,SAAS,GAAG,SAAS,CAAC,QAAQ;AACjC,WAAK,QAAQ,MAAM,oBAAoB,GAAG;AAAA,IAC5C,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,KAAyB,IAAwE;AACxG,UAAM,MAAM,IAAI,cAAc,IAAI,KAAK;AACvC,SAAK,gBAAgB,KAAK,GAAG;AAE7B,QAAI,gBAAgB,oBAAI,IAAuB;AAG/C,QAAI,CAAC,KAAK,gBAAgB;AACxB,UAAI,IAAI,YAAY;AAClB,cAAM,GAAG,CAAC,CAAC;AAAA,MACb,CAAC;AAAA,IACH;AAEA,SAAK,SAAS,GAAG,OAAO,CAAC,OAAO,aAAa;AAE3C,UAAI,CAAC,kBAAkB,SAAS,KAAuB,EAAG;AAU1D,UAAI,CAAC,cAAc,IAAI,QAAQ,GAAG;AAChC,sBAAc,IAAI,UAAU,KAAK;AAAA,MACnC;AACA,YAAM,YAAY,cAAc,IAAI,QAAQ;AAE5C,UAAI,cAAc,SAAS,UAAU,UAAU;AAE7C,sBAAc,IAAI,UAAU,KAAK;AAAA,MACnC,WAAY,cAAc,SAAS,UAAU,YAAc,cAAc,YAAY,UAAU,aAAc;AAE3G,sBAAc,OAAO,QAAQ;AAAA,MAC/B,WAAW,cAAc,aAAa,UAAU,SAAS,UAAU,WAAW;AAE5E,sBAAc,IAAI,UAAU,KAAK;AAAA,MACnC,WAAW,cAAc,eAAe,UAAU,UAAU;AAE1D,sBAAc,IAAI,UAAU,QAAQ;AAAA,MACtC,OAAO;AACL,sBAAc,IAAI,UAAU,KAAK;AAAA,MACnC;AAEA,UAAI,IAAI,YAAY;AAClB,YAAI,cAAc,SAAS,EAAG;AAE9B,cAAM,oBAAoB;AAC1B,wBAAgB,oBAAI,IAAuB;AAE3C,cAAM,cAAc,MAAM,KAAK,kBAAkB,QAAQ,CAAC,EAAE;AAAA,UAC1D,CAAC,CAAC,MAAM,GAAG,OAA4B;AAAA,YACrC,MAAM,SAAS,IAAI;AAAA,YACnB,OAAO;AAAA,UACT;AAAA,QACF;AAEA,cAAM,GAAG,WAAW;AAAA,MACtB,CAAC;AAAA,IACH,CAAC;AAED,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAuB;AAC3B,eAAW,KAAK,KAAK,iBAAiB;AACpC,QAAE,QAAQ;AAAA,IACZ;AACA,SAAK,gBAAgB,SAAS;AAC9B,UAAM,KAAK,SAAS,MAAM;AAAA,EAC5B;AACF;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["// Utils\nexport * from \"./utils/fs\";\nexport * from \"./utils/path\";\n\n// Features\nexport * from \"./features/fs-watcher\";\n\n// Worker\nexport * from \"./worker/types\";\nexport * from \"./worker/worker\";\nexport * from \"./worker/create-worker\";\n"],
|
|
5
4
|
"mappings": "AACA,cAAc;AACd,cAAc;AAGd,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/dist/utils/fs.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/fs.ts"],
|
|
4
|
-
"sourcesContent": ["import path from \"path\";\nimport fs from \"fs\";\nimport os from \"os\";\nimport { glob as globRaw, type GlobOptions, globSync as globRawSync } from \"glob\";\nimport { jsonParse, jsonStringify, SdError } from \"@simplysm/core-common\";\nimport \"@simplysm/core-common\";\n\n//#region \uC874\uC7AC \uD655\uC778\n\n/**\n * \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC \uC874\uC7AC \uD655\uC778 (\uB3D9\uAE30).\n * @param targetPath - \uD655\uC778\uD560 \uACBD\uB85C\n */\nexport function fsExistsSync(targetPath: string): boolean {\n return fs.existsSync(targetPath);\n}\n\n/**\n * \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC \uC874\uC7AC \uD655\uC778 (\uBE44\uB3D9\uAE30).\n * @param targetPath - \uD655\uC778\uD560 \uACBD\uB85C\n */\nexport async function fsExists(targetPath: string): Promise<boolean> {\n try {\n await fs.promises.access(targetPath);\n return true;\n } catch {\n return false;\n }\n}\n\n//#endregion\n\n//#region \uB514\uB809\uD1A0\uB9AC \uC0DD\uC131\n\n/**\n * \uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 (recursive).\n * @param targetPath - \uC0DD\uC131\uD560 \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C\n */\nexport function fsMkdirSync(targetPath: string): void {\n try {\n fs.mkdirSync(targetPath, { recursive: true });\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uB514\uB809\uD1A0\uB9AC \uC0DD\uC131 (recursive, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC0DD\uC131\uD560 \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C\n */\nexport async function fsMkdir(targetPath: string): Promise<void> {\n try {\n await fs.promises.mkdir(targetPath, { recursive: true });\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n//#endregion\n\n//#region \uC0AD\uC81C\n\n/**\n * \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC \uC0AD\uC81C.\n * @param targetPath - \uC0AD\uC81C\uD560 \uACBD\uB85C\n * @remarks \uB3D9\uAE30 \uBC84\uC804\uC740 \uC7AC\uC2DC\uB3C4 \uC5C6\uC774 \uC989\uC2DC \uC2E4\uD328\uD568. \uD30C\uC77C \uC7A0\uAE08 \uB4F1 \uC77C\uC2DC\uC801 \uC624\uB958 \uAC00\uB2A5\uC131\uC774 \uC788\uB294 \uACBD\uC6B0 fsRm \uC0AC\uC6A9\uC744 \uAD8C\uC7A5\uD568.\n */\nexport function fsRmSync(targetPath: string): void {\n try {\n fs.rmSync(targetPath, { recursive: true, force: true });\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC \uC0AD\uC81C (\uBE44\uB3D9\uAE30).\n * @param targetPath - \uC0AD\uC81C\uD560 \uACBD\uB85C\n * @remarks \uBE44\uB3D9\uAE30 \uBC84\uC804\uC740 \uD30C\uC77C \uC7A0\uAE08 \uB4F1\uC758 \uC77C\uC2DC\uC801 \uC624\uB958\uC5D0 \uB300\uD574 \uCD5C\uB300 6\uD68C(500ms \uAC04\uACA9) \uC7AC\uC2DC\uB3C4\uD568.\n */\nexport async function fsRm(targetPath: string): Promise<void> {\n try {\n await fs.promises.rm(targetPath, {\n recursive: true,\n force: true,\n retryDelay: 500,\n maxRetries: 6,\n });\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n//#endregion\n\n//#region \uBCF5\uC0AC\n\n/**\n * \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC \uBCF5\uC0AC.\n *\n * sourcePath\uAC00 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC73C\uBA74 \uC544\uBB34 \uC791\uC5C5\uB3C4 \uC218\uD589\uD558\uC9C0 \uC54A\uACE0 \uBC18\uD658\uD55C\uB2E4.\n *\n * @param sourcePath \uBCF5\uC0AC\uD560 \uC6D0\uBCF8 \uACBD\uB85C\n * @param targetPath \uBCF5\uC0AC \uB300\uC0C1 \uACBD\uB85C\n * @param filter \uBCF5\uC0AC \uC5EC\uBD80\uB97C \uACB0\uC815\uD558\uB294 \uD544\uD130 \uD568\uC218.\n * \uAC01 \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC\uC758 **\uC808\uB300 \uACBD\uB85C**\uAC00 \uC804\uB2EC\uB418\uBA70,\n * true\uB97C \uBC18\uD658\uD558\uBA74 \uBCF5\uC0AC, false\uBA74 \uC81C\uC678.\n * **\uC8FC\uC758**: \uCD5C\uC0C1\uC704 sourcePath\uB294 \uD544\uD130 \uB300\uC0C1\uC774 \uC544\uB2C8\uBA70,\n * \uBAA8\uB4E0 \uD558\uC704 \uD56D\uBAA9(\uC790\uC2DD, \uC190\uC790 \uB4F1)\uC5D0 \uC7AC\uADC0\uC801\uC73C\uB85C filter \uD568\uC218\uAC00 \uC801\uC6A9\uB41C\uB2E4.\n * \uB514\uB809\uD1A0\uB9AC\uC5D0 false\uB97C \uBC18\uD658\uD558\uBA74 \uD574\uB2F9 \uB514\uB809\uD1A0\uB9AC\uC640 \uBAA8\uB4E0 \uD558\uC704 \uD56D\uBAA9\uC774 \uAC74\uB108\uB6F0\uC5B4\uC9D0.\n */\nexport function fsCopySync(sourcePath: string, targetPath: string, filter?: (absolutePath: string) => boolean): void {\n if (!fsExistsSync(sourcePath)) {\n return;\n }\n\n let stats: fs.Stats;\n try {\n stats = fs.lstatSync(sourcePath);\n } catch (err) {\n throw new SdError(err, sourcePath);\n }\n\n if (stats.isDirectory()) {\n fsMkdirSync(targetPath);\n\n const children = fsGlobSync(path.resolve(sourcePath, \"*\"), { dot: true });\n\n for (const childPath of children) {\n if (filter !== undefined && !filter(childPath)) {\n continue;\n }\n\n const relativeChildPath = path.relative(sourcePath, childPath);\n const childTargetPath = path.resolve(targetPath, relativeChildPath);\n fsCopySync(childPath, childTargetPath, filter);\n }\n } else {\n fsMkdirSync(path.dirname(targetPath));\n\n try {\n fs.copyFileSync(sourcePath, targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n }\n}\n\n/**\n * \uD30C\uC77C \uB610\uB294 \uB514\uB809\uD1A0\uB9AC \uBCF5\uC0AC (\uBE44\uB3D9\uAE30).\n *\n * sourcePath\uAC00 \uC874\uC7AC\uD558\uC9C0 \uC54A\uC73C\uBA74 \uC544\uBB34 \uC791\uC5C5\uB3C4 \uC218\uD589\uD558\uC9C0 \uC54A\uACE0 \uBC18\uD658\uD55C\uB2E4.\n *\n * @param sourcePath \uBCF5\uC0AC\uD560 \uC6D0\uBCF8 \uACBD\uB85C\n * @param targetPath \uBCF5\uC0AC \uB300\uC0C1 \uACBD\uB85C\n * @param filter \uBCF5\uC0AC \uC5EC\uBD80\uB97C \uACB0\uC815\uD558\uB294 \uD544\uD130 \uD568\uC218.\n * \uAC01 \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC\uC758 **\uC808\uB300 \uACBD\uB85C**\uAC00 \uC804\uB2EC\uB418\uBA70,\n * true\uB97C \uBC18\uD658\uD558\uBA74 \uBCF5\uC0AC, false\uBA74 \uC81C\uC678.\n * **\uC8FC\uC758**: \uCD5C\uC0C1\uC704 sourcePath\uB294 \uD544\uD130 \uB300\uC0C1\uC774 \uC544\uB2C8\uBA70,\n * \uBAA8\uB4E0 \uD558\uC704 \uD56D\uBAA9(\uC790\uC2DD, \uC190\uC790 \uB4F1)\uC5D0 \uC7AC\uADC0\uC801\uC73C\uB85C filter \uD568\uC218\uAC00 \uC801\uC6A9\uB41C\uB2E4.\n * \uB514\uB809\uD1A0\uB9AC\uC5D0 false\uB97C \uBC18\uD658\uD558\uBA74 \uD574\uB2F9 \uB514\uB809\uD1A0\uB9AC\uC640 \uBAA8\uB4E0 \uD558\uC704 \uD56D\uBAA9\uC774 \uAC74\uB108\uB6F0\uC5B4\uC9D0.\n */\nexport async function fsCopy(\n sourcePath: string,\n targetPath: string,\n filter?: (absolutePath: string) => boolean,\n): Promise<void> {\n if (!(await fsExists(sourcePath))) {\n return;\n }\n\n let stats: fs.Stats;\n try {\n stats = await fs.promises.lstat(sourcePath);\n } catch (err) {\n throw new SdError(err, sourcePath);\n }\n\n if (stats.isDirectory()) {\n await fsMkdir(targetPath);\n\n const children = await fsGlob(path.resolve(sourcePath, \"*\"), { dot: true });\n\n await children.parallelAsync(async (childPath) => {\n if (filter !== undefined && !filter(childPath)) {\n return;\n }\n\n const relativeChildPath = path.relative(sourcePath, childPath);\n const childTargetPath = path.resolve(targetPath, relativeChildPath);\n await fsCopy(childPath, childTargetPath, filter);\n });\n } else {\n await fsMkdir(path.dirname(targetPath));\n\n try {\n await fs.promises.copyFile(sourcePath, targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n }\n}\n\n//#endregion\n\n//#region \uD30C\uC77C \uC77D\uAE30\n\n/**\n * \uD30C\uC77C \uC77D\uAE30 (UTF-8 \uBB38\uC790\uC5F4).\n * @param targetPath - \uC77D\uC744 \uD30C\uC77C \uACBD\uB85C\n */\nexport function fsReadSync(targetPath: string): string {\n try {\n return fs.readFileSync(targetPath, \"utf-8\");\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C \uC77D\uAE30 (UTF-8 \uBB38\uC790\uC5F4, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC77D\uC744 \uD30C\uC77C \uACBD\uB85C\n */\nexport async function fsRead(targetPath: string): Promise<string> {\n try {\n return await fs.promises.readFile(targetPath, \"utf-8\");\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C \uC77D\uAE30 (Buffer).\n * @param targetPath - \uC77D\uC744 \uD30C\uC77C \uACBD\uB85C\n */\nexport function fsReadBufferSync(targetPath: string): Buffer {\n try {\n return fs.readFileSync(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C \uC77D\uAE30 (Buffer, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC77D\uC744 \uD30C\uC77C \uACBD\uB85C\n */\nexport async function fsReadBuffer(targetPath: string): Promise<Buffer> {\n try {\n return await fs.promises.readFile(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * JSON \uD30C\uC77C \uC77D\uAE30 (JsonConvert \uC0AC\uC6A9).\n * @param targetPath - \uC77D\uC744 JSON \uD30C\uC77C \uACBD\uB85C\n */\nexport function fsReadJsonSync<T = unknown>(targetPath: string): T {\n const contents = fsReadSync(targetPath);\n try {\n return jsonParse(contents);\n } catch (err) {\n const preview = contents.length > 500 ? contents.slice(0, 500) + \"...(truncated)\" : contents;\n throw new SdError(err, targetPath + os.EOL + preview);\n }\n}\n\n/**\n * JSON \uD30C\uC77C \uC77D\uAE30 (JsonConvert \uC0AC\uC6A9, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC77D\uC744 JSON \uD30C\uC77C \uACBD\uB85C\n */\nexport async function fsReadJson<T = unknown>(targetPath: string): Promise<T> {\n const contents = await fsRead(targetPath);\n try {\n return jsonParse<T>(contents);\n } catch (err) {\n const preview = contents.length > 500 ? contents.slice(0, 500) + \"...(truncated)\" : contents;\n throw new SdError(err, targetPath + os.EOL + preview);\n }\n}\n\n//#endregion\n\n//#region \uD30C\uC77C \uC4F0\uAE30\n\n/**\n * \uD30C\uC77C \uC4F0\uAE30 (\uBD80\uBAA8 \uB514\uB809\uD1A0\uB9AC \uC790\uB3D9 \uC0DD\uC131).\n * @param targetPath - \uC4F8 \uD30C\uC77C \uACBD\uB85C\n * @param data - \uC4F8 \uB370\uC774\uD130 (\uBB38\uC790\uC5F4 \uB610\uB294 \uBC14\uC774\uB108\uB9AC)\n */\nexport function fsWriteSync(targetPath: string, data: string | Uint8Array): void {\n fsMkdirSync(path.dirname(targetPath));\n\n try {\n fs.writeFileSync(targetPath, data, { flush: true });\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C \uC4F0\uAE30 (\uBD80\uBAA8 \uB514\uB809\uD1A0\uB9AC \uC790\uB3D9 \uC0DD\uC131, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC4F8 \uD30C\uC77C \uACBD\uB85C\n * @param data - \uC4F8 \uB370\uC774\uD130 (\uBB38\uC790\uC5F4 \uB610\uB294 \uBC14\uC774\uB108\uB9AC)\n */\nexport async function fsWrite(targetPath: string, data: string | Uint8Array): Promise<void> {\n await fsMkdir(path.dirname(targetPath));\n\n try {\n await fs.promises.writeFile(targetPath, data, { flush: true });\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * JSON \uD30C\uC77C \uC4F0\uAE30 (JsonConvert \uC0AC\uC6A9).\n * @param targetPath - \uC4F8 JSON \uD30C\uC77C \uACBD\uB85C\n * @param data - \uC4F8 \uB370\uC774\uD130\n * @param options - JSON \uC9C1\uB82C\uD654 \uC635\uC158\n */\nexport function fsWriteJsonSync(\n targetPath: string,\n data: unknown,\n options?: {\n replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;\n space?: string | number;\n },\n): void {\n const json = jsonStringify(data, options);\n fsWriteSync(targetPath, json);\n}\n\n/**\n * JSON \uD30C\uC77C \uC4F0\uAE30 (JsonConvert \uC0AC\uC6A9, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC4F8 JSON \uD30C\uC77C \uACBD\uB85C\n * @param data - \uC4F8 \uB370\uC774\uD130\n * @param options - JSON \uC9C1\uB82C\uD654 \uC635\uC158\n */\nexport async function fsWriteJson(\n targetPath: string,\n data: unknown,\n options?: {\n replacer?: (this: unknown, key: string | undefined, value: unknown) => unknown;\n space?: string | number;\n },\n): Promise<void> {\n const json = jsonStringify(data, options);\n await fsWrite(targetPath, json);\n}\n\n//#endregion\n\n//#region \uB514\uB809\uD1A0\uB9AC \uC77D\uAE30\n\n/**\n * \uB514\uB809\uD1A0\uB9AC \uB0B4\uC6A9 \uC77D\uAE30.\n * @param targetPath - \uC77D\uC744 \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C\n */\nexport function fsReaddirSync(targetPath: string): string[] {\n try {\n return fs.readdirSync(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uB514\uB809\uD1A0\uB9AC \uB0B4\uC6A9 \uC77D\uAE30 (\uBE44\uB3D9\uAE30).\n * @param targetPath - \uC77D\uC744 \uB514\uB809\uD1A0\uB9AC \uACBD\uB85C\n */\nexport async function fsReaddir(targetPath: string): Promise<string[]> {\n try {\n return await fs.promises.readdir(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n//#endregion\n\n//#region \uD30C\uC77C \uC815\uBCF4\n\n/**\n * \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC \uC815\uBCF4 (\uC2EC\uBCFC\uB9AD \uB9C1\uD06C \uB530\uB77C\uAC10).\n * @param targetPath - \uC815\uBCF4\uB97C \uC870\uD68C\uD560 \uACBD\uB85C\n */\nexport function fsStatSync(targetPath: string): fs.Stats {\n try {\n return fs.statSync(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC \uC815\uBCF4 (\uC2EC\uBCFC\uB9AD \uB9C1\uD06C \uB530\uB77C\uAC10, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC815\uBCF4\uB97C \uC870\uD68C\uD560 \uACBD\uB85C\n */\nexport async function fsStat(targetPath: string): Promise<fs.Stats> {\n try {\n return await fs.promises.stat(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC \uC815\uBCF4 (\uC2EC\uBCFC\uB9AD \uB9C1\uD06C \uB530\uB77C\uAC00\uC9C0 \uC54A\uC74C).\n * @param targetPath - \uC815\uBCF4\uB97C \uC870\uD68C\uD560 \uACBD\uB85C\n */\nexport function fsLstatSync(targetPath: string): fs.Stats {\n try {\n return fs.lstatSync(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n/**\n * \uD30C\uC77C/\uB514\uB809\uD1A0\uB9AC \uC815\uBCF4 (\uC2EC\uBCFC\uB9AD \uB9C1\uD06C \uB530\uB77C\uAC00\uC9C0 \uC54A\uC74C, \uBE44\uB3D9\uAE30).\n * @param targetPath - \uC815\uBCF4\uB97C \uC870\uD68C\uD560 \uACBD\uB85C\n */\nexport async function fsLstat(targetPath: string): Promise<fs.Stats> {\n try {\n return await fs.promises.lstat(targetPath);\n } catch (err) {\n throw new SdError(err, targetPath);\n }\n}\n\n//#endregion\n\n//#region \uAE00\uB85C\uBE0C\n\n/**\n * \uAE00\uB85C\uBE0C \uD328\uD134\uC73C\uB85C \uD30C\uC77C \uAC80\uC0C9.\n * @param pattern - \uAE00\uB85C\uBE0C \uD328\uD134 (\uC608: \"**\\/*.ts\")\n * @param options - glob \uC635\uC158\n * @returns \uB9E4\uCE6D\uB41C \uD30C\uC77C\uB4E4\uC758 \uC808\uB300 \uACBD\uB85C \uBC30\uC5F4\n */\nexport function fsGlobSync(pattern: string, options?: GlobOptions): string[] {\n return globRawSync(pattern.replace(/\\\\/g, \"/\"), options ?? {}).map((item) => path.resolve(item.toString()));\n}\n\n/**\n * \uAE00\uB85C\uBE0C \uD328\uD134\uC73C\uB85C \uD30C\uC77C \uAC80\uC0C9 (\uBE44\uB3D9\uAE30).\n * @param pattern - \uAE00\uB85C\uBE0C \uD328\uD134 (\uC608: \"**\\/*.ts\")\n * @param options - glob \uC635\uC158\n * @returns \uB9E4\uCE6D\uB41C \uD30C\uC77C\uB4E4\uC758 \uC808\uB300 \uACBD\uB85C \uBC30\uC5F4\n */\nexport async function fsGlob(pattern: string, options?: GlobOptions): Promise<string[]> {\n return (await globRaw(pattern.replace(/\\\\/g, \"/\"), options ?? {})).map((item) => path.resolve(item.toString()));\n}\n\n//#endregion\n\n//#region \uC720\uD2F8\uB9AC\uD2F0\n\n/**\n * \uC9C0\uC815 \uB514\uB809\uD1A0\uB9AC \uD558\uC704\uC758 \uBE48 \uB514\uB809\uD1A0\uB9AC\uB97C \uC7AC\uADC0\uC801\uC73C\uB85C \uD0D0\uC0C9\uD558\uC5EC \uC0AD\uC81C.\n * \uD558\uC704 \uB514\uB809\uD1A0\uB9AC\uAC00 \uBAA8\uB450 \uC0AD\uC81C\uB418\uC5B4 \uBE48 \uB514\uB809\uD1A0\uB9AC\uAC00 \uB41C \uACBD\uC6B0, \uD574\uB2F9 \uB514\uB809\uD1A0\uB9AC\uB3C4 \uC0AD\uC81C \uB300\uC0C1\uC774 \uB428.\n */\nexport async function fsClearEmptyDirectory(dirPath: string): Promise<void> {\n if (!(await fsExists(dirPath))) return;\n\n const childNames = await fsReaddir(dirPath);\n let hasFiles = false;\n\n for (const childName of childNames) {\n const childPath = path.resolve(dirPath, childName);\n if ((await fsLstat(childPath)).isDirectory()) {\n await fsClearEmptyDirectory(childPath);\n } else {\n hasFiles = true;\n }\n }\n\n // \uD30C\uC77C\uC774 \uC788\uC5C8\uB2E4\uBA74 \uC0AD\uC81C \uBD88\uAC00\n if (hasFiles) return;\n\n // \uD30C\uC77C\uC774 \uC5C6\uC5C8\uB358 \uACBD\uC6B0\uC5D0\uB9CC \uC7AC\uD655\uC778 (\uD558\uC704 \uB514\uB809\uD1A0\uB9AC\uAC00 \uC0AD\uC81C\uB418\uC5C8\uC744 \uC218 \uC788\uC74C)\n if ((await fsReaddir(dirPath)).length === 0) {\n await fsRm(dirPath);\n }\n}\n\n/**\n * \uC2DC\uC791 \uACBD\uB85C\uBD80\uD130 \uB8E8\uD2B8 \uBC29\uD5A5\uC73C\uB85C \uC0C1\uC704 \uB514\uB809\uD1A0\uB9AC\uB97C \uC21C\uD68C\uD558\uBA70 glob \uD328\uD134 \uAC80\uC0C9.\n * \uAC01 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C childGlob \uD328\uD134\uC5D0 \uB9E4\uCE6D\uB418\uB294 \uBAA8\uB4E0 \uD30C\uC77C \uACBD\uB85C\uB97C \uC218\uC9D1.\n * @param childGlob - \uAC01 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uAC80\uC0C9\uD560 glob \uD328\uD134\n * @param fromPath - \uAC80\uC0C9 \uC2DC\uC791 \uACBD\uB85C\n * @param rootPath - \uAC80\uC0C9 \uC885\uB8CC \uACBD\uB85C (\uBBF8\uC9C0\uC815 \uC2DC \uD30C\uC77C\uC2DC\uC2A4\uD15C \uB8E8\uD2B8\uAE4C\uC9C0).\n * **\uC8FC\uC758**: fromPath\uAC00 rootPath\uC758 \uC790\uC2DD \uACBD\uB85C\uC5EC\uC57C \uD568.\n * \uADF8\uB807\uC9C0 \uC54A\uC73C\uBA74 \uD30C\uC77C\uC2DC\uC2A4\uD15C \uB8E8\uD2B8\uAE4C\uC9C0 \uAC80\uC0C9\uD568.\n */\nexport function fsFindAllParentChildPathsSync(childGlob: string, fromPath: string, rootPath?: string): string[] {\n const resultPaths: string[] = [];\n\n let current = fromPath;\n while (current) {\n const potential = path.resolve(current, childGlob);\n const globResults = fsGlobSync(potential);\n resultPaths.push(...globResults);\n\n if (current === rootPath) break;\n\n const next = path.dirname(current);\n if (next === current) break;\n current = next;\n }\n\n return resultPaths;\n}\n\n/**\n * \uC2DC\uC791 \uACBD\uB85C\uBD80\uD130 \uB8E8\uD2B8 \uBC29\uD5A5\uC73C\uB85C \uC0C1\uC704 \uB514\uB809\uD1A0\uB9AC\uB97C \uC21C\uD68C\uD558\uBA70 glob \uD328\uD134 \uAC80\uC0C9 (\uBE44\uB3D9\uAE30).\n * \uAC01 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C childGlob \uD328\uD134\uC5D0 \uB9E4\uCE6D\uB418\uB294 \uBAA8\uB4E0 \uD30C\uC77C \uACBD\uB85C\uB97C \uC218\uC9D1.\n * @param childGlob - \uAC01 \uB514\uB809\uD1A0\uB9AC\uC5D0\uC11C \uAC80\uC0C9\uD560 glob \uD328\uD134\n * @param fromPath - \uAC80\uC0C9 \uC2DC\uC791 \uACBD\uB85C\n * @param rootPath - \uAC80\uC0C9 \uC885\uB8CC \uACBD\uB85C (\uBBF8\uC9C0\uC815 \uC2DC \uD30C\uC77C\uC2DC\uC2A4\uD15C \uB8E8\uD2B8\uAE4C\uC9C0).\n * **\uC8FC\uC758**: fromPath\uAC00 rootPath\uC758 \uC790\uC2DD \uACBD\uB85C\uC5EC\uC57C \uD568.\n * \uADF8\uB807\uC9C0 \uC54A\uC73C\uBA74 \uD30C\uC77C\uC2DC\uC2A4\uD15C \uB8E8\uD2B8\uAE4C\uC9C0 \uAC80\uC0C9\uD568.\n */\nexport async function fsFindAllParentChildPaths(\n childGlob: string,\n fromPath: string,\n rootPath?: string,\n): Promise<string[]> {\n const resultPaths: string[] = [];\n\n let current = fromPath;\n while (current) {\n const potential = path.resolve(current, childGlob);\n const globResults = await fsGlob(potential);\n resultPaths.push(...globResults);\n\n if (current === rootPath) break;\n\n const next = path.dirname(current);\n if (next === current) break;\n current = next;\n }\n\n return resultPaths;\n}\n\n//#endregion\n"],
|
|
5
4
|
"mappings": "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",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/dist/utils/path.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/utils/path.ts"],
|
|
4
|
-
"sourcesContent": ["import path from \"path\";\nimport { ArgumentError } from \"@simplysm/core-common\";\n\n//#region Types\n\nconst NORM = Symbol(\"NormPath\");\n\n/**\n * \uC815\uADDC\uD654\uB41C \uACBD\uB85C\uB97C \uB098\uD0C0\uB0B4\uB294 \uBE0C\uB79C\uB4DC \uD0C0\uC785.\n * pathNorm()\uC744 \uD1B5\uD574\uC11C\uB9CC \uC0DD\uC131 \uAC00\uB2A5.\n */\nexport type NormPath = string & {\n [NORM]: never;\n};\n\n//#endregion\n\n//#region \uD568\uC218\n\n/**\n * POSIX \uC2A4\uD0C0\uC77C \uACBD\uB85C\uB85C \uBCC0\uD658 (\uBC31\uC2AC\uB798\uC2DC \u2192 \uC2AC\uB798\uC2DC).\n *\n * @example\n * pathPosix(\"C:\\\\Users\\\\test\"); // \"C:/Users/test\"\n * pathPosix(\"src\", \"index.ts\"); // \"src/index.ts\"\n */\nexport function pathPosix(...args: string[]): string {\n const resolvedPath = path.join(...args);\n return resolvedPath.replace(/\\\\/g, \"/\");\n}\n\n/**\n * \uD30C\uC77C \uACBD\uB85C\uC758 \uB514\uB809\uD1A0\uB9AC\uB97C \uBCC0\uACBD.\n *\n * @example\n * pathChangeFileDirectory(\"/a/b/c.txt\", \"/a\", \"/x\");\n * // \u2192 \"/x/b/c.txt\"\n *\n * @throws \uD30C\uC77C\uC774 fromDirectory \uC548\uC5D0 \uC5C6\uC73C\uBA74 \uC5D0\uB7EC\n */\nexport function pathChangeFileDirectory(filePath: string, fromDirectory: string, toDirectory: string): string {\n if (filePath === fromDirectory) {\n return toDirectory;\n }\n\n if (!pathIsChildPath(filePath, fromDirectory)) {\n throw new ArgumentError(`'${filePath}'\uAC00 ${fromDirectory} \uC548\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.`, { filePath, fromDirectory });\n }\n\n return path.resolve(toDirectory, path.relative(fromDirectory, filePath));\n}\n\n/**\n * \uD655\uC7A5\uC790\uB97C \uC81C\uAC70\uD55C \uD30C\uC77C\uBA85(basename)\uC744 \uBC18\uD658.\n *\n * @example\n * pathGetBasenameWithoutExt(\"file.txt\"); // \"file\"\n * pathGetBasenameWithoutExt(\"/path/to/file.spec.ts\"); // \"file.spec\"\n */\nexport function pathGetBasenameWithoutExt(filePath: string): string {\n return path.basename(filePath, path.extname(filePath));\n}\n\n/**\n * childPath\uAC00 parentPath\uC758 \uC790\uC2DD \uACBD\uB85C\uC778\uC9C0 \uD655\uC778.\n * \uAC19\uC740 \uACBD\uB85C\uB294 false \uBC18\uD658.\n *\n * \uACBD\uB85C\uB294 \uB0B4\uBD80\uC801\uC73C\uB85C `pathNorm()`\uC73C\uB85C \uC815\uADDC\uD654\uB41C \uD6C4 \uBE44\uAD50\uB418\uBA70,\n * \uD50C\uB7AB\uD3FC\uBCC4 \uACBD\uB85C \uAD6C\uBD84\uC790(Windows: `\\`, Unix: `/`)\uB97C \uC0AC\uC6A9\uD55C\uB2E4.\n *\n * @example\n * pathIsChildPath(\"/a/b/c\", \"/a/b\"); // true\n * pathIsChildPath(\"/a/b\", \"/a/b/c\"); // false\n * pathIsChildPath(\"/a/b\", \"/a/b\"); // false (\uAC19\uC740 \uACBD\uB85C)\n */\nexport function pathIsChildPath(childPath: string, parentPath: string): boolean {\n const normalizedChild = pathNorm(childPath);\n const normalizedParent = pathNorm(parentPath);\n\n // \uAC19\uC740 \uACBD\uB85C\uBA74 false\n if (normalizedChild === normalizedParent) {\n return false;\n }\n\n // \uBD80\uBAA8 \uACBD\uB85C + \uAD6C\uBD84\uC790\uB85C \uC2DC\uC791\uD558\uB294\uC9C0 \uD655\uC778\n const parentWithSep = normalizedParent.endsWith(path.sep) ? normalizedParent : normalizedParent + path.sep;\n\n return normalizedChild.startsWith(parentWithSep);\n}\n\n/**\n * \uACBD\uB85C\uB97C \uC815\uADDC\uD654\uD558\uC5EC NormPath\uB85C \uBC18\uD658.\n * \uC808\uB300 \uACBD\uB85C\uB85C \uBCC0\uD658\uB418\uBA70, \uD50C\uB7AB\uD3FC\uBCC4 \uAD6C\uBD84\uC790\uB85C \uC815\uADDC\uD654\uB428.\n *\n * @example\n * pathNorm(\"/some/path\"); // NormPath\n * pathNorm(\"relative\", \"path\"); // NormPath (\uC808\uB300 \uACBD\uB85C\uB85C \uBCC0\uD658)\n */\nexport function pathNorm(...paths: string[]): NormPath {\n return path.resolve(...paths) as NormPath;\n}\n\n/**\n * \uD0C0\uAC9F \uACBD\uB85C \uBAA9\uB85D\uC744 \uAE30\uC900\uC73C\uB85C \uD30C\uC77C\uC744 \uD544\uD130\uB9C1.\n * \uD30C\uC77C\uC774 \uD0C0\uAC9F \uACBD\uB85C\uC640 \uAC19\uAC70\uB098 \uD0C0\uAC9F\uC758 \uC790\uC2DD \uACBD\uB85C\uC77C \uB54C \uD3EC\uD568.\n *\n * @param files - \uD544\uD130\uB9C1\uD560 \uD30C\uC77C \uACBD\uB85C \uBAA9\uB85D.\n * **\uC8FC\uC758**: cwd \uD558\uC704\uC758 \uC808\uB300 \uACBD\uB85C\uC5EC\uC57C \uD568.\n * cwd \uC678\uBD80 \uACBD\uB85C\uB294 \uC0C1\uB300 \uACBD\uB85C(../ \uD615\uD0DC)\uB85C \uBCC0\uD658\uB418\uC5B4 \uCC98\uB9AC\uB428.\n * @param targets - \uD0C0\uAC9F \uACBD\uB85C \uBAA9\uB85D (cwd \uAE30\uC900 \uC0C1\uB300 \uACBD\uB85C, POSIX \uC2A4\uD0C0\uC77C \uAD8C\uC7A5)\n * @param cwd - \uD604\uC7AC \uC791\uC5C5 \uB514\uB809\uD1A0\uB9AC (\uC808\uB300 \uACBD\uB85C)\n * @returns targets\uAC00 \uBE48 \uBC30\uC5F4\uC774\uBA74 files \uADF8\uB300\uB85C, \uC544\uB2C8\uBA74 \uD0C0\uAC9F \uACBD\uB85C \uD558\uC704 \uD30C\uC77C\uB9CC\n *\n * @example\n * const files = [\"/proj/src/a.ts\", \"/proj/src/b.ts\", \"/proj/tests/c.ts\"];\n * pathFilterByTargets(files, [\"src\"], \"/proj\");\n * // \u2192 [\"/proj/src/a.ts\", \"/proj/src/b.ts\"]\n */\nexport function pathFilterByTargets(files: string[], targets: string[], cwd: string): string[] {\n if (targets.length === 0) return files;\n const normalizedTargets = targets.map((t) => pathPosix(t));\n return files.filter((file) => {\n const relativePath = pathPosix(path.relative(cwd, file));\n return normalizedTargets.some((target) => relativePath === target || relativePath.startsWith(target + \"/\"));\n });\n}\n\n//#endregion\n"],
|
|
5
4
|
"mappings": "AAAA,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAI9B,MAAM,OAAO,uBAAO,UAAU;AAqBvB,SAAS,aAAa,MAAwB;AACnD,QAAM,eAAe,KAAK,KAAK,GAAG,IAAI;AACtC,SAAO,aAAa,QAAQ,OAAO,GAAG;AACxC;AAWO,SAAS,wBAAwB,UAAkB,eAAuB,aAA6B;AAC5G,MAAI,aAAa,eAAe;AAC9B,WAAO;AAAA,EACT;AAEA,MAAI,CAAC,gBAAgB,UAAU,aAAa,GAAG;AAC7C,UAAM,IAAI,cAAc,IAAI,QAAQ,WAAM,aAAa,2CAAa,EAAE,UAAU,cAAc,CAAC;AAAA,EACjG;AAEA,SAAO,KAAK,QAAQ,aAAa,KAAK,SAAS,eAAe,QAAQ,CAAC;AACzE;AASO,SAAS,0BAA0B,UAA0B;AAClE,SAAO,KAAK,SAAS,UAAU,KAAK,QAAQ,QAAQ,CAAC;AACvD;AAcO,SAAS,gBAAgB,WAAmB,YAA6B;AAC9E,QAAM,kBAAkB,SAAS,SAAS;AAC1C,QAAM,mBAAmB,SAAS,UAAU;AAG5C,MAAI,oBAAoB,kBAAkB;AACxC,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,iBAAiB,SAAS,KAAK,GAAG,IAAI,mBAAmB,mBAAmB,KAAK;AAEvG,SAAO,gBAAgB,WAAW,aAAa;AACjD;AAUO,SAAS,YAAY,OAA2B;AACrD,SAAO,KAAK,QAAQ,GAAG,KAAK;AAC9B;AAkBO,SAAS,oBAAoB,OAAiB,SAAmB,KAAuB;AAC7F,MAAI,QAAQ,WAAW,EAAG,QAAO;AACjC,QAAM,oBAAoB,QAAQ,IAAI,CAAC,MAAM,UAAU,CAAC,CAAC;AACzD,SAAO,MAAM,OAAO,CAAC,SAAS;AAC5B,UAAM,eAAe,UAAU,KAAK,SAAS,KAAK,IAAI,CAAC;AACvD,WAAO,kBAAkB,KAAK,CAAC,WAAW,iBAAiB,UAAU,aAAa,WAAW,SAAS,GAAG,CAAC;AAAA,EAC5G,CAAC;AACH;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/worker/create-worker.ts"],
|
|
4
|
-
"sourcesContent": ["import { parentPort } from \"worker_threads\";\nimport { SdError, transferableDecode, transferableEncode } from \"@simplysm/core-common\";\nimport type { WorkerRequest, WorkerResponse } from \"./types\";\n\n//#region createSdWorker\n\n/**\n * \uC6CC\uCEE4 \uC2A4\uB808\uB4DC\uC5D0\uC11C \uC0AC\uC6A9\uD560 \uC6CC\uCEE4 \uD329\uD1A0\uB9AC.\n *\n * @example\n * // \uC774\uBCA4\uD2B8 \uC5C6\uB294 \uC6CC\uCEE4\n * export default createWorker({\n * add: (a: number, b: number) => a + b,\n * });\n *\n * // \uC774\uBCA4\uD2B8 \uC788\uB294 \uC6CC\uCEE4\n * interface MyEvents { progress: number; }\n * const methods = {\n * calc: (x: number) => { sender.send(\"progress\", 50); return x * 2; },\n * };\n * const sender = createWorker<typeof methods, MyEvents>(methods);\n * export default sender;\n */\nexport function createWorker<\n TMethods extends Record<string, (...args: any[]) => unknown>,\n TEvents extends Record<string, unknown> = Record<string, never>,\n>(\n methods: TMethods,\n): {\n send<K extends keyof TEvents & string>(event: K, data?: TEvents[K]): void;\n __methods: TMethods;\n __events: TEvents;\n} {\n if (parentPort === null) {\n throw new SdError(\"\uC774 \uC2A4\uD06C\uB9BD\uD2B8\uB294 \uC6CC\uCEE4 \uC2A4\uB808\uB4DC\uC5D0\uC11C \uC2E4\uD589\uB418\uC5B4\uC57C \uD569\uB2C8\uB2E4 (parentPort \uD544\uC694).\");\n }\n\n const port = parentPort;\n\n // Worker \uC2A4\uB808\uB4DC\uC758 stdout\uC740 \uBA54\uC778 \uC2A4\uB808\uB4DC\uB85C \uC790\uB3D9 \uC804\uB2EC\uB418\uC9C0 \uC54A\uC74C\n // stdout.write\uB97C \uAC00\uB85C\uCC44\uC11C \uBA54\uC2DC\uC9C0 \uD504\uB85C\uD1A0\uCF5C\uC744 \uD1B5\uD574 \uBA54\uC778 \uC2A4\uB808\uB4DC\uB85C \uC804\uB2EC\n process.stdout.write = (\n chunk: string | Uint8Array,\n encodingOrCallback?: BufferEncoding | ((err?: Error) => void),\n callback?: (err?: Error) => void,\n ): boolean => {\n const body = typeof chunk === \"string\" ? chunk : new TextDecoder().decode(chunk);\n const response: WorkerResponse = { type: \"log\", body };\n const serialized = transferableEncode(response);\n port.postMessage(serialized.result, serialized.transferList);\n\n const cb = typeof encodingOrCallback === \"function\" ? encodingOrCallback : callback;\n if (cb) {\n queueMicrotask(() => cb());\n }\n\n return true;\n };\n\n port.on(\"message\", async (serializedRequest: unknown) => {\n const decoded = transferableDecode(serializedRequest);\n\n // \uC694\uCCAD \uAD6C\uC870 \uAC80\uC99D\n if (\n decoded == null ||\n typeof decoded !== \"object\" ||\n !(\"id\" in decoded) ||\n !(\"method\" in decoded) ||\n !(\"params\" in decoded)\n ) {\n let decodedStr: string;\n try {\n decodedStr = JSON.stringify(decoded);\n } catch {\n decodedStr = String(decoded);\n }\n const errorResponse: WorkerResponse = {\n type: \"error\",\n request: { id: \"unknown\", method: \"unknown\", params: [] },\n body: new SdError(`\uD615\uC2DD\uC774 \uC798\uBABB\uB41C \uC6CC\uCEE4 \uC694\uCCAD: ${decodedStr}`),\n };\n const serialized = transferableEncode(errorResponse);\n port.postMessage(serialized.result, serialized.transferList);\n return;\n }\n const request = decoded as WorkerRequest;\n\n const methodFn = methods[request.method] as ((...args: unknown[]) => unknown) | undefined;\n\n if (methodFn == null) {\n const response: WorkerResponse = {\n request,\n type: \"error\",\n body: new SdError(`\uC54C \uC218 \uC5C6\uB294 \uBA54\uC11C\uB4DC: ${request.method}`),\n };\n\n const serialized = transferableEncode(response);\n port.postMessage(serialized.result, serialized.transferList);\n return;\n }\n\n try {\n const result = await methodFn(...request.params);\n\n const response: WorkerResponse = {\n request,\n type: \"return\",\n body: result,\n };\n\n const serialized = transferableEncode(response);\n port.postMessage(serialized.result, serialized.transferList);\n } catch (err) {\n const response: WorkerResponse = {\n request,\n type: \"error\",\n body: err instanceof Error ? err : new Error(String(err)),\n };\n\n const serialized = transferableEncode(response);\n port.postMessage(serialized.result, serialized.transferList);\n }\n });\n\n return {\n __methods: methods,\n __events: {} as TEvents,\n send<K extends keyof TEvents & string>(event: K, data?: TEvents[K]) {\n const response: WorkerResponse = {\n type: \"event\",\n event,\n body: data,\n };\n\n const serialized = transferableEncode(response);\n port.postMessage(serialized.result, serialized.transferList);\n },\n };\n}\n\n//#endregion\n"],
|
|
5
4
|
"mappings": "AAAA,SAAS,kBAAkB;AAC3B,SAAS,SAAS,oBAAoB,0BAA0B;AAsBzD,SAAS,aAId,SAKA;AACA,MAAI,eAAe,MAAM;AACvB,UAAM,IAAI,QAAQ,gKAA6C;AAAA,EACjE;AAEA,QAAM,OAAO;AAIb,UAAQ,OAAO,QAAQ,CACrB,OACA,oBACA,aACY;AACZ,UAAM,OAAO,OAAO,UAAU,WAAW,QAAQ,IAAI,YAAY,EAAE,OAAO,KAAK;AAC/E,UAAM,WAA2B,EAAE,MAAM,OAAO,KAAK;AACrD,UAAM,aAAa,mBAAmB,QAAQ;AAC9C,SAAK,YAAY,WAAW,QAAQ,WAAW,YAAY;AAE3D,UAAM,KAAK,OAAO,uBAAuB,aAAa,qBAAqB;AAC3E,QAAI,IAAI;AACN,qBAAe,MAAM,GAAG,CAAC;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAEA,OAAK,GAAG,WAAW,OAAO,sBAA+B;AACvD,UAAM,UAAU,mBAAmB,iBAAiB;AAGpD,QACE,WAAW,QACX,OAAO,YAAY,YACnB,EAAE,QAAQ,YACV,EAAE,YAAY,YACd,EAAE,YAAY,UACd;AACA,UAAI;AACJ,UAAI;AACF,qBAAa,KAAK,UAAU,OAAO;AAAA,MACrC,QAAQ;AACN,qBAAa,OAAO,OAAO;AAAA,MAC7B;AACA,YAAM,gBAAgC;AAAA,QACpC,MAAM;AAAA,QACN,SAAS,EAAE,IAAI,WAAW,QAAQ,WAAW,QAAQ,CAAC,EAAE;AAAA,QACxD,MAAM,IAAI,QAAQ,oEAAkB,UAAU,EAAE;AAAA,MAClD;AACA,YAAM,aAAa,mBAAmB,aAAa;AACnD,WAAK,YAAY,WAAW,QAAQ,WAAW,YAAY;AAC3D;AAAA,IACF;AACA,UAAM,UAAU;AAEhB,UAAM,WAAW,QAAQ,QAAQ,MAAM;AAEvC,QAAI,YAAY,MAAM;AACpB,YAAM,WAA2B;AAAA,QAC/B;AAAA,QACA,MAAM;AAAA,QACN,MAAM,IAAI,QAAQ,kDAAe,QAAQ,MAAM,EAAE;AAAA,MACnD;AAEA,YAAM,aAAa,mBAAmB,QAAQ;AAC9C,WAAK,YAAY,WAAW,QAAQ,WAAW,YAAY;AAC3D;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,SAAS,GAAG,QAAQ,MAAM;AAE/C,YAAM,WAA2B;AAAA,QAC/B;AAAA,QACA,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAEA,YAAM,aAAa,mBAAmB,QAAQ;AAC9C,WAAK,YAAY,WAAW,QAAQ,WAAW,YAAY;AAAA,IAC7D,SAAS,KAAK;AACZ,YAAM,WAA2B;AAAA,QAC/B;AAAA,QACA,MAAM;AAAA,QACN,MAAM,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAAA,MAC1D;AAEA,YAAM,aAAa,mBAAmB,QAAQ;AAC9C,WAAK,YAAY,WAAW,QAAQ,WAAW,YAAY;AAAA,IAC7D;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,WAAW;AAAA,IACX,UAAU,CAAC;AAAA,IACX,KAAuC,OAAU,MAAmB;AAClE,YAAM,WAA2B;AAAA,QAC/B,MAAM;AAAA,QACN;AAAA,QACA,MAAM;AAAA,MACR;AAEA,YAAM,aAAa,mBAAmB,QAAQ;AAC9C,WAAK,YAAY,WAAW,QAAQ,WAAW,YAAY;AAAA,IAC7D;AAAA,EACF;AACF;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/dist/worker/types.js.map
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/worker/worker.ts"],
|
|
4
|
-
"sourcesContent": ["import { EventEmitter, transferableDecode, transferableEncode, Uuid } from \"@simplysm/core-common\";\nimport consola from \"consola\";\nimport path from \"path\";\nimport { fileURLToPath } from \"url\";\nimport type { WorkerOptions as WorkerRawOptions } from \"worker_threads\";\nimport { Worker as WorkerRaw } from \"worker_threads\";\nimport type { WorkerModule, WorkerProxy, WorkerRequest, WorkerResponse } from \"./types\";\n\nconst logger = consola.withTag(\"sd-worker\");\n\n//#region WorkerInternal\n\n/**\n * Worker \uB0B4\uBD80 \uAD6C\uD604 \uD074\uB798\uC2A4.\n * Proxy\uB97C \uD1B5\uD574 \uC678\uBD80\uC5D0 \uB178\uCD9C\uB428.\n *\n * \uAC1C\uBC1C \uD658\uACBD(.ts)\uC5D0\uC11C\uB294 tsx\uB97C \uD1B5\uD574 TypeScript \uC6CC\uCEE4 \uD30C\uC77C\uC744 \uC2E4\uD589\uD558\uACE0,\n * \uD504\uB85C\uB355\uC158 \uD658\uACBD(.js)\uC5D0\uC11C\uB294 \uC9C1\uC811 Worker\uB97C \uC0DD\uC131\uD55C\uB2E4.\n */\nclass WorkerInternal extends EventEmitter<Record<string, unknown>> {\n private readonly _worker: WorkerRaw;\n private _isTerminated = false;\n private readonly _pendingRequests = new Map<\n string,\n { method: string; resolve: (value: unknown) => void; reject: (err: Error) => void }\n >();\n\n constructor(filePath: string, opt?: Omit<WorkerRawOptions, \"stdout\" | \"stderr\">) {\n super();\n\n const ext = path.extname(import.meta.filename);\n\n // \uD0C0\uC785 \uAC00\uB4DC\uB97C \uD1B5\uD55C env \uAC1D\uCCB4 \uCD94\uCD9C\n const envObj = opt?.env != null && typeof opt.env === \"object\" ? opt.env : {};\n\n // \uAC1C\uBC1C \uD658\uACBD (.ts \uD30C\uC77C)\uC778 \uACBD\uC6B0 tsx\uB97C \uD1B5\uD574 \uC2E4\uD589\n // worker-dev-proxy.js: tsx\uB85C TypeScript \uC6CC\uCEE4 \uD30C\uC77C\uC744 \uB3D9\uC801\uC73C\uB85C \uB85C\uB4DC\uD558\uB294 \uD504\uB85D\uC2DC\n if (ext === \".ts\") {\n // file:// URL\uC778 \uACBD\uC6B0 \uC808\uB300 \uACBD\uB85C\uB85C \uBCC0\uD658 (worker-dev-proxy.js\uC5D0\uC11C \uB2E4\uC2DC pathToFileURL \uC801\uC6A9)\n const workerPath = filePath.startsWith(\"file://\") ? fileURLToPath(filePath) : filePath;\n this._worker = new WorkerRaw(path.resolve(import.meta.dirname, \"../../lib/worker-dev-proxy.js\"), {\n stdout: true,\n stderr: true,\n ...opt,\n env: {\n ...process.env,\n ...envObj,\n },\n argv: [workerPath, ...(opt?.argv ?? [])],\n });\n } else {\n // \uD504\uB85C\uB355\uC158 \uD658\uACBD (.js \uD30C\uC77C)\n // file:// URL\uC778 \uACBD\uC6B0 \uBCC0\uD658, \uC774\uBBF8 \uC808\uB300 \uACBD\uB85C\uC778 \uACBD\uC6B0 \uADF8\uB300\uB85C \uC0AC\uC6A9\n const workerPath = filePath.startsWith(\"file://\") ? fileURLToPath(filePath) : filePath;\n this._worker = new WorkerRaw(workerPath, {\n stdout: true,\n stderr: true,\n ...opt,\n env: {\n ...process.env,\n ...envObj,\n },\n });\n }\n\n // \uC6CC\uCEE4\uC758 stdout/stderr\uB97C \uBA54\uC778\uC5D0 \uCD9C\uB825\n this._worker.stdout.pipe(process.stdout);\n this._worker.stderr.pipe(process.stderr);\n\n this._worker.on(\"exit\", (code) => {\n if (!this._isTerminated && code !== 0) {\n logger.error(`\uC6CC\uCEE4\uAC00 \uC624\uB958\uC640 \uD568\uAED8 \uB2EB\uD798 (code: ${code})`);\n // \uBE44\uC815\uC0C1 \uC885\uB8CC \uC2DC \uB300\uAE30 \uC911\uC778 \uBAA8\uB4E0 \uC694\uCCAD reject\n this._rejectAllPending(new Error(`\uC6CC\uCEE4\uAC00 \uBE44\uC815\uC0C1 \uC885\uB8CC\uB428 (code: ${code})`));\n }\n });\n\n this._worker.on(\"error\", (err) => {\n logger.error(\"\uC6CC\uCEE4 \uC624\uB958:\", err);\n // \uC6CC\uCEE4 \uC5D0\uB7EC \uC2DC \uB300\uAE30 \uC911\uC778 \uBAA8\uB4E0 \uC694\uCCAD reject\n this._rejectAllPending(err);\n });\n\n this._worker.on(\"message\", (serializedResponse: unknown) => {\n const decoded = transferableDecode(serializedResponse);\n\n // \uC751\uB2F5 \uAD6C\uC870 \uAC80\uC99D\n if (decoded == null || typeof decoded !== \"object\" || !(\"type\" in decoded)) {\n logger.warn(\"\uC6CC\uCEE4\uC5D0\uC11C \uC798\uBABB\uB41C \uD615\uC2DD\uC758 \uC751\uB2F5:\", decoded);\n return;\n }\n const response = decoded as WorkerResponse;\n\n if (response.type === \"event\") {\n this.emit(response.event, response.body);\n } else if (response.type === \"log\") {\n process.stdout.write(response.body);\n } else if (response.type === \"return\") {\n const pending = this._pendingRequests.get(response.request.id);\n if (pending) {\n this._pendingRequests.delete(response.request.id);\n pending.resolve(response.body);\n }\n } else {\n // response.type === \"error\"\n const pending = this._pendingRequests.get(response.request.id);\n if (pending) {\n this._pendingRequests.delete(response.request.id);\n pending.reject(response.body);\n }\n }\n });\n }\n\n /**\n * \uB300\uAE30 \uC911\uC778 \uBAA8\uB4E0 \uC694\uCCAD\uC744 reject\uD569\uB2C8\uB2E4.\n */\n private _rejectAllPending(err: Error): void {\n for (const [_id, { method, reject }] of this._pendingRequests) {\n reject(new Error(`${err.message} (method: ${method})`));\n }\n this._pendingRequests.clear();\n }\n\n /**\n * \uC6CC\uCEE4 \uBA54\uC11C\uB4DC \uD638\uCD9C.\n */\n call(method: string, params: unknown[]): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const request: WorkerRequest = {\n id: Uuid.new().toString(),\n method,\n params,\n };\n\n this._pendingRequests.set(request.id, { method, resolve, reject });\n\n const serialized = transferableEncode(request);\n this._worker.postMessage(serialized.result, serialized.transferList);\n });\n }\n\n /**\n * \uC6CC\uCEE4 \uC885\uB8CC.\n */\n async terminate(): Promise<void> {\n this._isTerminated = true;\n this._rejectAllPending(new Error(\"\uC6CC\uCEE4\uAC00 \uC885\uB8CC\uB428\"));\n await this._worker.terminate();\n }\n}\n\n//#endregion\n\n//#region Worker\n\n/**\n * \uD0C0\uC785 \uC548\uC804\uD55C Worker \uB798\uD37C.\n *\n * @example\n * // worker.ts\n * export default createWorker({\n * add: (a: number, b: number) => a + b,\n * });\n *\n * // main.ts\n * const worker = Worker.create<typeof import(\"./worker\")>(\"./worker.ts\");\n * const result = await worker.add(10, 20); // 30\n * await worker.terminate();\n */\nexport const Worker = {\n /**\n * \uD0C0\uC785 \uC548\uC804\uD55C Worker Proxy \uC0DD\uC131.\n *\n * @param filePath - \uC6CC\uCEE4 \uD30C\uC77C \uACBD\uB85C (file:// URL \uB610\uB294 \uC808\uB300 \uACBD\uB85C)\n * @param opt - Worker \uC635\uC158\n * @returns Proxy \uAC1D\uCCB4 (\uBA54\uC11C\uB4DC \uC9C1\uC811 \uD638\uCD9C, on(), terminate() \uC9C0\uC6D0)\n */\n create<TModule extends WorkerModule>(\n filePath: string,\n opt?: Omit<WorkerRawOptions, \"stdout\" | \"stderr\">,\n ): WorkerProxy<TModule> {\n const internal = new WorkerInternal(filePath, opt);\n\n return new Proxy({} as WorkerProxy<TModule>, {\n get(_target, prop: string) {\n // \uC608\uC57D\uB41C \uBA54\uC11C\uB4DC: on, off, terminate\n if (prop === \"on\") {\n return (event: string, listener: (data: unknown) => void) => {\n internal.on(event, listener);\n };\n }\n if (prop === \"off\") {\n return (event: string, listener: (data: unknown) => void) => {\n internal.off(event, listener);\n };\n }\n if (prop === \"terminate\") {\n return () => internal.terminate();\n }\n\n // \uADF8 \uC678\uB294 \uC6CC\uCEE4 \uBA54\uC11C\uB4DC\uB85C \uCC98\uB9AC\n return (...args: unknown[]) => internal.call(prop, args);\n },\n });\n },\n};\n\n//#endregion\n"],
|
|
5
4
|
"mappings": "AAAA,SAAS,cAAc,oBAAoB,oBAAoB,YAAY;AAC3E,OAAO,aAAa;AACpB,OAAO,UAAU;AACjB,SAAS,qBAAqB;AAE9B,SAAS,UAAU,iBAAiB;AAGpC,MAAM,SAAS,QAAQ,QAAQ,WAAW;AAW1C,MAAM,uBAAuB,aAAsC;AAAA,EAChD;AAAA,EACT,gBAAgB;AAAA,EACP,mBAAmB,oBAAI,IAGtC;AAAA,EAEF,YAAY,UAAkB,KAAmD;AAC/E,UAAM;AAEN,UAAM,MAAM,KAAK,QAAQ,YAAY,QAAQ;AAG7C,UAAM,SAAS,KAAK,OAAO,QAAQ,OAAO,IAAI,QAAQ,WAAW,IAAI,MAAM,CAAC;AAI5E,QAAI,QAAQ,OAAO;AAEjB,YAAM,aAAa,SAAS,WAAW,SAAS,IAAI,cAAc,QAAQ,IAAI;AAC9E,WAAK,UAAU,IAAI,UAAU,KAAK,QAAQ,YAAY,SAAS,+BAA+B,GAAG;AAAA,QAC/F,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,GAAG;AAAA,QACH,KAAK;AAAA,UACH,GAAG,QAAQ;AAAA,UACX,GAAG;AAAA,QACL;AAAA,QACA,MAAM,CAAC,YAAY,GAAI,KAAK,QAAQ,CAAC,CAAE;AAAA,MACzC,CAAC;AAAA,IACH,OAAO;AAGL,YAAM,aAAa,SAAS,WAAW,SAAS,IAAI,cAAc,QAAQ,IAAI;AAC9E,WAAK,UAAU,IAAI,UAAU,YAAY;AAAA,QACvC,QAAQ;AAAA,QACR,QAAQ;AAAA,QACR,GAAG;AAAA,QACH,KAAK;AAAA,UACH,GAAG,QAAQ;AAAA,UACX,GAAG;AAAA,QACL;AAAA,MACF,CAAC;AAAA,IACH;AAGA,SAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AACvC,SAAK,QAAQ,OAAO,KAAK,QAAQ,MAAM;AAEvC,SAAK,QAAQ,GAAG,QAAQ,CAAC,SAAS;AAChC,UAAI,CAAC,KAAK,iBAAiB,SAAS,GAAG;AACrC,eAAO,MAAM,0EAAwB,IAAI,GAAG;AAE5C,aAAK,kBAAkB,IAAI,MAAM,mEAAsB,IAAI,GAAG,CAAC;AAAA,MACjE;AAAA,IACF,CAAC;AAED,SAAK,QAAQ,GAAG,SAAS,CAAC,QAAQ;AAChC,aAAO,MAAM,8BAAU,GAAG;AAE1B,WAAK,kBAAkB,GAAG;AAAA,IAC5B,CAAC;AAED,SAAK,QAAQ,GAAG,WAAW,CAAC,uBAAgC;AAC1D,YAAM,UAAU,mBAAmB,kBAAkB;AAGrD,UAAI,WAAW,QAAQ,OAAO,YAAY,YAAY,EAAE,UAAU,UAAU;AAC1E,eAAO,KAAK,gFAAoB,OAAO;AACvC;AAAA,MACF;AACA,YAAM,WAAW;AAEjB,UAAI,SAAS,SAAS,SAAS;AAC7B,aAAK,KAAK,SAAS,OAAO,SAAS,IAAI;AAAA,MACzC,WAAW,SAAS,SAAS,OAAO;AAClC,gBAAQ,OAAO,MAAM,SAAS,IAAI;AAAA,MACpC,WAAW,SAAS,SAAS,UAAU;AACrC,cAAM,UAAU,KAAK,iBAAiB,IAAI,SAAS,QAAQ,EAAE;AAC7D,YAAI,SAAS;AACX,eAAK,iBAAiB,OAAO,SAAS,QAAQ,EAAE;AAChD,kBAAQ,QAAQ,SAAS,IAAI;AAAA,QAC/B;AAAA,MACF,OAAO;AAEL,cAAM,UAAU,KAAK,iBAAiB,IAAI,SAAS,QAAQ,EAAE;AAC7D,YAAI,SAAS;AACX,eAAK,iBAAiB,OAAO,SAAS,QAAQ,EAAE;AAChD,kBAAQ,OAAO,SAAS,IAAI;AAAA,QAC9B;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,KAAkB;AAC1C,eAAW,CAAC,KAAK,EAAE,QAAQ,OAAO,CAAC,KAAK,KAAK,kBAAkB;AAC7D,aAAO,IAAI,MAAM,GAAG,IAAI,OAAO,aAAa,MAAM,GAAG,CAAC;AAAA,IACxD;AACA,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,QAAgB,QAAqC;AACxD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,UAAyB;AAAA,QAC7B,IAAI,KAAK,IAAI,EAAE,SAAS;AAAA,QACxB;AAAA,QACA;AAAA,MACF;AAEA,WAAK,iBAAiB,IAAI,QAAQ,IAAI,EAAE,QAAQ,SAAS,OAAO,CAAC;AAEjE,YAAM,aAAa,mBAAmB,OAAO;AAC7C,WAAK,QAAQ,YAAY,WAAW,QAAQ,WAAW,YAAY;AAAA,IACrE,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAA2B;AAC/B,SAAK,gBAAgB;AACrB,SAAK,kBAAkB,IAAI,MAAM,uCAAS,CAAC;AAC3C,UAAM,KAAK,QAAQ,UAAU;AAAA,EAC/B;AACF;AAoBO,MAAM,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQpB,OACE,UACA,KACsB;AACtB,UAAM,WAAW,IAAI,eAAe,UAAU,GAAG;AAEjD,WAAO,IAAI,MAAM,CAAC,GAA2B;AAAA,MAC3C,IAAI,SAAS,MAAc;AAEzB,YAAI,SAAS,MAAM;AACjB,iBAAO,CAAC,OAAe,aAAsC;AAC3D,qBAAS,GAAG,OAAO,QAAQ;AAAA,UAC7B;AAAA,QACF;AACA,YAAI,SAAS,OAAO;AAClB,iBAAO,CAAC,OAAe,aAAsC;AAC3D,qBAAS,IAAI,OAAO,QAAQ;AAAA,UAC9B;AAAA,QACF;AACA,YAAI,SAAS,aAAa;AACxB,iBAAO,MAAM,SAAS,UAAU;AAAA,QAClC;AAGA,eAAO,IAAI,SAAoB,SAAS,KAAK,MAAM,IAAI;AAAA,MACzD;AAAA,IACF,CAAC;AAAA,EACH;AACF;",
|
|
6
5
|
"names": []
|
|
7
6
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/core-node",
|
|
3
|
-
"version": "13.0.0-beta.
|
|
3
|
+
"version": "13.0.0-beta.47",
|
|
4
4
|
"description": "심플리즘 패키지 - 코어 모듈 (node)",
|
|
5
5
|
"author": "김석래",
|
|
6
6
|
"repository": {
|
|
@@ -14,13 +14,14 @@
|
|
|
14
14
|
"main": "./dist/index.js",
|
|
15
15
|
"types": "./dist/index.d.ts",
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"src"
|
|
18
19
|
],
|
|
19
20
|
"dependencies": {
|
|
20
21
|
"chokidar": "^5.0.0",
|
|
21
22
|
"consola": "^3.4.2",
|
|
22
23
|
"glob": "^13.0.2",
|
|
23
24
|
"tsx": "^4.21.0",
|
|
24
|
-
"@simplysm/core-common": "13.0.0-beta.
|
|
25
|
+
"@simplysm/core-common": "13.0.0-beta.47"
|
|
25
26
|
}
|
|
26
27
|
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { DebounceQueue } from "@simplysm/core-common";
|
|
2
|
+
import * as chokidar from "chokidar";
|
|
3
|
+
import consola from "consola";
|
|
4
|
+
import type { EventName } from "chokidar/handler.js";
|
|
5
|
+
import { type NormPath, pathNorm } from "../utils/path";
|
|
6
|
+
|
|
7
|
+
//#region Types
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 지원하는 파일 변경 이벤트 타입 목록.
|
|
11
|
+
*/
|
|
12
|
+
const FS_WATCHER_EVENTS = ["add", "addDir", "change", "unlink", "unlinkDir"] as const;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 파일 변경 이벤트 타입.
|
|
16
|
+
*/
|
|
17
|
+
export type FsWatcherEvent = (typeof FS_WATCHER_EVENTS)[number];
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 파일 변경 정보.
|
|
21
|
+
*/
|
|
22
|
+
export interface FsWatcherChangeInfo {
|
|
23
|
+
/** 변경 이벤트 타입 */
|
|
24
|
+
event: FsWatcherEvent;
|
|
25
|
+
/** 변경된 파일/디렉토리 경로 (정규화됨) */
|
|
26
|
+
path: NormPath;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
|
|
31
|
+
//#region FsWatcher
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* chokidar 기반 파일 시스템 감시 래퍼.
|
|
35
|
+
* 짧은 시간 내 발생한 이벤트를 병합하여 콜백 호출.
|
|
36
|
+
*
|
|
37
|
+
* **주의**: chokidar의 `ignoreInitial` 옵션은 내부적으로 항상 `true`로 설정된다.
|
|
38
|
+
* `options.ignoreInitial: false`를 전달하면 `onChange` 첫 호출 시 빈 배열로
|
|
39
|
+
* 콜백이 호출되지만, 실제 초기 파일 목록은 포함되지 않는다.
|
|
40
|
+
* 이는 이벤트 병합 로직과의 충돌을 방지하기 위한 의도된 동작이다.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const watcher = await FsWatcher.watch(["src/**\/*.ts"]);
|
|
44
|
+
* watcher.onChange({ delay: 300 }, (changes) => {
|
|
45
|
+
* for (const { path, event } of changes) {
|
|
46
|
+
* console.log(`${event}: ${path}`);
|
|
47
|
+
* }
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* // 종료
|
|
51
|
+
* await watcher.close();
|
|
52
|
+
*/
|
|
53
|
+
export class FsWatcher {
|
|
54
|
+
/**
|
|
55
|
+
* 파일 감시 시작 (비동기).
|
|
56
|
+
* ready 이벤트가 발생할 때까지 대기.
|
|
57
|
+
*
|
|
58
|
+
* @param paths - 감시할 파일/디렉토리 경로 또는 glob 패턴 배열
|
|
59
|
+
* @param options - chokidar 옵션
|
|
60
|
+
*/
|
|
61
|
+
static async watch(paths: string[], options?: chokidar.ChokidarOptions): Promise<FsWatcher> {
|
|
62
|
+
return new Promise<FsWatcher>((resolve, reject) => {
|
|
63
|
+
const watcher = new FsWatcher(paths, options);
|
|
64
|
+
watcher._watcher.on("ready", () => {
|
|
65
|
+
resolve(watcher);
|
|
66
|
+
});
|
|
67
|
+
watcher._watcher.on("error", reject);
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private readonly _watcher: chokidar.FSWatcher;
|
|
72
|
+
private readonly _ignoreInitial: boolean = true;
|
|
73
|
+
private readonly _debounceQueues: DebounceQueue[] = [];
|
|
74
|
+
|
|
75
|
+
private readonly _logger = consola.withTag("sd-fs-watcher");
|
|
76
|
+
|
|
77
|
+
private constructor(paths: string[], options?: chokidar.ChokidarOptions) {
|
|
78
|
+
this._watcher = chokidar.watch(paths, {
|
|
79
|
+
persistent: true,
|
|
80
|
+
...options,
|
|
81
|
+
ignoreInitial: true,
|
|
82
|
+
});
|
|
83
|
+
this._ignoreInitial = options?.ignoreInitial ?? this._ignoreInitial;
|
|
84
|
+
|
|
85
|
+
// 감시 중 발생하는 에러 로깅
|
|
86
|
+
this._watcher.on("error", (err) => {
|
|
87
|
+
this._logger.error("FsWatcher error:", err);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* 파일 변경 이벤트 핸들러 등록.
|
|
93
|
+
* 지정된 delay 시간 동안 이벤트를 모아서 한 번에 콜백 호출.
|
|
94
|
+
*
|
|
95
|
+
* @param opt.delay - 이벤트 병합 대기 시간 (ms)
|
|
96
|
+
* @param cb - 변경 이벤트 콜백
|
|
97
|
+
*/
|
|
98
|
+
onChange(opt: { delay?: number }, cb: (changeInfos: FsWatcherChangeInfo[]) => void | Promise<void>): this {
|
|
99
|
+
const fnQ = new DebounceQueue(opt.delay);
|
|
100
|
+
this._debounceQueues.push(fnQ);
|
|
101
|
+
|
|
102
|
+
let changeInfoMap = new Map<string, EventName>();
|
|
103
|
+
|
|
104
|
+
// ignoreInitial이 false면 초기에 빈 배열로 콜백 호출
|
|
105
|
+
if (!this._ignoreInitial) {
|
|
106
|
+
fnQ.run(async () => {
|
|
107
|
+
await cb([]);
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this._watcher.on("all", (event, filePath) => {
|
|
112
|
+
// 지원하는 이벤트만 처리
|
|
113
|
+
if (!FS_WATCHER_EVENTS.includes(event as FsWatcherEvent)) return;
|
|
114
|
+
|
|
115
|
+
/*
|
|
116
|
+
* 이벤트 병합 전략:
|
|
117
|
+
* 짧은 시간 내 같은 파일에 대해 여러 이벤트가 발생하면 최종 상태만 전달한다.
|
|
118
|
+
* - add + change → add (생성 직후 수정은 생성으로 간주)
|
|
119
|
+
* - add + unlink → 삭제 (생성 후 즉시 삭제는 변경 없음)
|
|
120
|
+
* - unlink + add → add (삭제 후 재생성은 생성으로 간주)
|
|
121
|
+
* - 그 외 → 최신 이벤트로 덮어씀
|
|
122
|
+
*/
|
|
123
|
+
if (!changeInfoMap.has(filePath)) {
|
|
124
|
+
changeInfoMap.set(filePath, event);
|
|
125
|
+
}
|
|
126
|
+
const prevEvent = changeInfoMap.get(filePath)!;
|
|
127
|
+
|
|
128
|
+
if (prevEvent === "add" && event === "change") {
|
|
129
|
+
// add 후 change → add 유지
|
|
130
|
+
changeInfoMap.set(filePath, "add");
|
|
131
|
+
} else if ((prevEvent === "add" && event === "unlink") || (prevEvent === "addDir" && event === "unlinkDir")) {
|
|
132
|
+
// add 후 unlink → 변경 없음 (삭제)
|
|
133
|
+
changeInfoMap.delete(filePath);
|
|
134
|
+
} else if (prevEvent === "unlink" && (event === "add" || event === "change")) {
|
|
135
|
+
// unlink 후 add/change → add (파일 재생성)
|
|
136
|
+
changeInfoMap.set(filePath, "add");
|
|
137
|
+
} else if (prevEvent === "unlinkDir" && event === "addDir") {
|
|
138
|
+
// unlinkDir 후 addDir → addDir (디렉토리 재생성)
|
|
139
|
+
changeInfoMap.set(filePath, "addDir");
|
|
140
|
+
} else {
|
|
141
|
+
changeInfoMap.set(filePath, event);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fnQ.run(async () => {
|
|
145
|
+
if (changeInfoMap.size === 0) return;
|
|
146
|
+
|
|
147
|
+
const currChangeInfoMap = changeInfoMap;
|
|
148
|
+
changeInfoMap = new Map<string, EventName>();
|
|
149
|
+
|
|
150
|
+
const changeInfos = Array.from(currChangeInfoMap.entries()).map(
|
|
151
|
+
([path, evt]): FsWatcherChangeInfo => ({
|
|
152
|
+
path: pathNorm(path),
|
|
153
|
+
event: evt as FsWatcherEvent,
|
|
154
|
+
}),
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
await cb(changeInfos);
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* 파일 감시 종료.
|
|
166
|
+
*/
|
|
167
|
+
async close(): Promise<void> {
|
|
168
|
+
for (const q of this._debounceQueues) {
|
|
169
|
+
q.dispose();
|
|
170
|
+
}
|
|
171
|
+
this._debounceQueues.length = 0;
|
|
172
|
+
await this._watcher.close();
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
//#endregion
|
package/src/index.ts
ADDED