@simplysm/core-common 13.0.0-beta.7 → 13.0.2

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.
Files changed (98) hide show
  1. package/README.md +191 -815
  2. package/dist/common.types.js +4 -4
  3. package/dist/common.types.js.map +0 -1
  4. package/dist/env.js +2 -2
  5. package/dist/env.js.map +1 -2
  6. package/dist/errors/argument-error.js +1 -1
  7. package/dist/errors/argument-error.js.map +0 -1
  8. package/dist/errors/not-implemented-error.js +1 -1
  9. package/dist/errors/not-implemented-error.js.map +0 -1
  10. package/dist/errors/sd-error.js.map +0 -1
  11. package/dist/errors/timeout-error.js +1 -1
  12. package/dist/errors/timeout-error.js.map +0 -1
  13. package/dist/extensions/arr-ext.helpers.js +4 -4
  14. package/dist/extensions/arr-ext.helpers.js.map +0 -1
  15. package/dist/extensions/arr-ext.js +9 -9
  16. package/dist/extensions/arr-ext.js.map +0 -1
  17. package/dist/extensions/arr-ext.types.js.map +0 -1
  18. package/dist/extensions/map-ext.js.map +0 -1
  19. package/dist/extensions/set-ext.js.map +0 -1
  20. package/dist/features/debounce-queue.d.ts.map +1 -1
  21. package/dist/features/debounce-queue.js +4 -4
  22. package/dist/features/debounce-queue.js.map +1 -2
  23. package/dist/features/event-emitter.js.map +0 -1
  24. package/dist/features/serial-queue.d.ts.map +1 -1
  25. package/dist/features/serial-queue.js +5 -5
  26. package/dist/features/serial-queue.js.map +1 -2
  27. package/dist/globals.js.map +0 -1
  28. package/dist/index.js +30 -30
  29. package/dist/index.js.map +0 -1
  30. package/dist/types/date-only.js +2 -2
  31. package/dist/types/date-only.js.map +0 -1
  32. package/dist/types/date-time.js +2 -2
  33. package/dist/types/date-time.js.map +0 -1
  34. package/dist/types/lazy-gc-map.d.ts.map +1 -1
  35. package/dist/types/lazy-gc-map.js +2 -2
  36. package/dist/types/lazy-gc-map.js.map +1 -2
  37. package/dist/types/time.js +2 -2
  38. package/dist/types/time.js.map +0 -1
  39. package/dist/types/uuid.js +1 -1
  40. package/dist/types/uuid.js.map +0 -1
  41. package/dist/utils/bytes.js +1 -1
  42. package/dist/utils/bytes.js.map +0 -1
  43. package/dist/utils/date-format.js.map +0 -1
  44. package/dist/utils/json.js +8 -8
  45. package/dist/utils/json.js.map +0 -1
  46. package/dist/utils/num.js.map +0 -1
  47. package/dist/utils/obj.js +5 -5
  48. package/dist/utils/obj.js.map +0 -1
  49. package/dist/utils/path.js.map +0 -1
  50. package/dist/utils/primitive.js +5 -5
  51. package/dist/utils/primitive.js.map +0 -1
  52. package/dist/utils/str.js.map +0 -1
  53. package/dist/utils/template-strings.js.map +0 -1
  54. package/dist/utils/transferable.js +4 -4
  55. package/dist/utils/transferable.js.map +0 -1
  56. package/dist/utils/wait.js +1 -1
  57. package/dist/utils/wait.js.map +0 -1
  58. package/dist/utils/xml.js.map +0 -1
  59. package/dist/zip/sd-zip.js.map +0 -1
  60. package/docs/extensions.md +381 -0
  61. package/docs/features.md +94 -0
  62. package/docs/types.md +338 -0
  63. package/docs/utils.md +631 -0
  64. package/package.json +5 -3
  65. package/src/common.types.ts +91 -0
  66. package/src/env.ts +11 -0
  67. package/src/errors/argument-error.ts +40 -0
  68. package/src/errors/not-implemented-error.ts +32 -0
  69. package/src/errors/sd-error.ts +53 -0
  70. package/src/errors/timeout-error.ts +36 -0
  71. package/src/extensions/arr-ext.helpers.ts +53 -0
  72. package/src/extensions/arr-ext.ts +777 -0
  73. package/src/extensions/arr-ext.types.ts +258 -0
  74. package/src/extensions/map-ext.ts +86 -0
  75. package/src/extensions/set-ext.ts +68 -0
  76. package/src/features/debounce-queue.ts +116 -0
  77. package/src/features/event-emitter.ts +112 -0
  78. package/src/features/serial-queue.ts +94 -0
  79. package/src/globals.ts +12 -0
  80. package/src/index.ts +55 -0
  81. package/src/types/date-only.ts +329 -0
  82. package/src/types/date-time.ts +294 -0
  83. package/src/types/lazy-gc-map.ts +244 -0
  84. package/src/types/time.ts +210 -0
  85. package/src/types/uuid.ts +113 -0
  86. package/src/utils/bytes.ts +160 -0
  87. package/src/utils/date-format.ts +239 -0
  88. package/src/utils/json.ts +230 -0
  89. package/src/utils/num.ts +97 -0
  90. package/src/utils/obj.ts +956 -0
  91. package/src/utils/path.ts +40 -0
  92. package/src/utils/primitive.ts +33 -0
  93. package/src/utils/str.ts +252 -0
  94. package/src/utils/template-strings.ts +132 -0
  95. package/src/utils/transferable.ts +269 -0
  96. package/src/utils/wait.ts +40 -0
  97. package/src/utils/xml.ts +105 -0
  98. package/src/zip/sd-zip.ts +218 -0
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/template-strings.ts"],
4
- "sourcesContent": ["/**\n * \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uD0DC\uADF8 \uD568\uC218\uB4E4\n * IDE \uCF54\uB4DC \uD558\uC774\uB77C\uC774\uD305 \uC9C0\uC6D0\uC6A9 (\uC2E4\uC81C \uB3D9\uC791\uC740 \uBB38\uC790\uC5F4 \uC870\uD569 + \uB4E4\uC5EC\uC4F0\uAE30 \uC815\uB9AC)\n */\n\n/**\n * JavaScript \uCF54\uB4DC \uD558\uC774\uB77C\uC774\uD305\uC6A9 \uD15C\uD50C\uB9BF \uD0DC\uADF8\n * @param strings \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uBC30\uC5F4\n * @param values \uBCF4\uAC04\uB41C \uAC12\uB4E4\n * @returns \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC815\uB9AC\uB41C \uBB38\uC790\uC5F4\n * @example\n * const code = js`\n * function hello() {\n * return \"world\";\n * }\n * `;\n */\nexport function js(strings: TemplateStringsArray, ...values: unknown[]): string {\n return _combine(strings, values);\n}\n\n/**\n * TypeScript \uCF54\uB4DC \uD558\uC774\uB77C\uC774\uD305\uC6A9 \uD15C\uD50C\uB9BF \uD0DC\uADF8\n * @param strings \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uBC30\uC5F4\n * @param values \uBCF4\uAC04\uB41C \uAC12\uB4E4\n * @returns \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC815\uB9AC\uB41C \uBB38\uC790\uC5F4\n * @example\n * const code = ts`\n * interface User {\n * name: string;\n * age: number;\n * }\n * `;\n */\nexport function ts(strings: TemplateStringsArray, ...values: unknown[]): string {\n return _combine(strings, values);\n}\n\n/**\n * HTML \uB9C8\uD06C\uC5C5 \uD558\uC774\uB77C\uC774\uD305\uC6A9 \uD15C\uD50C\uB9BF \uD0DC\uADF8\n * @param strings \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uBC30\uC5F4\n * @param values \uBCF4\uAC04\uB41C \uAC12\uB4E4\n * @returns \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC815\uB9AC\uB41C \uBB38\uC790\uC5F4\n * @example\n * const markup = html`\n * <div class=\"container\">\n * <span>${name}</span>\n * </div>\n * `;\n */\nexport function html(strings: TemplateStringsArray, ...values: unknown[]): string {\n return _combine(strings, values);\n}\n\n/**\n * MSSQL T-SQL \uD558\uC774\uB77C\uC774\uD305\uC6A9 \uD15C\uD50C\uB9BF \uD0DC\uADF8\n * @param strings \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uBC30\uC5F4\n * @param values \uBCF4\uAC04\uB41C \uAC12\uB4E4\n * @returns \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC815\uB9AC\uB41C \uBB38\uC790\uC5F4\n * @example\n * const query = tsql`\n * SELECT TOP 10 *\n * FROM Users\n * WHERE Name LIKE '%${keyword}%'\n * `;\n */\nexport function tsql(strings: TemplateStringsArray, ...values: unknown[]): string {\n return _combine(strings, values);\n}\n\n/**\n * MySQL SQL \uD558\uC774\uB77C\uC774\uD305\uC6A9 \uD15C\uD50C\uB9BF \uD0DC\uADF8\n * @param strings \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uBC30\uC5F4\n * @param values \uBCF4\uAC04\uB41C \uAC12\uB4E4\n * @returns \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC815\uB9AC\uB41C \uBB38\uC790\uC5F4\n * @example\n * const query = mysql`\n * SELECT *\n * FROM users\n * LIMIT 10\n * `;\n */\nexport function mysql(strings: TemplateStringsArray, ...values: unknown[]): string {\n return _combine(strings, values);\n}\n\n/**\n * PostgreSQL SQL \uD558\uC774\uB77C\uC774\uD305\uC6A9 \uD15C\uD50C\uB9BF \uD0DC\uADF8\n * @param strings \uD15C\uD50C\uB9BF \uBB38\uC790\uC5F4 \uBC30\uC5F4\n * @param values \uBCF4\uAC04\uB41C \uAC12\uB4E4\n * @returns \uB4E4\uC5EC\uC4F0\uAE30\uAC00 \uC815\uB9AC\uB41C \uBB38\uC790\uC5F4\n * @example\n * const query = pgsql`\n * SELECT *\n * FROM users\n * OFFSET 0 LIMIT 10\n * `;\n */\nexport function pgsql(strings: TemplateStringsArray, ...values: unknown[]): string {\n return _combine(strings, values);\n}\n\nfunction _combine(strings: TemplateStringsArray, values: unknown[]): string {\n const raw = strings.reduce((result, str, i) => {\n const value = values[i] !== undefined ? String(values[i]) : \"\";\n return result + str + value;\n }, \"\");\n return _trimIndent(raw);\n}\n\nfunction _trimIndent(text: string): string {\n const lines = text.split(\"\\n\");\n\n // \uCCAB/\uB9C8\uC9C0\uB9C9 \uBE48 \uC904 \uC81C\uAC70 (\uC5F0\uC18D\uB41C \uBE48 \uC904 \uBAA8\uB450 \uC81C\uAC70)\n while (lines.length > 0 && lines[0].trim() === \"\") {\n lines.shift();\n }\n while (lines.length > 0 && lines[lines.length - 1].trim() === \"\") {\n lines.pop();\n }\n\n // \uCD5C\uC18C \uB4E4\uC5EC\uC4F0\uAE30 \uACC4\uC0B0\n const minIndent = lines\n .filter((line) => line.trim() !== \"\")\n .reduce((min, line) => {\n const indent = line.match(/^ */)?.[0].length ?? 0;\n return Math.min(min, indent);\n }, Infinity);\n\n // \uB4E4\uC5EC\uC4F0\uAE30 \uC81C\uAC70\n return lines.map((line) => (line.trim() === \"\" ? \"\" : line.slice(minIndent))).join(\"\\n\");\n}\n"],
5
4
  "mappings": "AAiBO,SAAS,GAAG,YAAkC,QAA2B;AAC9E,SAAO,SAAS,SAAS,MAAM;AACjC;AAeO,SAAS,GAAG,YAAkC,QAA2B;AAC9E,SAAO,SAAS,SAAS,MAAM;AACjC;AAcO,SAAS,KAAK,YAAkC,QAA2B;AAChF,SAAO,SAAS,SAAS,MAAM;AACjC;AAcO,SAAS,KAAK,YAAkC,QAA2B;AAChF,SAAO,SAAS,SAAS,MAAM;AACjC;AAcO,SAAS,MAAM,YAAkC,QAA2B;AACjF,SAAO,SAAS,SAAS,MAAM;AACjC;AAcO,SAAS,MAAM,YAAkC,QAA2B;AACjF,SAAO,SAAS,SAAS,MAAM;AACjC;AAEA,SAAS,SAAS,SAA+B,QAA2B;AAC1E,QAAM,MAAM,QAAQ,OAAO,CAAC,QAAQ,KAAK,MAAM;AAC7C,UAAM,QAAQ,OAAO,CAAC,MAAM,SAAY,OAAO,OAAO,CAAC,CAAC,IAAI;AAC5D,WAAO,SAAS,MAAM;AAAA,EACxB,GAAG,EAAE;AACL,SAAO,YAAY,GAAG;AACxB;AAEA,SAAS,YAAY,MAAsB;AACzC,QAAM,QAAQ,KAAK,MAAM,IAAI;AAG7B,SAAO,MAAM,SAAS,KAAK,MAAM,CAAC,EAAE,KAAK,MAAM,IAAI;AACjD,UAAM,MAAM;AAAA,EACd;AACA,SAAO,MAAM,SAAS,KAAK,MAAM,MAAM,SAAS,CAAC,EAAE,KAAK,MAAM,IAAI;AAChE,UAAM,IAAI;AAAA,EACZ;AAGA,QAAM,YAAY,MACf,OAAO,CAAC,SAAS,KAAK,KAAK,MAAM,EAAE,EACnC,OAAO,CAAC,KAAK,SAAS;AA5H3B;AA6HM,UAAM,WAAS,UAAK,MAAM,KAAK,MAAhB,mBAAoB,GAAG,WAAU;AAChD,WAAO,KAAK,IAAI,KAAK,MAAM;AAAA,EAC7B,GAAG,QAAQ;AAGb,SAAO,MAAM,IAAI,CAAC,SAAU,KAAK,KAAK,MAAM,KAAK,KAAK,KAAK,MAAM,SAAS,CAAE,EAAE,KAAK,IAAI;AACzF;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,7 @@
