jtcsv 2.2.8 → 3.1.0

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 (246) hide show
  1. package/README.md +204 -115
  2. package/bin/jtcsv.ts +2612 -0
  3. package/browser.d.ts +142 -0
  4. package/dist/benchmark.js +446 -0
  5. package/dist/benchmark.js.map +1 -0
  6. package/dist/bin/jtcsv.js +1940 -0
  7. package/dist/bin/jtcsv.js.map +1 -0
  8. package/dist/csv-to-json.js +1262 -0
  9. package/dist/csv-to-json.js.map +1 -0
  10. package/dist/errors.js +291 -0
  11. package/dist/errors.js.map +1 -0
  12. package/dist/eslint.config.js +147 -0
  13. package/dist/eslint.config.js.map +1 -0
  14. package/dist/index-core.js +95 -0
  15. package/dist/index-core.js.map +1 -0
  16. package/dist/index.js +93 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/json-save.js +229 -0
  19. package/dist/json-save.js.map +1 -0
  20. package/dist/json-to-csv.js +576 -0
  21. package/dist/json-to-csv.js.map +1 -0
  22. package/dist/jtcsv-core.cjs.js +1736 -0
  23. package/dist/jtcsv-core.cjs.js.map +1 -0
  24. package/dist/jtcsv-core.esm.js +1708 -0
  25. package/dist/jtcsv-core.esm.js.map +1 -0
  26. package/dist/jtcsv-core.umd.js +1742 -0
  27. package/dist/jtcsv-core.umd.js.map +1 -0
  28. package/dist/jtcsv-full.cjs.js +2241 -0
  29. package/dist/jtcsv-full.cjs.js.map +1 -0
  30. package/dist/jtcsv-full.esm.js +2209 -0
  31. package/dist/jtcsv-full.esm.js.map +1 -0
  32. package/dist/jtcsv-full.umd.js +2247 -0
  33. package/dist/jtcsv-full.umd.js.map +1 -0
  34. package/dist/jtcsv-workers.esm.js +768 -0
  35. package/dist/jtcsv-workers.esm.js.map +1 -0
  36. package/dist/jtcsv-workers.umd.js +782 -0
  37. package/dist/jtcsv-workers.umd.js.map +1 -0
  38. package/dist/jtcsv.cjs.js +1996 -2048
  39. package/dist/jtcsv.cjs.js.map +1 -1
  40. package/dist/jtcsv.esm.js +1992 -2048
  41. package/dist/jtcsv.esm.js.map +1 -1
  42. package/dist/jtcsv.umd.js +2157 -2209
  43. package/dist/jtcsv.umd.js.map +1 -1
  44. package/dist/plugins/express-middleware/index.js +350 -0
  45. package/dist/plugins/express-middleware/index.js.map +1 -0
  46. package/dist/plugins/fastify-plugin/index.js +315 -0
  47. package/dist/plugins/fastify-plugin/index.js.map +1 -0
  48. package/dist/plugins/hono/index.js +111 -0
  49. package/dist/plugins/hono/index.js.map +1 -0
  50. package/dist/plugins/nestjs/index.js +112 -0
  51. package/dist/plugins/nestjs/index.js.map +1 -0
  52. package/dist/plugins/nuxt/index.js +53 -0
  53. package/dist/plugins/nuxt/index.js.map +1 -0
  54. package/dist/plugins/remix/index.js +133 -0
  55. package/dist/plugins/remix/index.js.map +1 -0
  56. package/dist/plugins/sveltekit/index.js +155 -0
  57. package/dist/plugins/sveltekit/index.js.map +1 -0
  58. package/dist/plugins/trpc/index.js +136 -0
  59. package/dist/plugins/trpc/index.js.map +1 -0
  60. package/dist/run-demo.js +49 -0
  61. package/dist/run-demo.js.map +1 -0
  62. package/dist/src/browser/browser-functions.js +193 -0
  63. package/dist/src/browser/browser-functions.js.map +1 -0
  64. package/dist/src/browser/core.js +123 -0
  65. package/dist/src/browser/core.js.map +1 -0
  66. package/dist/src/browser/csv-to-json-browser.js +353 -0
  67. package/dist/src/browser/csv-to-json-browser.js.map +1 -0
  68. package/dist/src/browser/errors-browser.js +219 -0
  69. package/dist/src/browser/errors-browser.js.map +1 -0
  70. package/dist/src/browser/extensions/plugins.js +106 -0
  71. package/dist/src/browser/extensions/plugins.js.map +1 -0
  72. package/dist/src/browser/extensions/workers.js +66 -0
  73. package/dist/src/browser/extensions/workers.js.map +1 -0
  74. package/dist/src/browser/index.js +140 -0
  75. package/dist/src/browser/index.js.map +1 -0
  76. package/dist/src/browser/json-to-csv-browser.js +225 -0
  77. package/dist/src/browser/json-to-csv-browser.js.map +1 -0
  78. package/dist/src/browser/streams.js +340 -0
  79. package/dist/src/browser/streams.js.map +1 -0
  80. package/dist/src/browser/workers/csv-parser.worker.js +264 -0
  81. package/dist/src/browser/workers/csv-parser.worker.js.map +1 -0
  82. package/dist/src/browser/workers/worker-pool.js +338 -0
  83. package/dist/src/browser/workers/worker-pool.js.map +1 -0
  84. package/dist/src/core/delimiter-cache.js +196 -0
  85. package/dist/src/core/delimiter-cache.js.map +1 -0
  86. package/dist/src/core/node-optimizations.js +279 -0
  87. package/dist/src/core/node-optimizations.js.map +1 -0
  88. package/dist/src/core/plugin-system.js +399 -0
  89. package/dist/src/core/plugin-system.js.map +1 -0
  90. package/dist/src/core/transform-hooks.js +348 -0
  91. package/dist/src/core/transform-hooks.js.map +1 -0
  92. package/dist/src/engines/fast-path-engine-new.js +262 -0
  93. package/dist/src/engines/fast-path-engine-new.js.map +1 -0
  94. package/dist/src/engines/fast-path-engine.js +671 -0
  95. package/dist/src/engines/fast-path-engine.js.map +1 -0
  96. package/dist/src/errors.js +18 -0
  97. package/dist/src/errors.js.map +1 -0
  98. package/dist/src/formats/ndjson-parser.js +332 -0
  99. package/dist/src/formats/ndjson-parser.js.map +1 -0
  100. package/dist/src/formats/tsv-parser.js +230 -0
  101. package/dist/src/formats/tsv-parser.js.map +1 -0
  102. package/dist/src/index-with-plugins.js +259 -0
  103. package/dist/src/index-with-plugins.js.map +1 -0
  104. package/dist/src/types/index.js +3 -0
  105. package/dist/src/types/index.js.map +1 -0
  106. package/dist/src/utils/bom-utils.js +267 -0
  107. package/dist/src/utils/bom-utils.js.map +1 -0
  108. package/dist/src/utils/encoding-support.js +77 -0
  109. package/dist/src/utils/encoding-support.js.map +1 -0
  110. package/dist/src/utils/schema-validator.js +609 -0
  111. package/dist/src/utils/schema-validator.js.map +1 -0
  112. package/dist/src/utils/transform-loader.js +281 -0
  113. package/dist/src/utils/transform-loader.js.map +1 -0
  114. package/dist/src/utils/validators.js +40 -0
  115. package/dist/src/utils/validators.js.map +1 -0
  116. package/dist/src/utils/zod-adapter.js +144 -0
  117. package/dist/src/utils/zod-adapter.js.map +1 -0
  118. package/dist/src/web-server/index.js +648 -0
  119. package/dist/src/web-server/index.js.map +1 -0
  120. package/dist/src/workers/csv-multithreaded.js +211 -0
  121. package/dist/src/workers/csv-multithreaded.js.map +1 -0
  122. package/dist/src/workers/csv-parser.worker.js +179 -0
  123. package/dist/src/workers/csv-parser.worker.js.map +1 -0
  124. package/dist/src/workers/worker-pool.js +228 -0
  125. package/dist/src/workers/worker-pool.js.map +1 -0
  126. package/dist/stream-csv-to-json.js +665 -0
  127. package/dist/stream-csv-to-json.js.map +1 -0
  128. package/dist/stream-json-to-csv.js +389 -0
  129. package/dist/stream-json-to-csv.js.map +1 -0
  130. package/examples/advanced/conditional-transformations.ts +446 -0
  131. package/examples/advanced/csv-parser.worker.ts +89 -0
  132. package/examples/advanced/nested-objects-example.ts +306 -0
  133. package/examples/advanced/performance-optimization.ts +504 -0
  134. package/examples/advanced/run-demo-server.ts +116 -0
  135. package/examples/advanced/web-worker-usage.html +874 -0
  136. package/examples/async-multithreaded-example.ts +335 -0
  137. package/examples/cli-advanced-usage.md +290 -0
  138. package/examples/{cli-batch-processing.js → cli-batch-processing.ts} +38 -38
  139. package/examples/{cli-tool.js → cli-tool.ts} +5 -8
  140. package/examples/{error-handling.js → error-handling.ts} +356 -324
  141. package/examples/{express-api.js → express-api.ts} +161 -164
  142. package/examples/{large-dataset-example.js → large-dataset-example.ts} +201 -182
  143. package/examples/{ndjson-processing.js → ndjson-processing.ts} +456 -434
  144. package/examples/{plugin-excel-exporter.js → plugin-excel-exporter.ts} +6 -7
  145. package/examples/react-integration.tsx +637 -0
  146. package/examples/{schema-validation.js → schema-validation.ts} +2 -2
  147. package/examples/simple-usage.ts +194 -0
  148. package/examples/{streaming-example.js → streaming-example.ts} +12 -12
  149. package/index.d.ts +187 -18
  150. package/package.json +75 -81
  151. package/plugins.d.ts +37 -0
  152. package/schema.d.ts +103 -0
  153. package/src/browser/browser-functions.ts +402 -0
  154. package/src/browser/core.ts +152 -0
  155. package/src/browser/csv-to-json-browser.d.ts +3 -0
  156. package/src/browser/csv-to-json-browser.ts +494 -0
  157. package/src/browser/{errors-browser.js → errors-browser.ts} +305 -197
  158. package/src/browser/extensions/plugins.ts +93 -0
  159. package/src/browser/extensions/workers.ts +39 -0
  160. package/src/browser/globals.d.ts +5 -0
  161. package/src/browser/index.ts +192 -0
  162. package/src/browser/json-to-csv-browser.d.ts +3 -0
  163. package/src/browser/json-to-csv-browser.ts +338 -0
  164. package/src/browser/streams.ts +403 -0
  165. package/src/browser/workers/{csv-parser.worker.js → csv-parser.worker.ts} +3 -3
  166. package/src/browser/workers/{worker-pool.js → worker-pool.ts} +51 -30
  167. package/src/core/delimiter-cache.ts +320 -0
  168. package/src/core/{node-optimizations.js → node-optimizations.ts} +448 -407
  169. package/src/core/plugin-system.ts +588 -0
  170. package/src/core/transform-hooks.ts +566 -0
  171. package/src/engines/{fast-path-engine-new.js → fast-path-engine-new.ts} +11 -2
  172. package/src/engines/{fast-path-engine.js → fast-path-engine.ts} +79 -53
  173. package/src/errors.ts +1 -0
  174. package/src/formats/{ndjson-parser.js → ndjson-parser.ts} +24 -16
  175. package/src/formats/{tsv-parser.js → tsv-parser.ts} +18 -17
  176. package/src/{index-with-plugins.js → index-with-plugins.ts} +381 -357
  177. package/src/types/index.ts +275 -0
  178. package/src/utils/bom-utils.ts +373 -0
  179. package/src/utils/encoding-support.ts +155 -0
  180. package/src/utils/{schema-validator.js → schema-validator.ts} +814 -589
  181. package/src/utils/transform-loader.ts +389 -0
  182. package/src/utils/validators.ts +35 -0
  183. package/src/utils/zod-adapter.ts +280 -0
  184. package/src/web-server/{index.js → index.ts} +19 -19
  185. package/src/workers/csv-multithreaded.ts +310 -0
  186. package/src/workers/csv-parser.worker.ts +227 -0
  187. package/src/workers/worker-pool.ts +409 -0
  188. package/bin/jtcsv.js +0 -2462
  189. package/csv-to-json.js +0 -688
  190. package/errors.js +0 -208
  191. package/examples/simple-usage.js +0 -282
  192. package/index.js +0 -68
  193. package/json-save.js +0 -254
  194. package/json-to-csv.js +0 -526
  195. package/plugins/README.md +0 -91
  196. package/plugins/express-middleware/README.md +0 -64
  197. package/plugins/express-middleware/example.js +0 -136
  198. package/plugins/express-middleware/index.d.ts +0 -114
  199. package/plugins/express-middleware/index.js +0 -360
  200. package/plugins/express-middleware/package.json +0 -52
  201. package/plugins/fastify-plugin/index.js +0 -406
  202. package/plugins/fastify-plugin/package.json +0 -55
  203. package/plugins/hono/README.md +0 -28
  204. package/plugins/hono/index.d.ts +0 -12
  205. package/plugins/hono/index.js +0 -36
  206. package/plugins/hono/package.json +0 -35
  207. package/plugins/nestjs/README.md +0 -35
  208. package/plugins/nestjs/index.d.ts +0 -25
  209. package/plugins/nestjs/index.js +0 -77
  210. package/plugins/nestjs/package.json +0 -37
  211. package/plugins/nextjs-api/README.md +0 -57
  212. package/plugins/nextjs-api/examples/ConverterComponent.jsx +0 -386
  213. package/plugins/nextjs-api/examples/api-convert.js +0 -69
  214. package/plugins/nextjs-api/index.js +0 -387
  215. package/plugins/nextjs-api/package.json +0 -63
  216. package/plugins/nextjs-api/route.js +0 -371
  217. package/plugins/nuxt/README.md +0 -24
  218. package/plugins/nuxt/index.js +0 -21
  219. package/plugins/nuxt/package.json +0 -35
  220. package/plugins/nuxt/runtime/composables/useJtcsv.js +0 -6
  221. package/plugins/nuxt/runtime/plugin.js +0 -6
  222. package/plugins/remix/README.md +0 -26
  223. package/plugins/remix/index.d.ts +0 -16
  224. package/plugins/remix/index.js +0 -62
  225. package/plugins/remix/package.json +0 -35
  226. package/plugins/sveltekit/README.md +0 -28
  227. package/plugins/sveltekit/index.d.ts +0 -17
  228. package/plugins/sveltekit/index.js +0 -54
  229. package/plugins/sveltekit/package.json +0 -33
  230. package/plugins/trpc/README.md +0 -25
  231. package/plugins/trpc/index.d.ts +0 -7
  232. package/plugins/trpc/index.js +0 -32
  233. package/plugins/trpc/package.json +0 -34
  234. package/src/browser/browser-functions.js +0 -219
  235. package/src/browser/csv-to-json-browser.js +0 -700
  236. package/src/browser/index.js +0 -113
  237. package/src/browser/json-to-csv-browser.js +0 -309
  238. package/src/browser/streams.js +0 -393
  239. package/src/core/delimiter-cache.js +0 -186
  240. package/src/core/plugin-system.js +0 -476
  241. package/src/core/transform-hooks.js +0 -350
  242. package/src/errors.js +0 -26
  243. package/src/utils/transform-loader.js +0 -205
  244. package/stream-csv-to-json.js +0 -542
  245. package/stream-json-to-csv.js +0 -464
  246. /package/examples/{web-workers-advanced.js → web-workers-advanced.ts} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-save.js","sourceRoot":"","sources":["../json-save.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,oDA6BC;AA4CD,gCA+DC;AAgBD,wCA+DC;AAUD,0CAiBC;AAQD,4CAmBC;AASD,4CAWC;AAUD,wCA2BC;AASD,sCAsBC;AAxXD,qCASkB;AAGlB,uCAAyB;AACzB,2CAA6B;AAM7B,SAAgB,oBAAoB,CAAC,QAAgB;IAEnD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QAC3D,MAAM,IAAI,wBAAe,CAAC,sCAAsC,CAAC,CAAC;IACpE,CAAC;IAGD,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;QAC9C,MAAM,IAAI,wBAAe,CAAC,gCAAgC,CAAC,CAAC;IAC9D,CAAC;IAGD,IAAI,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7D,MAAM,IAAI,sBAAa,CAAC,2BAA2B,CAAC,CAAC;IACvD,CAAC;IAGD,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC5C,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAGhD,IAAI,cAAc,CAAC,QAAQ,CAAC,IAAI,CAAC;QAC7B,mBAAmB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClC,QAAQ,CAAC,UAAU,CAAC,IAAI,CAAC;QACzB,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,sBAAa,CAAC,2CAA2C,CAAC,CAAC;IACvE,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAMD,SAAS,gBAAgB,CAAC,IAAS,EAAE,OAA2B;IAE9D,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QACxC,MAAM,IAAI,wBAAe,CAAC,kCAAkC,CAAC,CAAC;IAChE,CAAC;IAGD,IAAI,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC3C,MAAM,IAAI,2BAAkB,CAAC,2BAA2B,CAAC,CAAC;IAC5D,CAAC;IAGD,IAAI,OAAO,EAAE,WAAW,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACnF,MAAM,IAAI,2BAAkB,CAAC,+BAA+B,CAAC,CAAC;IAChE,CAAC;IAGD,IAAI,OAAO,EAAE,OAAO,IAAI,CAAC,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,IAAI,2BAAkB,CAAC,mCAAmC,CAAC,CAAC;IACpE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAgBM,KAAK,UAAU,UAAU,CAC9B,IAAS,EACT,QAAgB,EAChB,UAA6B,EAAE;IAE/B,OAAO,IAAA,yBAAgB,EAAC,KAAK,IAAI,EAAE;QAEjC,MAAM,WAAW,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACpD,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACpC,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAEpD,MAAM,EACJ,WAAW,GAAG,KAAK,EACnB,OAAO,GAAG,QAAQ,EACnB,GAAG,WAAW,CAAC;QAGhB,IAAI,UAAkB,CAAC;QACvB,IAAI,CAAC;YACH,UAAU,GAAG,WAAW;gBACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/C,MAAM,IAAI,wBAAe,CAAC,mCAAmC,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,IAAI,wBAAe,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;QAGD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACzD,IAAI,UAAU,GAAG,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,mBAAU,CAClB,sCAAsC,OAAO,QAAQ,EACrD,OAAO,EACP,UAAU,CACX,CAAC;QACJ,CAAC;QAGD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAe,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YACxD,CAAC;YACD,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAe,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAC/D,CAAC;YACD,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAe,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAC9D,CAAC;YACD,MAAM,IAAI,wBAAe,CAAC,8BAA8B,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC;QACtG,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC,EAAE,mBAAmB,EAAE,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC,CAAC;AACtD,CAAC;AAgBD,SAAgB,cAAc,CAC5B,IAAS,EACT,QAAgB,EAChB,UAA6B,EAAE;IAE/B,OAAO,IAAA,wBAAe,EAAC,GAAG,EAAE;QAE1B,MAAM,WAAW,GAAG,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;QACpD,gBAAgB,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QACpC,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QAEpD,MAAM,EACJ,WAAW,GAAG,KAAK,EACnB,OAAO,GAAG,QAAQ,EACnB,GAAG,WAAW,CAAC;QAGhB,IAAI,UAAkB,CAAC;QACvB,IAAI,CAAC;YACH,UAAU,GAAG,WAAW;gBACtB,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC/B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/C,MAAM,IAAI,wBAAe,CAAC,mCAAmC,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,IAAI,wBAAe,CAAC,6BAA6B,OAAO,EAAE,CAAC,CAAC;QACpE,CAAC;QAGD,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;QACzD,IAAI,UAAU,GAAG,OAAO,EAAE,CAAC;YACzB,MAAM,IAAI,mBAAU,CAClB,sCAAsC,OAAO,QAAQ,EACrD,OAAO,EACP,UAAU,CACX,CAAC;QACJ,CAAC;QAGD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;QACvC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,IAAI,CAAC;YACH,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,UAAU,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAU,EAAE,CAAC;YACpB,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAe,CAAC,mBAAmB,EAAE,KAAK,CAAC,CAAC;YACxD,CAAC;YACD,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAe,CAAC,0BAA0B,EAAE,KAAK,CAAC,CAAC;YAC/D,CAAC;YACD,IAAI,KAAK,EAAE,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,MAAM,IAAI,wBAAe,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAC9D,CAAC;YACD,MAAM,IAAI,wBAAe,CAAC,8BAA8B,KAAK,EAAE,OAAO,IAAI,eAAe,EAAE,EAAE,KAAK,CAAC,CAAC;QACtG,CAAC;QAED,OAAO,YAAY,CAAC;IACtB,CAAC,EAAE,mBAAmB,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE,CAAC,CAAC;AAC1D,CAAC;AAUM,KAAK,UAAU,eAAe,CACnC,IAAS,EACT,QAAgB,EAChB,UAKI,EAAE;IAEN,OAAO,IAAA,yBAAgB,EAAC,KAAK,IAAI,EAAE;QACjC,MAAM,EAAE,UAAU,GAAG,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,WAAW,EAAE,GAAG,OAAO,CAAC;QAI3F,MAAM,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,CAAC,CAAC;IAChD,CAAC,EAAE,mBAAmB,EAAE,EAAE,QAAQ,EAAE,iBAAiB,EAAE,CAAC,CAAC;AAC3D,CAAC;AAQD,SAAgB,gBAAgB,CAAC,QAAgB;IAM/C,IAAI,CAAC;QACH,MAAM,YAAY,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;QACpD,OAAO;YACL,OAAO,EAAE,IAAI;YACb,YAAY;SACb,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,KAAK,CAAC,OAAO;YACpB,SAAS,EAAE,KAAK,CAAC,IAAI,IAAI,kBAAkB;SAC5C,CAAC;IACJ,CAAC;AACH,CAAC;AASD,SAAgB,gBAAgB,CAC9B,IAAS,EACT,UAAqC,EAAE;IAEvC,MAAM,EAAE,WAAW,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IAExC,MAAM,UAAU,GAAG,WAAW;QAC5B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEzB,OAAO,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;AAC/C,CAAC;AAUM,KAAK,UAAU,cAAc,CAClC,IAAS,EACT,QAAgB,EAChB,UAA6B,EAAE;IAO/B,IAAI,CAAC;QACH,MAAM,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC1C,MAAM,IAAI,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAE7C,OAAO;YACL,OAAO,EAAE,IAAI;YACb,QAAQ;YACR,IAAI;SACL,CAAC;IACJ,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO;YACL,OAAO,EAAE,KAAK;YACd,QAAQ;YACR,IAAI,EAAE,CAAC;YACP,KAAK;SACN,CAAC;IACJ,CAAC;AACH,CAAC;AASM,KAAK,UAAU,aAAa,CACjC,KAIE,EACF,gBAAmC,EAAE;IAOrC,MAAM,OAAO,GAAG,EAAE,CAAC;IAEnB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,EAAE,GAAG,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;QACtD,MAAM,MAAM,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACvE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC","sourcesContent":["/**\r\n * JSON Save Module - TypeScript Module\r\n * \r\n * A lightweight module for saving JSON data to files with security validation.\r\n */\r\n\r\nimport {\r\n ValidationError,\r\n SecurityError,\r\n FileSystemError,\r\n LimitError,\r\n ConfigurationError,\r\n safeExecuteSync,\r\n safeExecuteAsync,\r\n ErrorCode\r\n} from './errors';\r\n\r\nimport { SaveAsJsonOptions, AnyObject, AnyArray } from './src/types';\r\nimport * as fs from 'fs';\r\nimport * as path from 'path';\r\n\r\n/**\r\n * Validates file path for JSON saving\r\n * @private\r\n */\r\nexport function validateJsonFilePath(filePath: string): string {\n // Basic validation\r\n if (typeof filePath !== 'string' || filePath.trim() === '') {\r\n throw new ValidationError('File path must be a non-empty string');\r\n }\r\n\r\n // Ensure file has .json extension\r\n if (!filePath.toLowerCase().endsWith('.json')) {\r\n throw new ValidationError('File must have .json extension');\r\n }\r\n\r\n // Block UNC paths BEFORE path.resolve() to avoid network lookup timeouts\r\n if (filePath.startsWith('\\\\\\\\') || filePath.startsWith('//')) {\r\n throw new SecurityError('UNC paths are not allowed');\r\n }\r\n\r\n // Get absolute path and check for traversal\r\n const absolutePath = path.resolve(filePath);\r\n const normalizedPath = path.normalize(filePath);\r\n \r\n // Prevent directory traversal attacks\r\n if (normalizedPath.includes('..') || \r\n /\\\\\\.\\.\\\\|\\/\\.\\.\\//.test(filePath) ||\r\n filePath.startsWith('..') ||\r\n filePath.includes('/..')) {\r\n throw new SecurityError('Directory traversal detected in file path');\r\n }\r\n \r\n return absolutePath;\r\n}\r\n\r\n/**\r\n * Validates JSON data and options\r\n * @private\r\n */\r\nfunction validateJsonData(data: any, options?: SaveAsJsonOptions): boolean {\r\n // Validate data\r\n if (data === undefined || data === null) {\r\n throw new ValidationError('Data cannot be null or undefined');\r\n }\r\n \r\n // Validate options\r\n if (options && typeof options !== 'object') {\r\n throw new ConfigurationError('Options must be an object');\r\n }\r\n \r\n // Validate prettyPrint\r\n if (options?.prettyPrint !== undefined && typeof options.prettyPrint !== 'boolean') {\r\n throw new ConfigurationError('prettyPrint must be a boolean');\r\n }\r\n \r\n // Validate maxSize\r\n if (options?.maxSize && (typeof options.maxSize !== 'number' || options.maxSize <= 0)) {\r\n throw new ConfigurationError('maxSize must be a positive number');\r\n }\r\n \r\n return true;\r\n}\r\n\r\n/**\r\n * Saves JSON data to a file\r\n * \r\n * @param data - Data to save as JSON\r\n * @param filePath - Path to save the JSON file\r\n * @param options - Configuration options\r\n * @returns Promise<void>\r\n * \r\n * @example\r\n * const { saveAsJson } = require('./json-save');\r\n * \r\n * const data = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];\r\n * await saveAsJson(data, './output.json', { prettyPrint: true });\r\n */\r\nexport async function saveAsJson(\n data: any,\n filePath: string,\n options: SaveAsJsonOptions = {}\n): Promise<string> {\n return safeExecuteAsync(async () => {\n // Validate inputs\n const safeOptions = options === null ? {} : options;\n validateJsonData(data, safeOptions);\n const absolutePath = validateJsonFilePath(filePath);\n \n const {\n prettyPrint = false,\n maxSize = 10485760 // 10MB default\n } = safeOptions;\n \n // Convert data to JSON string\n let jsonString: string;\n try {\n jsonString = prettyPrint\n ? JSON.stringify(data, null, 2)\n : JSON.stringify(data);\n } catch (error: any) {\n const message = error?.message ? String(error.message) : 'Unknown error';\n if (message.toLowerCase().includes('circular')) {\n throw new ValidationError('JSON contains circular references');\n }\n throw new ValidationError(`Failed to stringify JSON: ${message}`);\n }\n \n // Check size limit\n const byteLength = Buffer.byteLength(jsonString, 'utf8');\n if (byteLength > maxSize) {\n throw new LimitError(\n `JSON size exceeds maximum limit of ${maxSize} bytes`,\n maxSize,\n byteLength\n );\n }\n \r\n // Ensure directory exists\r\n const dir = path.dirname(absolutePath);\r\n if (!fs.existsSync(dir)) {\r\n fs.mkdirSync(dir, { recursive: true });\r\n }\r\n \r\n try {\n await fs.promises.writeFile(absolutePath, jsonString, 'utf8');\n } catch (error: any) {\n if (error?.code === 'EACCES') {\n throw new FileSystemError('Permission denied', error);\n }\n if (error?.code === 'ENOENT') {\n throw new FileSystemError('Directory does not exist', error);\n }\n if (error?.code === 'ENOSPC') {\n throw new FileSystemError('No space left on device', error);\n }\n throw new FileSystemError(`Failed to write JSON file: ${error?.message || 'unknown error'}`, error);\n }\n\n return absolutePath;\n }, 'FILE_SYSTEM_ERROR', { function: 'saveAsJson' });\n}\n\r\n/**\r\n * Synchronous version of saveAsJson\r\n * \r\n * @param data - Data to save as JSON\r\n * @param filePath - Path to save the JSON file\r\n * @param options - Configuration options\r\n * @returns void\r\n * \r\n * @example\r\n * const { saveAsJsonSync } = require('./json-save');\r\n * \r\n * const data = [{ id: 1, name: 'John' }, { id: 2, name: 'Jane' }];\r\n * saveAsJsonSync(data, './output.json', { prettyPrint: true });\r\n */\r\nexport function saveAsJsonSync(\n data: any,\n filePath: string,\n options: SaveAsJsonOptions = {}\n): string {\n return safeExecuteSync(() => {\n // Validate inputs\n const safeOptions = options === null ? {} : options;\n validateJsonData(data, safeOptions);\n const absolutePath = validateJsonFilePath(filePath);\n \n const {\n prettyPrint = false,\n maxSize = 10485760 // 10MB default\n } = safeOptions;\n \n // Convert data to JSON string\n let jsonString: string;\n try {\n jsonString = prettyPrint\n ? JSON.stringify(data, null, 2)\n : JSON.stringify(data);\n } catch (error: any) {\n const message = error?.message ? String(error.message) : 'Unknown error';\n if (message.toLowerCase().includes('circular')) {\n throw new ValidationError('JSON contains circular references');\n }\n throw new ValidationError(`Failed to stringify JSON: ${message}`);\n }\n \n // Check size limit\n const byteLength = Buffer.byteLength(jsonString, 'utf8');\n if (byteLength > maxSize) {\n throw new LimitError(\n `JSON size exceeds maximum limit of ${maxSize} bytes`,\n maxSize,\n byteLength\n );\n }\n \r\n // Ensure directory exists\r\n const dir = path.dirname(absolutePath);\r\n if (!fs.existsSync(dir)) {\r\n fs.mkdirSync(dir, { recursive: true });\r\n }\r\n \r\n try {\n fs.writeFileSync(absolutePath, jsonString, 'utf8');\n } catch (error: any) {\n if (error?.code === 'EACCES') {\n throw new FileSystemError('Permission denied', error);\n }\n if (error?.code === 'ENOENT') {\n throw new FileSystemError('Directory does not exist', error);\n }\n if (error?.code === 'ENOSPC') {\n throw new FileSystemError('No space left on device', error);\n }\n throw new FileSystemError(`Failed to write JSON file: ${error?.message || 'unknown error'}`, error);\n }\n\n return absolutePath;\n }, 'FILE_SYSTEM_ERROR', { function: 'saveAsJsonSync' });\n}\n\r\n/**\r\n * Asynchronous version with worker thread support for large datasets\r\n * \r\n * @param data - Data to save as JSON\r\n * @param filePath - Path to save the JSON file\r\n * @param options - Configuration options with worker support\r\n * @returns Promise<void>\r\n */\r\nexport async function saveAsJsonAsync(\r\n data: any,\r\n filePath: string,\r\n options: SaveAsJsonOptions & {\r\n useWorkers?: boolean;\r\n workerCount?: number;\r\n chunkSize?: number;\r\n onProgress?: (progress: { processed: number; total: number; percentage: number }) => void;\r\n } = {}\r\n): Promise<void> {\n return safeExecuteAsync(async () => {\n const { useWorkers = false, workerCount, chunkSize, onProgress, ...saveOptions } = options;\n \n // For now, use the standard async version\n // TODO: Implement worker thread support for large datasets\n await saveAsJson(data, filePath, saveOptions);\n }, 'FILE_SYSTEM_ERROR', { function: 'saveAsJsonAsync' });\n}\n\r\n/**\r\n * Validates if a file path is safe for JSON saving\r\n * \r\n * @param filePath - File path to validate\r\n * @returns Validation result with details\r\n */\r\nexport function validateFilePath(filePath: string): {\r\n isValid: boolean;\r\n absolutePath?: string;\r\n error?: string;\r\n errorCode?: string;\r\n} {\r\n try {\r\n const absolutePath = validateJsonFilePath(filePath);\r\n return {\r\n isValid: true,\r\n absolutePath\r\n };\r\n } catch (error: any) {\r\n return {\r\n isValid: false,\r\n error: error.message,\r\n errorCode: error.code || 'VALIDATION_ERROR'\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Estimates the size of JSON data in bytes\r\n * \r\n * @param data - Data to estimate size for\r\n * @param options - Options for pretty printing\r\n * @returns Estimated size in bytes\r\n */\r\nexport function estimateJsonSize(\r\n data: any,\r\n options: { prettyPrint?: boolean } = {}\r\n): number {\r\n const { prettyPrint = false } = options;\r\n \r\n const jsonString = prettyPrint \r\n ? JSON.stringify(data, null, 2)\r\n : JSON.stringify(data);\r\n \r\n return Buffer.byteLength(jsonString, 'utf8');\r\n}\r\n\r\n/**\r\n * Creates a JSON file with proper error handling\r\n * \r\n * @param data - Data to save\r\n * @param filePath - Path to save\r\n * @param options - Save options\r\n * @returns Promise with result object\r\n */\r\nexport async function createJsonFile(\r\n data: any,\r\n filePath: string,\r\n options: SaveAsJsonOptions = {}\r\n): Promise<{\r\n success: boolean;\r\n filePath: string;\r\n size: number;\r\n error?: Error;\r\n}> {\r\n try {\r\n await saveAsJson(data, filePath, options);\r\n const size = estimateJsonSize(data, options);\r\n \r\n return {\r\n success: true,\r\n filePath,\r\n size\r\n };\r\n } catch (error: any) {\r\n return {\r\n success: false,\r\n filePath,\r\n size: 0,\r\n error\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Batch save multiple JSON files\r\n * \r\n * @param files - Array of file definitions\r\n * @param options - Common options for all files\r\n * @returns Promise with results\r\n */\r\nexport async function saveJsonFiles(\r\n files: Array<{\r\n data: any;\r\n filePath: string;\r\n options?: SaveAsJsonOptions;\r\n }>,\r\n commonOptions: SaveAsJsonOptions = {}\r\n): Promise<Array<{\r\n success: boolean;\r\n filePath: string;\r\n size: number;\r\n error?: Error;\r\n}>> {\r\n const results = [];\r\n \r\n for (const file of files) {\r\n const options = { ...commonOptions, ...file.options };\r\n const result = await createJsonFile(file.data, file.filePath, options);\r\n results.push(result);\r\n }\r\n \r\n return results;\r\n}\n"]}
@@ -0,0 +1,576 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.preprocessData = preprocessData;
4
+ exports.deepUnwrap = deepUnwrap;
5
+ exports.validateFilePath = validateFilePath;
6
+ exports.jsonToCsv = jsonToCsv;
7
+ exports.jsonToCsvAsync = jsonToCsvAsync;
8
+ exports.saveAsCsv = saveAsCsv;
9
+ exports.saveAsCsvAsync = saveAsCsvAsync;
10
+ const errors_1 = require("./errors");
11
+ const schema_validator_1 = require("./src/utils/schema-validator");
12
+ function validateInput(data, options) {
13
+ if (!Array.isArray(data)) {
14
+ throw new errors_1.ValidationError('Input data must be an array');
15
+ }
16
+ if (options && typeof options !== 'object') {
17
+ throw new errors_1.ConfigurationError('Options must be an object');
18
+ }
19
+ if (options?.delimiter && typeof options.delimiter !== 'string') {
20
+ throw new errors_1.ConfigurationError('Delimiter must be a string');
21
+ }
22
+ if (options?.delimiter && options.delimiter.length !== 1) {
23
+ throw new errors_1.ConfigurationError('Delimiter must be a single character');
24
+ }
25
+ if (options?.renameMap && typeof options.renameMap !== 'object') {
26
+ throw new errors_1.ConfigurationError('renameMap must be an object');
27
+ }
28
+ if (options && options.maxRecords !== undefined) {
29
+ if (typeof options.maxRecords !== 'number' || options.maxRecords <= 0) {
30
+ throw new errors_1.ConfigurationError('maxRecords must be a positive number');
31
+ }
32
+ }
33
+ if (options?.memoryWarningThreshold !== undefined) {
34
+ if (typeof options.memoryWarningThreshold !== 'number' || options.memoryWarningThreshold <= 0) {
35
+ throw new errors_1.ConfigurationError('memoryWarningThreshold must be a positive number');
36
+ }
37
+ }
38
+ if (options?.memoryLimit !== undefined) {
39
+ if (typeof options.memoryLimit !== 'number') {
40
+ throw new errors_1.ConfigurationError('memoryLimit must be a number');
41
+ }
42
+ if (options.memoryLimit !== Infinity && options.memoryLimit <= 0) {
43
+ throw new errors_1.ConfigurationError('memoryLimit must be a positive number or Infinity');
44
+ }
45
+ }
46
+ if (options?.preventCsvInjection !== undefined && typeof options.preventCsvInjection !== 'boolean') {
47
+ throw new errors_1.ConfigurationError('preventCsvInjection must be a boolean');
48
+ }
49
+ if (options?.rfc4180Compliant !== undefined && typeof options.rfc4180Compliant !== 'boolean') {
50
+ throw new errors_1.ConfigurationError('rfc4180Compliant must be a boolean');
51
+ }
52
+ if (options?.normalizeQuotes !== undefined && typeof options.normalizeQuotes !== 'boolean') {
53
+ throw new errors_1.ConfigurationError('normalizeQuotes must be a boolean');
54
+ }
55
+ if (options?.schema && typeof options.schema !== 'object') {
56
+ throw new errors_1.ConfigurationError('schema must be an object');
57
+ }
58
+ return true;
59
+ }
60
+ function preprocessData(data, options = {}) {
61
+ const { flatten = false, flattenSeparator = '.', flattenMaxDepth = 3, arrayHandling = 'join' } = options;
62
+ if (!Array.isArray(data)) {
63
+ return [];
64
+ }
65
+ const processed = [];
66
+ const fastPath = !flatten && arrayHandling === 'join';
67
+ for (const item of data) {
68
+ if (!item || typeof item !== 'object') {
69
+ processed.push({});
70
+ continue;
71
+ }
72
+ if (fastPath) {
73
+ let hasComplex = false;
74
+ let hasNullish = false;
75
+ for (const key in item) {
76
+ if (!Object.prototype.hasOwnProperty.call(item, key)) {
77
+ continue;
78
+ }
79
+ const value = item[key];
80
+ if (value === null || value === undefined) {
81
+ hasNullish = true;
82
+ continue;
83
+ }
84
+ if (typeof value === 'object') {
85
+ hasComplex = true;
86
+ break;
87
+ }
88
+ }
89
+ if (!hasComplex && !hasNullish) {
90
+ processed.push(item);
91
+ continue;
92
+ }
93
+ const processedItem = {};
94
+ for (const key in item) {
95
+ if (!Object.prototype.hasOwnProperty.call(item, key)) {
96
+ continue;
97
+ }
98
+ const value = item[key];
99
+ if (value === null || value === undefined) {
100
+ processedItem[key] = '';
101
+ }
102
+ else if (typeof value === 'object') {
103
+ processedItem[key] = deepUnwrap(value);
104
+ }
105
+ else {
106
+ processedItem[key] = value;
107
+ }
108
+ }
109
+ processed.push(processedItem);
110
+ continue;
111
+ }
112
+ let processedItem = { ...item };
113
+ if (flatten) {
114
+ processedItem = flattenObject(item, flattenSeparator, flattenMaxDepth);
115
+ }
116
+ processedItem = processArrays(processedItem, arrayHandling);
117
+ for (const [key, value] of Object.entries(processedItem)) {
118
+ if (value && typeof value === 'object') {
119
+ processedItem[key] = deepUnwrap(value);
120
+ }
121
+ else if (value === null || value === undefined) {
122
+ processedItem[key] = '';
123
+ }
124
+ else {
125
+ processedItem[key] = value;
126
+ }
127
+ }
128
+ processed.push(processedItem);
129
+ }
130
+ return processed;
131
+ }
132
+ function flattenObject(obj, separator = '.', maxDepth = 3, currentDepth = 0, prefix = '') {
133
+ if (currentDepth >= maxDepth) {
134
+ return { [prefix || 'value']: obj };
135
+ }
136
+ const flattened = {};
137
+ for (const [key, value] of Object.entries(obj)) {
138
+ const newKey = prefix ? `${prefix}${separator}${key}` : key;
139
+ if (value && typeof value === 'object' && !Array.isArray(value)) {
140
+ const nestedFlattened = flattenObject(value, separator, maxDepth, currentDepth + 1, newKey);
141
+ Object.assign(flattened, nestedFlattened);
142
+ }
143
+ else {
144
+ flattened[newKey] = value;
145
+ }
146
+ }
147
+ return flattened;
148
+ }
149
+ function processArrays(obj, arrayHandling) {
150
+ const processed = { ...obj };
151
+ for (const [key, value] of Object.entries(obj)) {
152
+ if (Array.isArray(value)) {
153
+ switch (arrayHandling) {
154
+ case 'stringify':
155
+ processed[key] = JSON.stringify(value);
156
+ break;
157
+ case 'join':
158
+ processed[key] = value.join(', ');
159
+ break;
160
+ case 'expand':
161
+ if (value.length > 0 && typeof value[0] === 'object') {
162
+ processed[key] = JSON.stringify(value);
163
+ }
164
+ else {
165
+ processed[key] = value.join(', ');
166
+ }
167
+ break;
168
+ }
169
+ }
170
+ }
171
+ return processed;
172
+ }
173
+ function deepUnwrap(value, depthOrOptions = 0, maxDepthParam = 10) {
174
+ let currentDepth = 0;
175
+ let maxDepth = 10;
176
+ let preserveArrays = false;
177
+ if (depthOrOptions && typeof depthOrOptions === 'object') {
178
+ maxDepth = typeof depthOrOptions.maxDepth === 'number' ? depthOrOptions.maxDepth : maxDepth;
179
+ preserveArrays = Boolean(depthOrOptions.preserveArrays);
180
+ }
181
+ else {
182
+ currentDepth = typeof depthOrOptions === 'number' ? depthOrOptions : 0;
183
+ maxDepth = typeof maxDepthParam === 'number' ? maxDepthParam : maxDepth;
184
+ }
185
+ return unwrapRecursive(value, currentDepth, maxDepth, preserveArrays, new WeakSet());
186
+ }
187
+ function unwrapRecursive(value, currentDepth, maxDepth, preserveArrays, seen) {
188
+ if (value === null || value === undefined) {
189
+ return '';
190
+ }
191
+ if (typeof value === 'string') {
192
+ return value;
193
+ }
194
+ if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'bigint') {
195
+ return String(value);
196
+ }
197
+ if (Array.isArray(value)) {
198
+ if (seen.has(value)) {
199
+ return '[Circular Reference]';
200
+ }
201
+ if (currentDepth >= maxDepth) {
202
+ return '[Too Deep]';
203
+ }
204
+ if (value.length === 0) {
205
+ return '';
206
+ }
207
+ seen.add(value);
208
+ if (preserveArrays) {
209
+ try {
210
+ return value.map(item => unwrapRecursive(item, currentDepth + 1, maxDepth, preserveArrays, seen));
211
+ }
212
+ finally {
213
+ seen.delete(value);
214
+ }
215
+ }
216
+ try {
217
+ const parts = value.map(item => unwrapRecursive(item, currentDepth + 1, maxDepth, preserveArrays, seen));
218
+ return parts.join(', ');
219
+ }
220
+ finally {
221
+ seen.delete(value);
222
+ }
223
+ }
224
+ if (typeof value === 'object') {
225
+ if (currentDepth >= maxDepth) {
226
+ return '[Too Deep]';
227
+ }
228
+ if (Object.keys(value).length === 0) {
229
+ return '';
230
+ }
231
+ if (seen.has(value)) {
232
+ return '[Circular Reference]';
233
+ }
234
+ seen.add(value);
235
+ try {
236
+ return JSON.stringify(value);
237
+ }
238
+ catch (error) {
239
+ const message = error?.message ? String(error.message) : '';
240
+ if (message.toLowerCase().includes('circular')) {
241
+ return '[Circular Reference]';
242
+ }
243
+ return '[Unstringifiable Object]';
244
+ }
245
+ finally {
246
+ seen.delete(value);
247
+ }
248
+ }
249
+ return String(value);
250
+ }
251
+ function validateFilePath(filePath, options = {}) {
252
+ const { allowRelative = true } = options;
253
+ if (typeof filePath !== 'string' || filePath.trim().length === 0) {
254
+ throw new errors_1.ValidationError('File path must be a non-empty string');
255
+ }
256
+ const normalized = filePath.trim();
257
+ if (normalized.includes('\0')) {
258
+ throw new errors_1.SecurityError('File path contains null byte');
259
+ }
260
+ const traversalPattern = /(^|[\\/])\.\.([\\/]|$)/;
261
+ const pathsToCheck = [normalized];
262
+ try {
263
+ const decodedOnce = decodeURIComponent(normalized);
264
+ pathsToCheck.push(decodedOnce);
265
+ try {
266
+ pathsToCheck.push(decodeURIComponent(decodedOnce));
267
+ }
268
+ catch {
269
+ }
270
+ }
271
+ catch {
272
+ }
273
+ for (const candidate of pathsToCheck) {
274
+ if (candidate.includes('..') || traversalPattern.test(candidate)) {
275
+ throw new errors_1.SecurityError('Directory traversal detected in file path');
276
+ }
277
+ }
278
+ if (!allowRelative && (normalized.startsWith('./') || normalized.startsWith('.\\'))) {
279
+ throw new errors_1.SecurityError('Relative file paths are not allowed');
280
+ }
281
+ if (process.platform === 'win32') {
282
+ const normalizedWin = normalized.replace(/\//g, '\\');
283
+ if (normalizedWin.startsWith('\\\\')) {
284
+ if (!normalizedWin.toLowerCase().startsWith('\\\\?\\')) {
285
+ throw new errors_1.SecurityError('UNC paths are not allowed');
286
+ }
287
+ if (normalizedWin.toLowerCase().startsWith('\\\\?\\unc\\')) {
288
+ throw new errors_1.SecurityError('UNC paths are not allowed');
289
+ }
290
+ }
291
+ }
292
+ const ext = require('path').extname(normalized);
293
+ if (!ext || ext.toLowerCase() !== '.csv') {
294
+ throw new errors_1.ValidationError('File must have .csv extension');
295
+ }
296
+ const dangerousPatterns = [
297
+ /^\/etc\/passwd/,
298
+ /^\/etc\/shadow/,
299
+ /^\/proc\/self/,
300
+ /^\/dev\/null/,
301
+ /^\/dev\/zero/,
302
+ /^\/dev\/random/,
303
+ /^\/dev\/urandom/
304
+ ];
305
+ for (const pattern of dangerousPatterns) {
306
+ if (pattern.test(filePath)) {
307
+ throw new errors_1.SecurityError('File path matches dangerous pattern');
308
+ }
309
+ }
310
+ return true;
311
+ }
312
+ function jsonToCsv(data, options = {}) {
313
+ return (0, errors_1.safeExecuteSync)(() => {
314
+ validateInput(data, options);
315
+ const opts = options && typeof options === 'object' ? options : {};
316
+ const { delimiter = ';', includeHeaders = true, renameMap = {}, template = {}, maxRecords, preventCsvInjection = true, rfc4180Compliant = true, normalizeQuotes = true, schema = null, flatten = false, flattenSeparator = '.', flattenMaxDepth = 3, arrayHandling = 'stringify', memoryWarningThreshold = 1000000, memoryLimit = 5000000 } = opts;
317
+ let schemaValidators = null;
318
+ if (schema) {
319
+ schemaValidators = (0, schema_validator_1.createSchemaValidators)(schema);
320
+ }
321
+ if (data.length === 0) {
322
+ return '';
323
+ }
324
+ if (Number.isFinite(memoryLimit) && data.length > memoryLimit) {
325
+ throw new errors_1.LimitError(`Data size exceeds memory safety limit of ${memoryLimit} records`, memoryLimit, data.length);
326
+ }
327
+ if (memoryWarningThreshold
328
+ && data.length > memoryWarningThreshold
329
+ && process.env['NODE_ENV'] !== 'test') {
330
+ console.warn('Warning: Large in-memory conversion detected.\n' +
331
+ 'Consider using streaming or batching for big datasets.\n' +
332
+ 'Current size: ' + data.length.toLocaleString() + ' records\n' +
333
+ 'Tip: Increase memoryLimit or set memoryLimit: Infinity to override.');
334
+ }
335
+ if (maxRecords && data.length > maxRecords) {
336
+ throw new errors_1.LimitError(`Data size exceeds maximum limit of ${maxRecords} records`, maxRecords, data.length);
337
+ }
338
+ const processedData = preprocessData(data, {
339
+ flatten,
340
+ flattenSeparator,
341
+ flattenMaxDepth,
342
+ arrayHandling
343
+ });
344
+ if (schemaValidators && Object.keys(schemaValidators).length > 0) {
345
+ for (let i = 0; i < processedData.length; i++) {
346
+ const row = processedData[i];
347
+ if (!row || typeof row !== 'object') {
348
+ continue;
349
+ }
350
+ for (const [field, validator] of Object.entries(schemaValidators)) {
351
+ const typedValidator = validator;
352
+ const value = row[field];
353
+ if (typeof typedValidator.validate === 'function' && !typedValidator.validate(value)) {
354
+ throw new errors_1.ValidationError(`Invalid value for field "${field}"`);
355
+ }
356
+ if (typeof typedValidator.format === 'function') {
357
+ row[field] = typedValidator.format(value);
358
+ }
359
+ }
360
+ }
361
+ }
362
+ const allKeys = new Set();
363
+ const originalKeys = [];
364
+ for (let i = 0; i < processedData.length; i++) {
365
+ const item = processedData[i];
366
+ if (!item || typeof item !== 'object') {
367
+ continue;
368
+ }
369
+ for (const key in item) {
370
+ if (Object.prototype.hasOwnProperty.call(item, key) && !allKeys.has(key)) {
371
+ allKeys.add(key);
372
+ originalKeys.push(key);
373
+ }
374
+ }
375
+ }
376
+ const hasRenameMap = Object.keys(renameMap).length > 0;
377
+ const hasTemplate = Object.keys(template).length > 0;
378
+ let headers = originalKeys;
379
+ let reverseRenameMap = null;
380
+ if (hasRenameMap) {
381
+ headers = new Array(originalKeys.length);
382
+ reverseRenameMap = {};
383
+ for (let i = 0; i < originalKeys.length; i++) {
384
+ const key = originalKeys[i];
385
+ const header = renameMap[key] || key;
386
+ headers[i] = header;
387
+ reverseRenameMap[header] = key;
388
+ }
389
+ }
390
+ let finalHeaders = headers;
391
+ if (hasTemplate) {
392
+ const templateKeys = Object.keys(template);
393
+ const templateHeaders = hasRenameMap
394
+ ? templateKeys.map(key => renameMap[key] || key)
395
+ : templateKeys;
396
+ const templateHeaderSet = new Set(templateHeaders);
397
+ const extraHeaders = [];
398
+ for (let i = 0; i < headers.length; i++) {
399
+ const header = headers[i];
400
+ if (!templateHeaderSet.has(header)) {
401
+ extraHeaders.push(header);
402
+ }
403
+ }
404
+ finalHeaders = templateHeaders.concat(extraHeaders);
405
+ }
406
+ const finalKeys = new Array(finalHeaders.length);
407
+ if (hasRenameMap && reverseRenameMap) {
408
+ for (let i = 0; i < finalHeaders.length; i++) {
409
+ const header = finalHeaders[i];
410
+ finalKeys[i] = reverseRenameMap[header] || header;
411
+ }
412
+ }
413
+ else {
414
+ for (let i = 0; i < finalHeaders.length; i++) {
415
+ finalKeys[i] = finalHeaders[i];
416
+ }
417
+ }
418
+ const phoneKeys = new Set(['phone', 'phonenumber', 'phone_number', 'tel', 'telephone']);
419
+ const normalizeQuotesInField = (value) => {
420
+ if ((value.startsWith('{') && value.endsWith('}')) ||
421
+ (value.startsWith('[') && value.endsWith(']'))) {
422
+ return value;
423
+ }
424
+ let normalized = value.replace(/"{2,}/g, '"');
425
+ normalized = normalized.replace(/"\n/g, '\n').replace(/\n"/g, '\n');
426
+ if (normalized.length >= 2 && normalized.startsWith('"') && normalized.endsWith('"')) {
427
+ normalized = normalized.slice(1, -1);
428
+ }
429
+ return normalized;
430
+ };
431
+ const normalizePhoneValue = (value) => {
432
+ const trimmed = value.trim();
433
+ if (trimmed === '') {
434
+ return trimmed;
435
+ }
436
+ return trimmed.replace(/["'\\]/g, '');
437
+ };
438
+ const normalizeValueForCsv = (value, key) => {
439
+ if (!normalizeQuotes || typeof value !== 'string') {
440
+ return value;
441
+ }
442
+ const base = normalizeQuotesInField(value);
443
+ if (key && phoneKeys.has(String(key).toLowerCase())) {
444
+ return normalizePhoneValue(base);
445
+ }
446
+ return base;
447
+ };
448
+ const quoteRegex = /"/g;
449
+ const delimiterCode = delimiter.charCodeAt(0);
450
+ const isPotentialFormula = (value) => {
451
+ let idx = 0;
452
+ while (idx < value.length) {
453
+ const code = value.charCodeAt(idx);
454
+ if (code === 32 || code === 9 || code === 10 || code === 13 || code === 0xfeff) {
455
+ idx++;
456
+ continue;
457
+ }
458
+ break;
459
+ }
460
+ if (idx < value.length && (value[idx] === '"' || value[idx] === "'")) {
461
+ idx++;
462
+ while (idx < value.length) {
463
+ const code = value.charCodeAt(idx);
464
+ if (code === 32 || code === 9) {
465
+ idx++;
466
+ continue;
467
+ }
468
+ break;
469
+ }
470
+ }
471
+ if (idx >= value.length) {
472
+ return false;
473
+ }
474
+ const char = value[idx];
475
+ return char === '=' || char === '+' || char === '-' || char === '@';
476
+ };
477
+ const escapeValue = (value) => {
478
+ if (value === null || value === undefined || value === '') {
479
+ return '';
480
+ }
481
+ let stringValue = value;
482
+ if (typeof stringValue !== 'string') {
483
+ stringValue = String(stringValue);
484
+ }
485
+ let escapedValue = stringValue;
486
+ if (preventCsvInjection) {
487
+ if (isPotentialFormula(stringValue)) {
488
+ escapedValue = "'" + stringValue;
489
+ }
490
+ const bidiChars = ['\u202A', '\u202B', '\u202C', '\u202D', '\u202E'];
491
+ for (const bidi of bidiChars) {
492
+ if (stringValue.includes(bidi)) {
493
+ escapedValue = escapedValue.replace(new RegExp(bidi, 'g'), '');
494
+ }
495
+ }
496
+ }
497
+ let needsQuoting = false;
498
+ let hasQuote = false;
499
+ for (let i = 0; i < escapedValue.length; i++) {
500
+ const code = escapedValue.charCodeAt(i);
501
+ if (code === 34) {
502
+ hasQuote = true;
503
+ needsQuoting = true;
504
+ }
505
+ else if (code === delimiterCode || code === 10 || code === 13) {
506
+ needsQuoting = true;
507
+ }
508
+ }
509
+ if (needsQuoting) {
510
+ const quotedValue = hasQuote ? escapedValue.replace(quoteRegex, '""') : escapedValue;
511
+ return `"${quotedValue}"`;
512
+ }
513
+ return escapedValue;
514
+ };
515
+ const rows = [];
516
+ if (includeHeaders) {
517
+ const headerRow = finalHeaders.map(header => escapeValue(header)).join(delimiter);
518
+ rows.push(headerRow);
519
+ }
520
+ for (let i = 0; i < processedData.length; i++) {
521
+ const item = processedData[i];
522
+ const rowValues = [];
523
+ for (let j = 0; j < finalKeys.length; j++) {
524
+ const key = finalKeys[j];
525
+ const value = item && typeof item === 'object' ? item[key] : undefined;
526
+ const normalized = normalizeValueForCsv(value, key);
527
+ rowValues.push(escapeValue(normalized));
528
+ }
529
+ rows.push(rowValues.join(delimiter));
530
+ }
531
+ let csv = rows.join(rfc4180Compliant ? '\r\n' : '\n');
532
+ return csv;
533
+ }, 'PARSING_ERROR', { function: 'jsonToCsv' });
534
+ }
535
+ async function jsonToCsvAsync(data, options = {}) {
536
+ return (0, errors_1.safeExecuteAsync)(async () => {
537
+ const { useWorkers = false, workerCount, chunkSize, onProgress, ...syncOptions } = options;
538
+ return jsonToCsv(data, syncOptions);
539
+ }, 'PARSING_ERROR', { function: 'jsonToCsvAsync' });
540
+ }
541
+ async function saveAsCsv(data, filePath, options = {}) {
542
+ return (0, errors_1.safeExecuteAsync)(async () => {
543
+ const { validatePath = true, ...csvOptions } = options;
544
+ if (validatePath) {
545
+ validateFilePath(filePath);
546
+ }
547
+ const path = require('path');
548
+ const fs = require('fs');
549
+ const resolvedPath = path.resolve(filePath);
550
+ const dir = path.dirname(resolvedPath);
551
+ try {
552
+ await fs.promises.mkdir(dir, { recursive: true });
553
+ const csv = jsonToCsv(data, csvOptions);
554
+ await fs.promises.writeFile(resolvedPath, csv, 'utf8');
555
+ }
556
+ catch (error) {
557
+ if (error instanceof errors_1.JtcsvError) {
558
+ throw error;
559
+ }
560
+ throw new errors_1.FileSystemError(error.message || 'File system error', error);
561
+ }
562
+ }, 'FILE_SYSTEM_ERROR', { function: 'saveAsCsv' });
563
+ }
564
+ async function saveAsCsvAsync(data, filePath, options = {}) {
565
+ return saveAsCsv(data, filePath, options);
566
+ }
567
+ exports.default = {
568
+ jsonToCsv,
569
+ jsonToCsvAsync,
570
+ preprocessData,
571
+ deepUnwrap,
572
+ validateFilePath,
573
+ saveAsCsv,
574
+ saveAsCsvAsync
575
+ };
576
+ //# sourceMappingURL=json-to-csv.js.map