1
- import { DateTime } from "../types/date-time";
2
- import { DateOnly } from "../types/date-only";
3
- import { Time } from "../types/time";
4
- import { Uuid } from "../types/uuid";
1
+ import { DateTime } from "../types/date-time.js";
2
+ import { DateOnly } from "../types/date-only.js";
3
+ import { Time } from "../types/time.js";
4
+ import { Uuid } from "../types/uuid.js";
5
5
  function transferableEncode(obj) {
6
6
  const transferList = [];
7
7
  const ancestors = /* @__PURE__ */ new Set();
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/transferable.ts"],
4
- "sourcesContent": ["import { DateTime } from \"../types/date-time\";\nimport { DateOnly } from \"../types/date-only\";\nimport { Time } from \"../types/time\";\nimport { Uuid } from \"../types/uuid\";\n\n/**\n * Worker \uAC04 \uC804\uC1A1 \uAC00\uB2A5\uD55C \uAC1D\uCCB4 \uD0C0\uC785\n *\n * \uC774 \uCF54\uB4DC\uC5D0\uC11C\uB294 ArrayBuffer\uB9CC \uC0AC\uC6A9\uB429\uB2C8\uB2E4.\n * @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects\n */\ntype Transferable = ArrayBuffer;\n\n/**\n * Transferable \uBCC0\uD658 \uC720\uD2F8\uB9AC\uD2F0 \uD568\uC218\n *\n * Worker \uAC04 \uB370\uC774\uD130 \uC804\uC1A1\uC744 \uC704\uD55C \uC9C1\uB82C\uD654/\uC5ED\uC9C1\uB82C\uD654\uB97C \uC218\uD589\uD569\uB2C8\uB2E4.\n * structuredClone\uC774 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uCEE4\uC2A4\uD140 \uD0C0\uC785\uB4E4\uC744 \uCC98\uB9AC\uD569\uB2C8\uB2E4.\n *\n * \uC9C0\uC6D0 \uD0C0\uC785:\n * - Date, DateTime, DateOnly, Time, Uuid, RegExp\n * - Error (cause, code, detail \uD3EC\uD568)\n * - Uint8Array (\uB2E4\uB978 TypedArray\uB294 \uBBF8\uC9C0\uC6D0, \uC77C\uBC18 \uAC1D\uCCB4\uB85C \uCC98\uB9AC\uB428)\n * - Array, Map, Set, \uC77C\uBC18 \uAC1D\uCCB4\n *\n * @note \uC21C\uD658 \uCC38\uC870\uAC00 \uC788\uC73C\uBA74 transferableEncode \uC2DC TypeError \uBC1C\uC0DD (\uACBD\uB85C \uC815\uBCF4 \uD3EC\uD568)\n * @note \uB3D9\uC77C \uAC1D\uCCB4\uAC00 \uC5EC\uB7EC \uACF3\uC5D0\uC11C \uCC38\uC870\uB418\uBA74 \uCE90\uC2DC\uB41C \uC778\uCF54\uB529 \uACB0\uACFC\uB97C \uC7AC\uC0AC\uC6A9\uD569\uB2C8\uB2E4\n *\n * @example\n * // Worker\uB85C \uB370\uC774\uD130 \uC804\uC1A1\n * const { result, transferList } = transferableEncode(data);\n * worker.postMessage(result, transferList);\n *\n * // Worker\uC5D0\uC11C \uB370\uC774\uD130 \uC218\uC2E0\n * const decoded = transferableDecode(event.data);\n */\n\n//#region encode\n\n/**\n * \uC2EC\uD50C\uB9AC\uC998 \uD0C0\uC785\uC744 \uC0AC\uC6A9\uD55C \uAC1D\uCCB4\uB97C \uC77C\uBC18 \uAC1D\uCCB4\uB85C \uBCC0\uD658\n * Worker\uC5D0 \uC804\uC1A1\uD560 \uC218 \uC788\uB294 \uD615\uD0DC\uB85C \uC9C1\uB82C\uD654\n *\n * @throws \uC21C\uD658 \uCC38\uC870 \uAC10\uC9C0 \uC2DC TypeError\n */\nexport function transferableEncode(obj: unknown): {\n result: unknown;\n transferList: Transferable[];\n} {\n const transferList: Transferable[] = [];\n const ancestors = new Set<object>();\n const cache = new Map<object, unknown>();\n const result = encodeImpl(obj, transferList, [], ancestors, cache);\n return { result, transferList };\n}\n\nfunction encodeImpl(\n obj: unknown,\n transferList: Transferable[],\n path: (string | number)[],\n ancestors: Set<object>,\n cache: Map<object, unknown>,\n): unknown {\n if (obj == null) return obj;\n\n // \uAC1D\uCCB4 \uD0C0\uC785 \uCC98\uB9AC: \uC21C\uD658 \uAC10\uC9C0 + \uCE90\uC2DC\n if (typeof obj === \"object\") {\n // \uC21C\uD658 \uCC38\uC870 \uAC10\uC9C0 (\uD604\uC7AC \uC7AC\uADC0 \uC2A4\uD0DD\uC5D0 \uC788\uB294 \uAC1D\uCCB4)\n if (ancestors.has(obj)) {\n const currentPath = path.length > 0 ? path.join(\".\") : \"root\";\n throw new TypeError(`\uC21C\uD658 \uCC38\uC870\uAC00 \uAC10\uC9C0\uB418\uC5C8\uC2B5\uB2C8\uB2E4: ${currentPath}`);\n }\n\n // \uCE90\uC2DC \uD788\uD2B8 \u2192 \uC774\uC804 \uC778\uCF54\uB529 \uACB0\uACFC \uC7AC\uC0AC\uC6A9\n const cached = cache.get(obj);\n if (cached !== undefined) return cached;\n\n // \uC7AC\uADC0 \uC2A4\uD0DD\uC5D0 \uCD94\uAC00\n ancestors.add(obj);\n }\n\n let result: unknown;\n\n try {\n // 1. Uint8Array\n if (obj instanceof Uint8Array) {\n // SharedArrayBuffer\uB294 \uC774\uBBF8 \uACF5\uC720 \uBA54\uBAA8\uB9AC\uC774\uBBC0\uB85C transferList\uC5D0 \uCD94\uAC00\uD558\uC9C0 \uC54A\uC74C\n // ArrayBuffer\uB9CC transferList\uC5D0 \uCD94\uAC00\n const isSharedArrayBuffer = typeof SharedArrayBuffer !== \"undefined\" && obj.buffer instanceof SharedArrayBuffer;\n const buffer = obj.buffer as ArrayBuffer;\n if (!isSharedArrayBuffer && !transferList.includes(buffer)) {\n transferList.push(buffer);\n }\n result = obj;\n }\n // 2. \uD2B9\uC218 \uD0C0\uC785 \uBCC0\uD658 (JSON.stringify \uC5C6\uC774 \uAD6C\uC870\uCCB4\uB85C \uBCC0\uD658)\n else if (obj instanceof Date) {\n result = { __type__: \"Date\", data: obj.getTime() };\n } else if (obj instanceof DateTime) {\n result = { __type__: \"DateTime\", data: obj.tick };\n } else if (obj instanceof DateOnly) {\n result = { __type__: \"DateOnly\", data: obj.tick };\n } else if (obj instanceof Time) {\n result = { __type__: \"Time\", data: obj.tick };\n } else if (obj instanceof Uuid) {\n result = { __type__: \"Uuid\", data: obj.toString() };\n } else if (obj instanceof RegExp) {\n result = { __type__: \"RegExp\", data: { source: obj.source, flags: obj.flags } };\n } else if (obj instanceof Error) {\n const errObj = obj as Error & {\n code?: unknown;\n detail?: unknown;\n };\n result = {\n __type__: \"Error\",\n data: {\n name: errObj.name,\n message: errObj.message,\n stack: errObj.stack,\n ...(errObj.code !== undefined ? { code: errObj.code } : {}),\n ...(errObj.detail !== undefined\n ? { detail: encodeImpl(errObj.detail, transferList, [...path, \"detail\"], ancestors, cache) }\n : {}),\n ...(errObj.cause !== undefined\n ? { cause: encodeImpl(errObj.cause, transferList, [...path, \"cause\"], ancestors, cache) }\n : {}),\n },\n };\n }\n // 3. \uBC30\uC5F4 \uC7AC\uADC0 \uC21C\uD68C\n else if (Array.isArray(obj)) {\n result = obj.map((item, idx) => encodeImpl(item, transferList, [...path, idx], ancestors, cache));\n }\n // 4. Map \uC7AC\uADC0 \uC21C\uD68C\n else if (obj instanceof Map) {\n let idx = 0;\n result = new Map(\n Array.from(obj.entries()).map(([k, v]) => {\n const keyPath = [...path, `Map[${idx}].key`];\n const valuePath = [...path, `Map[${idx}].value`];\n idx++;\n return [\n encodeImpl(k, transferList, keyPath, ancestors, cache),\n encodeImpl(v, transferList, valuePath, ancestors, cache),\n ];\n }),\n );\n }\n // 5. Set \uC7AC\uADC0 \uC21C\uD68C\n else if (obj instanceof Set) {\n let idx = 0;\n result = new Set(\n Array.from(obj).map((v) => encodeImpl(v, transferList, [...path, `Set[${idx++}]`], ancestors, cache)),\n );\n }\n // 6. \uC77C\uBC18 \uAC1D\uCCB4 \uC7AC\uADC0 \uC21C\uD68C\n else if (typeof obj === \"object\") {\n const res: Record<string, unknown> = {};\n const record = obj as Record<string, unknown>;\n for (const key of Object.keys(record)) {\n res[key] = encodeImpl(record[key], transferList, [...path, key], ancestors, cache);\n }\n result = res;\n }\n // 7. \uC6D0\uC2DC \uD0C0\uC785\n else {\n return obj;\n }\n\n // \uCE90\uC2DC \uC800\uC7A5 (\uC131\uACF5 \uC2DC\uC5D0\uB9CC)\n if (typeof obj === \"object\") {\n cache.set(obj, result);\n }\n\n return result;\n } finally {\n // \uC7AC\uADC0 \uC2A4\uD0DD\uC5D0\uC11C \uC81C\uAC70 (\uC608\uC678 \uC2DC\uC5D0\uB3C4 \uBC18\uB4DC\uC2DC \uC2E4\uD589)\n if (typeof obj === \"object\") {\n ancestors.delete(obj);\n }\n }\n}\n\n//#endregion\n\n//#region decode\n\n/**\n * serialize \uAC1D\uCCB4\uB97C \uC2EC\uD50C\uB9AC\uC998 \uD0C0\uC785 \uC0AC\uC6A9 \uAC1D\uCCB4\uB85C \uBCC0\uD658\n * Worker\uB85C\uBD80\uD130 \uBC1B\uC740 \uB370\uC774\uD130\uB97C \uC5ED\uC9C1\uB82C\uD654\n */\nexport function transferableDecode(obj: unknown): unknown {\n if (obj == null) return obj;\n\n // 1. \uD2B9\uC218 \uD0C0\uC785 \uBCF5\uC6D0\n if (typeof obj === \"object\" && \"__type__\" in obj && \"data\" in obj) {\n const typed = obj as { __type__: string; data: unknown };\n const data = typed.data;\n\n if (typed.__type__ === \"Date\" && typeof data === \"number\") return new Date(data);\n if (typed.__type__ === \"DateTime\" && typeof data === \"number\") return new DateTime(data);\n if (typed.__type__ === \"DateOnly\" && typeof data === \"number\") return new DateOnly(data);\n if (typed.__type__ === \"Time\" && typeof data === \"number\") return new Time(data);\n if (typed.__type__ === \"Uuid\" && typeof data === \"string\") return new Uuid(data);\n if (typed.__type__ === \"RegExp\" && typeof data === \"object\" && data !== null) {\n const regexData = data as { source: string; flags: string };\n return new RegExp(regexData.source, regexData.flags);\n }\n if (typed.__type__ === \"Error\" && typeof data === \"object\" && data !== null) {\n const errorData = data as {\n name: string;\n message: string;\n stack?: string;\n code?: unknown;\n cause?: unknown;\n detail?: unknown;\n };\n const err = new Error(errorData.message) as Error & {\n code?: unknown;\n detail?: unknown;\n };\n\n err.name = errorData.name;\n err.stack = errorData.stack;\n\n if (errorData.code !== undefined) err.code = errorData.code;\n if (errorData.cause !== undefined) (err as Error).cause = transferableDecode(errorData.cause);\n if (errorData.detail !== undefined) err.detail = transferableDecode(errorData.detail);\n return err;\n }\n }\n\n // 2. \uBC30\uC5F4 \uC7AC\uADC0 (\uC0C8 \uBC30\uC5F4 \uC0DD\uC131)\n if (Array.isArray(obj)) {\n return obj.map((item) => transferableDecode(item));\n }\n\n // 3. Map \uC7AC\uADC0\n if (obj instanceof Map) {\n const newMap = new Map<unknown, unknown>();\n for (const [k, v] of obj) {\n newMap.set(transferableDecode(k), transferableDecode(v));\n }\n return newMap;\n }\n\n // 4. Set \uC7AC\uADC0\n if (obj instanceof Set) {\n const newSet = new Set<unknown>();\n for (const v of obj) {\n newSet.add(transferableDecode(v));\n }\n return newSet;\n }\n\n // 5. \uAC1D\uCCB4 \uC7AC\uADC0 (\uC0C8 \uAC1D\uCCB4 \uC0DD\uC131)\n if (typeof obj === \"object\") {\n const record = obj as Record<string, unknown>;\n const result: Record<string, unknown> = {};\n for (const key of Object.keys(record)) {\n result[key] = transferableDecode(record[key]);\n }\n return result;\n }\n\n return obj;\n}\n\n//#endregion\n"],
5
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -1,4 +1,4 @@
1
- import { TimeoutError } from "../errors/timeout-error";
1
+ import { TimeoutError } from "../errors/timeout-error.js";
2
2
  async function waitUntil(forwarder, milliseconds, maxCount) {
3
3
  let count = 0;
4
4
  while (!await forwarder()) {
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/wait.ts"],
4
- "sourcesContent": ["/**\n * \uB300\uAE30 \uC720\uD2F8\uB9AC\uD2F0 \uD568\uC218\n */\nimport { TimeoutError } from \"../errors/timeout-error\";\n\n/**\n * \uC870\uAC74\uC774 \uCC38\uC774 \uB420 \uB54C\uAE4C\uC9C0 \uB300\uAE30\n * @param forwarder \uC870\uAC74 \uD568\uC218\n * @param milliseconds \uCCB4\uD06C \uAC04\uACA9 (\uAE30\uBCF8: 100ms)\n * @param maxCount \uCD5C\uB300 \uC2DC\uB3C4 \uD69F\uC218 (undefined\uBA74 \uBB34\uC81C\uD55C)\n *\n * @note \uC870\uAC74\uC774 \uCCAB \uBC88\uC9F8 \uD638\uCD9C\uC5D0\uC11C true\uBA74 \uC989\uC2DC \uBC18\uD658\uB429\uB2C8\uB2E4.\n * @example\n * // maxCount=3: \uCD5C\uB300 3\uBC88 \uC870\uAC74 \uD655\uC778 \uD6C4 \uBAA8\uB450 false\uBA74 TimeoutError\n * await waitUntil(() => someCondition, 100, 3);\n * @throws TimeoutError \uCD5C\uB300 \uC2DC\uB3C4 \uD69F\uC218 \uCD08\uACFC \uC2DC\n */\nexport async function waitUntil(\n forwarder: () => boolean | Promise<boolean>,\n milliseconds?: number,\n maxCount?: number,\n): Promise<void> {\n let count = 0;\n while (!(await forwarder())) {\n count++;\n if (maxCount !== undefined && count >= maxCount) {\n throw new TimeoutError(count);\n }\n\n await waitTime(milliseconds ?? 100);\n }\n}\n\n/**\n * \uC9C0\uC815\uB41C \uC2DC\uAC04\uB9CC\uD07C \uB300\uAE30\n * @param millisecond \uB300\uAE30 \uC2DC\uAC04 (ms)\n */\nexport async function waitTime(millisecond: number): Promise<void> {\n return new Promise<void>((resolve) => setTimeout(resolve, millisecond));\n}\n"],
5
4
  "mappings": "AAGA,SAAS,oBAAoB;AAc7B,eAAsB,UACpB,WACA,cACA,UACe;AACf,MAAI,QAAQ;AACZ,SAAO,CAAE,MAAM,UAAU,GAAI;AAC3B;AACA,QAAI,aAAa,UAAa,SAAS,UAAU;AAC/C,YAAM,IAAI,aAAa,KAAK;AAAA,IAC9B;AAEA,UAAM,SAAS,gBAAgB,GAAG;AAAA,EACpC;AACF;AAMA,eAAsB,SAAS,aAAoC;AACjE,SAAO,IAAI,QAAc,CAAC,YAAY,WAAW,SAAS,WAAW,CAAC;AACxE;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/xml.ts"],
4
- "sourcesContent": ["/**\n * XML \uBCC0\uD658 \uC720\uD2F8\uB9AC\uD2F0\n */\nimport type { XmlBuilderOptions } from \"fast-xml-parser\";\nimport { XMLBuilder, XMLParser } from \"fast-xml-parser\";\n\n//#region parse\n\n/**\n * XML \uBB38\uC790\uC5F4\uC744 \uAC1D\uCCB4\uB85C \uD30C\uC2F1\n * @param str XML \uBB38\uC790\uC5F4\n * @param options \uC635\uC158\n * @param options.stripTagPrefix \uD0DC\uADF8 prefix \uC81C\uAC70 \uC5EC\uBD80 (namespace)\n * @returns \uD30C\uC2F1\uB41C \uAC1D\uCCB4. \uAD6C\uC870:\n * - \uC18D\uC131: `$` \uAC1D\uCCB4\uC5D0 \uADF8\uB8F9\uD654\n * - \uD14D\uC2A4\uD2B8 \uB178\uB4DC: `_` \uD0A4\uC5D0 \uC800\uC7A5\n * - \uC790\uC2DD \uC694\uC18C: \uBC30\uC5F4\uB85C \uBCC0\uD658 (\uB8E8\uD2B8 \uC694\uC18C \uC81C\uC678)\n * @example\n * xmlParse('<root id=\"1\"><item>hello</item></root>');\n * // { root: { $: { id: \"1\" }, item: [{ _: \"hello\" }] } }\n */\nexport function xmlParse(str: string, options?: { stripTagPrefix?: boolean }): unknown {\n const result = new XMLParser({\n ignoreAttributes: false,\n attributeNamePrefix: \"\",\n attributesGroupName: \"$\",\n parseAttributeValue: false,\n parseTagValue: false,\n textNodeName: \"_\",\n isArray: (_tagName: string, jPath: string, _isLeafNode: boolean, isAttribute: boolean) => {\n return !isAttribute && jPath.split(\".\").length > 1;\n },\n }).parse(str) as unknown;\n return options?.stripTagPrefix ? stripTagPrefix(result) : result;\n}\n\n//#endregion\n\n//#region stringify\n\n/**\n * \uAC1D\uCCB4\uB97C XML \uBB38\uC790\uC5F4\uB85C \uC9C1\uB82C\uD654\n * @param obj \uC9C1\uB82C\uD654\uD560 \uAC1D\uCCB4\n * @param options fast-xml-parser XmlBuilderOptions (\uC120\uD0DD)\n * @returns XML \uBB38\uC790\uC5F4\n * @example\n * xmlStringify({\n * root: {\n * $: { id: \"1\" },\n * item: [{ _: \"hello\" }, { _: \"world\" }],\n * },\n * });\n * // '<root id=\"1\"><item>hello</item><item>world</item></root>'\n */\nexport function xmlStringify(obj: unknown, options?: XmlBuilderOptions): string {\n return new XMLBuilder({\n ignoreAttributes: false,\n attributeNamePrefix: \"\",\n attributesGroupName: \"$\",\n suppressBooleanAttributes: false,\n textNodeName: \"_\",\n ...options,\n }).build(obj);\n}\n\n//#endregion\n\n//#region private\n\n/**\n * \uD0DC\uADF8 \uC774\uB984\uC5D0\uC11C namespace prefix \uC81C\uAC70\n * @note XML \uD30C\uC2F1 \uACB0\uACFC\uC5D0\uC11C \"ns:tag\" \uD615\uD0DC\uC758 namespace prefix\uB97C \uC81C\uAC70\uD558\uC5EC \uD0DC\uADF8 \uC774\uB984\uB9CC \uB0A8\uAE34\uB2E4.\n * \uC774\uB97C \uD1B5\uD574 namespace\uB97C \uACE0\uB824\uD558\uC9C0 \uC54A\uACE0 \uC77C\uAD00\uB41C \uBC29\uC2DD\uC73C\uB85C XML \uB370\uC774\uD130\uC5D0 \uC811\uADFC\uD560 \uC218 \uC788\uB2E4.\n * \uB2E8, \uC18D\uC131(attribute)\uC740 prefix\uB97C \uC720\uC9C0\uD55C\uB2E4.\n */\nfunction stripTagPrefix(obj: unknown): unknown {\n if (Array.isArray(obj)) {\n return obj.map((item) => stripTagPrefix(item));\n }\n\n if (typeof obj === \"object\" && obj !== null) {\n const newObj: Record<string, unknown> = {};\n const record = obj as Record<string, unknown>;\n\n for (const key of Object.keys(record)) {\n const value = record[key];\n\n // Attribute\uB294 prefix\uB97C \uC81C\uAC70\uD558\uBA74 \uC548 \uB41C\uB2E4.\n if (key === \"$\") {\n newObj[key] = value;\n } else {\n // \uD0DC\uADF8 \uC774\uB984\uC5D0\uC11C\uB9CC \uCCAB \uBC88\uC9F8 \":\"\uC744 \uAE30\uC900\uC73C\uB85C prefix \uC81C\uAC70\n const colonIndex = key.indexOf(\":\");\n const cleanKey = colonIndex !== -1 ? key.slice(colonIndex + 1) : key;\n newObj[cleanKey] = stripTagPrefix(value);\n }\n }\n\n return newObj;\n }\n\n return obj;\n}\n\n//#endregion\n"],
5
4
  "mappings": "AAIA,SAAS,YAAY,iBAAiB;AAiB/B,SAAS,SAAS,KAAa,SAAiD;AACrF,QAAM,SAAS,IAAI,UAAU;AAAA,IAC3B,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,eAAe;AAAA,IACf,cAAc;AAAA,IACd,SAAS,CAAC,UAAkB,OAAe,aAAsB,gBAAyB;AACxF,aAAO,CAAC,eAAe,MAAM,MAAM,GAAG,EAAE,SAAS;AAAA,IACnD;AAAA,EACF,CAAC,EAAE,MAAM,GAAG;AACZ,UAAO,mCAAS,kBAAiB,eAAe,MAAM,IAAI;AAC5D;AAoBO,SAAS,aAAa,KAAc,SAAqC;AAC9E,SAAO,IAAI,WAAW;AAAA,IACpB,kBAAkB;AAAA,IAClB,qBAAqB;AAAA,IACrB,qBAAqB;AAAA,IACrB,2BAA2B;AAAA,IAC3B,cAAc;AAAA,IACd,GAAG;AAAA,EACL,CAAC,EAAE,MAAM,GAAG;AACd;AAYA,SAAS,eAAe,KAAuB;AAC7C,MAAI,MAAM,QAAQ,GAAG,GAAG;AACtB,WAAO,IAAI,IAAI,CAAC,SAAS,eAAe,IAAI,CAAC;AAAA,EAC/C;AAEA,MAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,UAAM,SAAkC,CAAC;AACzC,UAAM,SAAS;AAEf,eAAW,OAAO,OAAO,KAAK,MAAM,GAAG;AACrC,YAAM,QAAQ,OAAO,GAAG;AAGxB,UAAI,QAAQ,KAAK;AACf,eAAO,GAAG,IAAI;AAAA,MAChB,OAAO;AAEL,cAAM,aAAa,IAAI,QAAQ,GAAG;AAClC,cAAM,WAAW,eAAe,KAAK,IAAI,MAAM,aAAa,CAAC,IAAI;AACjE,eAAO,QAAQ,IAAI,eAAe,KAAK;AAAA,MACzC;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAEA,SAAO;AACT;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/zip/sd-zip.ts"],
4
- "sourcesContent": ["/**\n * ZIP \uD30C\uC77C \uCC98\uB9AC \uC720\uD2F8\uB9AC\uD2F0\n */\nimport type { FileEntry } from \"@zip.js/zip.js\";\nimport { BlobReader, Uint8ArrayReader, Uint8ArrayWriter, ZipReader, ZipWriter } from \"@zip.js/zip.js\";\nimport type { Bytes } from \"../common.types\";\n\nexport interface ZipArchiveProgress {\n fileName: string;\n totalSize: number;\n extractedSize: number;\n}\n\n/**\n * ZIP \uC544\uCE74\uC774\uBE0C \uCC98\uB9AC \uD074\uB798\uC2A4\n *\n * ZIP \uD30C\uC77C\uC758 \uC77D\uAE30, \uC4F0\uAE30, \uC555\uCD95/\uD574\uC81C\uB97C \uCC98\uB9AC\uD569\uB2C8\uB2E4.\n * \uB0B4\uBD80 \uCE90\uC2DC\uB97C \uC0AC\uC6A9\uD558\uC5EC \uB3D9\uC77C \uD30C\uC77C\uC758 \uC911\uBCF5 \uC555\uCD95 \uD574\uC81C\uB97C \uBC29\uC9C0\uD569\uB2C8\uB2E4.\n *\n * @example\n * // ZIP \uD30C\uC77C \uC77D\uAE30\n * await using archive = new ZipArchive(zipBytes);\n * const content = await archive.get(\"file.txt\");\n *\n * @example\n * // ZIP \uD30C\uC77C \uC0DD\uC131\n * await using archive = new ZipArchive();\n * archive.write(\"file.txt\", textBytes);\n * archive.write(\"data.json\", jsonBytes);\n * const zipBytes = await archive.compress();\n *\n * @example\n * // \uC804\uCCB4 \uC555\uCD95 \uD574\uC81C (\uC9C4\uD589\uB960 \uD45C\uC2DC)\n * await using archive = new ZipArchive(zipBytes);\n * const files = await archive.extractAll((progress) => {\n * console.log(`${progress.fileName}: ${progress.extractedSize}/${progress.totalSize}`);\n * });\n */\nexport class ZipArchive {\n private readonly _reader?: ZipReader<Blob | Bytes>;\n private readonly _cache = new Map<string, Bytes | undefined>();\n private _entries?: Awaited<ReturnType<ZipReader<Blob | Bytes>[\"getEntries\"]>>;\n\n /**\n * ZipArchive \uC0DD\uC131\n * @param data ZIP \uB370\uC774\uD130 (\uC0DD\uB7B5 \uC2DC \uC0C8 \uC544\uCE74\uC774\uBE0C \uC0DD\uC131)\n */\n constructor(data?: Blob | Bytes) {\n if (!data) return;\n\n if (data instanceof Uint8Array) {\n this._reader = new ZipReader(new Uint8ArrayReader(data));\n } else {\n this._reader = new ZipReader(new BlobReader(data));\n }\n }\n\n private async _getEntries() {\n if (this._entries == null && this._reader != null) {\n this._entries = await this._reader.getEntries();\n }\n return this._entries;\n }\n\n //#region extractAll\n /**\n * \uBAA8\uB4E0 \uD30C\uC77C\uC744 \uC555\uCD95 \uD574\uC81C\n * @param progressCallback \uC9C4\uD589\uB960 \uCF5C\uBC31\n */\n async extractAll(progressCallback?: (progress: ZipArchiveProgress) => void): Promise<Map<string, Bytes | undefined>> {\n const entries = await this._getEntries();\n if (entries == null) return this._cache;\n\n // \uC555\uCD95 \uD574\uC81C \uB300\uC0C1 \uD06C\uAE30 \uCD1D\uD569 \uACC4\uC0B0\n const totalSize = entries.filter((e) => !e.directory).reduce((acc, e) => acc + e.uncompressedSize, 0);\n\n let totalExtracted = 0;\n for (const entry of entries) {\n if (entry.directory) continue;\n\n progressCallback?.({\n fileName: entry.filename,\n totalSize: totalSize,\n extractedSize: totalExtracted,\n });\n\n const entryBytes =\n this._cache.get(entry.filename) ??\n (await entry.getData(new Uint8ArrayWriter(), {\n onprogress: (extracted) => {\n const currentTotal = totalExtracted + extracted;\n\n progressCallback?.({\n fileName: entry.filename,\n totalSize: totalSize,\n extractedSize: currentTotal,\n });\n\n return undefined;\n },\n }));\n\n this._cache.set(entry.filename, entryBytes);\n\n // \uAC1C\uBCC4 \uD30C\uC77C\uC774 \uB05D\uB098\uBA74 \uB204\uC801 \uCC98\uB9AC\n totalExtracted += entry.uncompressedSize;\n\n progressCallback?.({\n fileName: entry.filename,\n totalSize: totalSize,\n extractedSize: totalExtracted,\n });\n }\n\n return this._cache;\n }\n //#endregion\n\n //#region get\n /**\n * \uD2B9\uC815 \uD30C\uC77C \uC555\uCD95 \uD574\uC81C\n * @param fileName \uD30C\uC77C \uC774\uB984\n */\n async get(fileName: string): Promise<Bytes | undefined> {\n if (this._cache.has(fileName)) {\n return this._cache.get(fileName);\n }\n\n const entries = await this._getEntries();\n if (entries == null) {\n this._cache.set(fileName, undefined);\n return undefined;\n }\n\n const entry = entries.find((item) => item.filename === fileName) as FileEntry | undefined;\n if (!entry) {\n this._cache.set(fileName, undefined);\n return undefined;\n }\n\n const bytes = await entry.getData(new Uint8ArrayWriter());\n this._cache.set(fileName, bytes);\n return bytes;\n }\n //#endregion\n\n //#region exists\n /**\n * \uD30C\uC77C \uC874\uC7AC \uC5EC\uBD80 \uD655\uC778\n * @param fileName \uD30C\uC77C \uC774\uB984\n */\n async exists(fileName: string): Promise<boolean> {\n if (this._cache.has(fileName)) {\n return this._cache.get(fileName) != null;\n }\n\n const entries = await this._getEntries();\n if (entries == null) {\n return false;\n }\n\n const entry = entries.find((item) => item.filename === fileName) as FileEntry | undefined;\n return entry !== undefined;\n }\n //#endregion\n\n //#region write\n /**\n * \uD30C\uC77C \uC4F0\uAE30 (\uCE90\uC2DC\uC5D0 \uC800\uC7A5)\n * @param fileName \uD30C\uC77C \uC774\uB984\n * @param bytes \uD30C\uC77C \uB0B4\uC6A9\n */\n write(fileName: string, bytes: Bytes): void {\n this._cache.set(fileName, bytes);\n }\n //#endregion\n\n //#region compress\n /**\n * \uCE90\uC2DC\uB41C \uD30C\uC77C\uB4E4\uC744 ZIP\uC73C\uB85C \uC555\uCD95\n *\n * @remarks\n * \uB0B4\uBD80\uC801\uC73C\uB85C `extractAll()`\uC744 \uD638\uCD9C\uD558\uC5EC \uBAA8\uB4E0 \uD30C\uC77C\uC744 \uBA54\uBAA8\uB9AC\uC5D0 \uB85C\uB4DC\uD55C \uD6C4 \uC555\uCD95\uD569\uB2C8\uB2E4.\n * \uB300\uC6A9\uB7C9 ZIP \uD30C\uC77C\uC758 \uACBD\uC6B0 \uBA54\uBAA8\uB9AC \uC0AC\uC6A9\uB7C9\uC5D0 \uC8FC\uC758\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4.\n */\n async compress(): Promise<Bytes> {\n const fileMap = await this.extractAll();\n\n const writer = new ZipWriter(new Uint8ArrayWriter());\n\n for (const key of fileMap.keys()) {\n const fileBytes = fileMap.get(key);\n if (!fileBytes) continue;\n\n await writer.add(key, new Uint8ArrayReader(fileBytes));\n }\n\n return writer.close();\n }\n //#endregion\n\n //#region close\n /**\n * \uB9AC\uB354 \uB2EB\uAE30 \uBC0F \uCE90\uC2DC \uC815\uB9AC\n */\n async close(): Promise<void> {\n await this._reader?.close();\n this._cache.clear();\n }\n\n /**\n * await using \uC9C0\uC6D0\n */\n async [Symbol.asyncDispose](): Promise<void> {\n await this.close();\n }\n //#endregion\n}\n"],
5
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -0,0 +1,381 @@
1
+ # Extensions
2
+
3
+ Array, Map, Set prototype extensions. Activated by `import "@simplysm/core-common"`.
4
+
5
+ ## Array extension methods
6
+
7
+ ### Query
8
+
9
+ #### single
10
+
11
+ Return single element (error if 2+).
12
+
13
+ ```typescript
14
+ import "@simplysm/core-common";
15
+
16
+ const users = [{ id: 1, name: "Alice" }];
17
+ users.single((u) => u.id === 1); // { id: 1, name: "Alice" }
18
+ ```
19
+
20
+ #### first
21
+
22
+ Return first element.
23
+
24
+ ```typescript
25
+ users.first(); // { id: 1, name: "Alice" }
26
+ ```
27
+
28
+ #### last
29
+
30
+ Return last element.
31
+
32
+ ```typescript
33
+ users.last(); // Last user
34
+ ```
35
+
36
+ ---
37
+
38
+ ### Filtering
39
+
40
+ #### filterExists
41
+
42
+ Remove `null`/`undefined`.
43
+
44
+ ```typescript
45
+ [1, null, 2, undefined, 3].filterExists(); // [1, 2, 3]
46
+ ```
47
+
48
+ #### ofType
49
+
50
+ Filter by type (`PrimitiveTypeStr` or constructor).
51
+
52
+ ```typescript
53
+ import "@simplysm/core-common";
54
+ ```
55
+
56
+ #### filterAsync
57
+
58
+ Async filter.
59
+
60
+ ```typescript
61
+ import "@simplysm/core-common";
62
+ ```
63
+
64
+ ---
65
+
66
+ ### Mapping/Transformation
67
+
68
+ #### mapAsync
69
+
70
+ Async mapping (sequential execution).
71
+
72
+ ```typescript
73
+ await ids.mapAsync(async (id) => await fetchUser(id));
74
+ ```
75
+
76
+ #### mapMany
77
+
78
+ flat + filterExists.
79
+
80
+ ```typescript
81
+ import "@simplysm/core-common";
82
+ ```
83
+
84
+ #### mapManyAsync
85
+
86
+ Async mapMany.
87
+
88
+ ```typescript
89
+ import "@simplysm/core-common";
90
+ ```
91
+
92
+ #### parallelAsync
93
+
94
+ Parallel async mapping (`Promise.all`).
95
+
96
+ ```typescript
97
+ await ids.parallelAsync(async (id) => await fetchUser(id));
98
+ ```
99
+
100
+ ---
101
+
102
+ ### Grouping/Transformation
103
+
104
+ #### groupBy
105
+
106
+ Group by key.
107
+
108
+ ```typescript
109
+ const users = [
110
+ { id: 1, name: "Alice", dept: "dev" },
111
+ { id: 2, name: "Bob", dept: "dev" },
112
+ { id: 3, name: "Charlie", dept: "hr" },
113
+ ];
114
+
115
+ users.groupBy((u) => u.dept);
116
+ // [{ key: "dev", values: [...] }, { key: "hr", values: [...] }]
117
+ ```
118
+
119
+ #### toMap
120
+
121
+ Convert to Map (error on duplicate key).
122
+
123
+ ```typescript
124
+ users.toMap((u) => u.id); // Map<number, User>
125
+ ```
126
+
127
+ #### toMapAsync
128
+
129
+ Async Map conversion.
130
+
131
+ ```typescript
132
+ import "@simplysm/core-common";
133
+ ```
134
+
135
+ #### toArrayMap
136
+
137
+ Convert to `Map<K, V[]>`.
138
+
139
+ ```typescript
140
+ users.toArrayMap((u) => u.dept); // Map<string, User[]>
141
+ ```
142
+
143
+ #### toSetMap
144
+
145
+ Convert to `Map<K, Set<V>>`.
146
+
147
+ ```typescript
148
+ import "@simplysm/core-common";
149
+ ```
150
+
151
+ #### toMapValues
152
+
153
+ Aggregate Map by group.
154
+
155
+ ```typescript
156
+ import "@simplysm/core-common";
157
+ ```
158
+
159
+ #### toObject
160
+
161
+ Convert to `Record<string, V>`.
162
+
163
+ ```typescript
164
+ import "@simplysm/core-common";
165
+ ```
166
+
167
+ #### toTree
168
+
169
+ Convert to tree structure.
170
+
171
+ ```typescript
172
+ import "@simplysm/core-common";
173
+ ```
174
+
175
+ ---
176
+
177
+ ### Deduplication
178
+
179
+ #### distinct
180
+
181
+ Remove duplicates (return new array).
182
+
183
+ ```typescript
184
+ [1, 2, 2, 3, 3].distinct(); // [1, 2, 3]
185
+ ```
186
+
187
+ #### distinctThis
188
+
189
+ Remove duplicates (modify original).
190
+
191
+ ```typescript
192
+ import "@simplysm/core-common";
193
+ ```
194
+
195
+ ---
196
+
197
+ ### Sorting
198
+
199
+ #### orderBy
200
+
201
+ Ascending sort (return new array).
202
+
203
+ ```typescript
204
+ users.orderBy((u) => u.name);
205
+ ```
206
+
207
+ #### orderByDesc
208
+
209
+ Descending sort (return new array).
210
+
211
+ ```typescript
212
+ users.orderByDesc((u) => u.id);
213
+ ```
214
+
215
+ #### orderByThis
216
+
217
+ Ascending sort (modify original).
218
+
219
+ ```typescript
220
+ import "@simplysm/core-common";
221
+ ```
222
+
223
+ #### orderByDescThis
224
+
225
+ Descending sort (modify original).
226
+
227
+ ```typescript
228
+ import "@simplysm/core-common";
229
+ ```
230
+
231
+ ---
232
+
233
+ ### Comparison/Merging
234
+
235
+ #### diffs
236
+
237
+ Compare differences between two arrays.
238
+
239
+ ```typescript
240
+ import "@simplysm/core-common";
241
+ ```
242
+
243
+ #### oneWayDiffs
244
+
245
+ One-way diff comparison (create/update/same).
246
+
247
+ ```typescript
248
+ import "@simplysm/core-common";
249
+ ```
250
+
251
+ #### merge
252
+
253
+ Merge arrays.
254
+
255
+ ```typescript
256
+ import "@simplysm/core-common";
257
+ ```
258
+
259
+ ---
260
+
261
+ ### Aggregation
262
+
263
+ #### sum
264
+
265
+ Sum.
266
+
267
+ ```typescript
268
+ import "@simplysm/core-common";
269
+ ```
270
+
271
+ #### min
272
+
273
+ Minimum.
274
+
275
+ ```typescript
276
+ import "@simplysm/core-common";
277
+ ```
278
+
279
+ #### max
280
+
281
+ Maximum.
282
+
283
+ ```typescript
284
+ import "@simplysm/core-common";
285
+ ```
286
+
287
+ ---
288
+
289
+ ### Mutation
290
+
291
+ #### insert
292
+
293
+ Insert at specific position.
294
+
295
+ ```typescript
296
+ import "@simplysm/core-common";
297
+ ```
298
+
299
+ #### remove
300
+
301
+ Remove item.
302
+
303
+ ```typescript
304
+ import "@simplysm/core-common";
305
+ ```
306
+
307
+ #### toggle
308
+
309
+ Remove if exists, add if not.
310
+
311
+ ```typescript
312
+ import "@simplysm/core-common";
313
+ ```
314
+
315
+ #### clear
316
+
317
+ Remove all items.
318
+
319
+ ```typescript
320
+ import "@simplysm/core-common";
321
+ ```
322
+
323
+ #### shuffle
324
+
325
+ Shuffle (return new array).
326
+
327
+ ```typescript
328
+ import "@simplysm/core-common";
329
+ ```
330
+
331
+ ---
332
+
333
+ ## Map extension methods
334
+
335
+ ### getOrCreate
336
+
337
+ If key doesn't exist, set new value and return.
338
+
339
+ ```typescript
340
+ const map = new Map<string, number[]>();
341
+
342
+ // Create and return if value doesn't exist
343
+ const arr = map.getOrCreate("key", []);
344
+ arr.push(1);
345
+
346
+ // Create with factory function (when computation is expensive)
347
+ map.getOrCreate("key2", () => expensiveComputation());
348
+ ```
349
+
350
+ ### update
351
+
352
+ Update value for key using function.
353
+
354
+ ```typescript
355
+ const countMap = new Map<string, number>();
356
+ countMap.update("key", (v) => (v ?? 0) + 1); // Increment counter
357
+ ```
358
+
359
+ ---
360
+
361
+ ## Set extension methods
362
+
363
+ ### adds
364
+
365
+ Add multiple values at once.
366
+
367
+ ```typescript
368
+ const set = new Set<number>([1, 2, 3]);
369
+ set.adds(4, 5, 6); // {1, 2, 3, 4, 5, 6}
370
+ ```
371
+
372
+ ### toggle
373
+
374
+ Toggle value (remove if exists, add if not).
375
+
376
+ ```typescript
377
+ set.toggle(2); // 2 exists so remove -> {1, 3, 4, 5, 6}
378
+ set.toggle(7); // 7 doesn't exist so add -> {1, 3, 4, 5, 6, 7}
379
+ set.toggle(8, "add"); // Force add
380
+ set.toggle(1, "del"); // Force delete
381
+ ```
@@ -0,0 +1,94 @@
1
+ # Features
2
+
3
+ Async operation control and event handling classes. All support `using` statements or `dispose()`.
4
+
5
+ ## DebounceQueue
6
+
7
+ Async debounce queue (executes only last request).
8
+
9
+ ```typescript
10
+ import { DebounceQueue } from "@simplysm/core-common";
11
+
12
+ using queue = new DebounceQueue(300); // 300ms debounce
13
+
14
+ // Error handling
15
+ queue.on("error", (err) => console.error(err));
16
+
17
+ // Only last call is executed
18
+ queue.run(() => console.log("1")); // Ignored
19
+ queue.run(() => console.log("2")); // Ignored
20
+ queue.run(() => console.log("3")); // Executed after 300ms
21
+ ```
22
+
23
+ ---
24
+
25
+ ## SerialQueue
26
+
27
+ Async serial queue (sequential execution).
28
+
29
+ ```typescript
30
+ import { SerialQueue } from "@simplysm/core-common";
31
+
32
+ using queue = new SerialQueue(100); // 100ms interval between tasks
33
+
34
+ queue.on("error", (err) => console.error(err));
35
+
36
+ queue.run(async () => { await fetch("/api/1"); });
37
+ queue.run(async () => { await fetch("/api/2"); }); // Runs after #1 completes
38
+ queue.run(async () => { await fetch("/api/3"); }); // Runs after #2 completes
39
+ ```
40
+
41
+ ---
42
+
43
+ ## EventEmitter
44
+
45
+ EventTarget wrapper with type-safe events.
46
+
47
+ ```typescript
48
+ import { EventEmitter } from "@simplysm/core-common";
49
+
50
+ interface MyEvents {
51
+ data: string;
52
+ error: Error;
53
+ done: void;
54
+ }
55
+
56
+ class MyService extends EventEmitter<MyEvents> {
57
+ process(): void {
58
+ this.emit("data", "result data");
59
+ this.emit("done"); // void type called without arguments
60
+ }
61
+ }
62
+
63
+ const service = new MyService();
64
+ service.on("data", (data) => console.log(data)); // data: string (type inferred)
65
+ service.off("data", listener); // Remove listener
66
+ service.listenerCount("data"); // Number of registered listeners
67
+ service.dispose(); // Remove all listeners
68
+ ```
69
+
70
+ ---
71
+
72
+ ## ZipArchive
73
+
74
+ ZIP file compression/decompression utility. Resources can be auto-cleaned with `await using`.
75
+
76
+ ```typescript
77
+ import { ZipArchive } from "@simplysm/core-common";
78
+
79
+ // Read ZIP file
80
+ await using archive = new ZipArchive(zipBytes);
81
+ const content = await archive.get("file.txt");
82
+ const exists = await archive.exists("data.json");
83
+
84
+ // Extract all (with progress)
85
+ const files = await archive.extractAll((progress) => {
86
+ console.log(`${progress.fileName}: ${progress.extractedSize}/${progress.totalSize}`);
87
+ });
88
+
89
+ // Create ZIP file
90
+ await using newArchive = new ZipArchive();
91
+ newArchive.write("file.txt", textBytes);
92
+ newArchive.write("data.json", jsonBytes);
93
+ const zipBytes = await newArchive.compress();
94
+ ```