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,275 @@
1
+ /**
2
+ * TypeScript интерфейсы для проекта jtcsv
3
+ */
4
+
5
+ // Базовые типы
6
+ export type AnyObject = Record<string, any>;
7
+ export type AnyArray = any[];
8
+
9
+ // JSON to CSV интерфейсы
10
+ export interface JsonToCsvOptions {
11
+ /** CSV delimiter (default: ';') */
12
+ delimiter?: string;
13
+ /** Include headers row (default: true) */
14
+ includeHeaders?: boolean;
15
+ /** Rename column headers { oldKey: newKey } */
16
+ renameMap?: Record<string, string>;
17
+ /** Template for guaranteed column order */
18
+ template?: Record<string, any>;
19
+ /** Maximum number of records to process (optional, no limit by default) */
20
+ maxRecords?: number;
21
+ /** Prevent CSV injection attacks by escaping formulas (default: true) */
22
+ preventCsvInjection?: boolean;
23
+ /** Ensure RFC 4180 compliance (proper quoting, line endings) (default: true) */
24
+ rfc4180Compliant?: boolean;
25
+ /** Normalize excessive quotes in JSON string values before CSV export (default: true) */
26
+ normalizeQuotes?: boolean;
27
+ /** JSON schema for data validation and formatting */
28
+ schema?: Record<string, any>;
29
+ /** Whether to flatten nested objects into dot notation keys */
30
+ flatten?: boolean;
31
+ /** Separator for flattened keys (e.g., 'user.name' with '.') */
32
+ flattenSeparator?: string;
33
+ /** Maximum depth for flattening nested objects */
34
+ flattenMaxDepth?: number;
35
+ /** How to handle arrays ('stringify', 'join', 'expand') */
36
+ arrayHandling?: 'stringify' | 'join' | 'expand';
37
+ /** Warn when record count exceeds this threshold (default: 1000000) */
38
+ memoryWarningThreshold?: number;
39
+ /** Safety limit for in-memory conversion (default: 5000000). Set to Infinity to disable. */
40
+ memoryLimit?: number;
41
+ }
42
+
43
+ export interface SaveAsCsvOptions extends JsonToCsvOptions {
44
+ /** Validate file path security (default: true) */
45
+ validatePath?: boolean;
46
+ }
47
+
48
+ // CSV to JSON интерфейсы
49
+ export interface CsvToJsonOptions {
50
+ /** CSV delimiter (default: auto-detected) */
51
+ delimiter?: string;
52
+ /** Auto-detect delimiter if not specified (default: true) */
53
+ autoDetect?: boolean;
54
+ /** Candidate delimiters for auto-detection (default: [';', ',', '\t', '|']) */
55
+ candidates?: string[];
56
+ /** Whether CSV has headers row (default: true) */
57
+ hasHeaders?: boolean;
58
+ /** Map for renaming column headers { newKey: oldKey } */
59
+ renameMap?: Record<string, string>;
60
+ /** Trim whitespace from values (default: true) */
61
+ trim?: boolean;
62
+ /** Parse numeric values (default: false) */
63
+ parseNumbers?: boolean;
64
+ /** Parse boolean values (default: false) */
65
+ parseBooleans?: boolean;
66
+ /** Maximum number of rows to process (optional, no limit by default) */
67
+ maxRows?: number;
68
+ /** Enable fast-path parsing (default: true) */
69
+ useFastPath?: boolean;
70
+ /** Fast-path output mode (default: 'objects') */
71
+ fastPathMode?: 'objects' | 'compact' | 'stream';
72
+ /** JSON schema for validation and formatting */
73
+ schema?: Record<string, any>;
74
+ /** Custom transform function for each row */
75
+ transform?: (row: Record<string, any>) => Record<string, any>;
76
+ /** Use delimiter cache for auto-detection (default: true) */
77
+ useCache?: boolean;
78
+ /** Custom delimiter cache instance */
79
+ cache?: any; // DelimiterCache type will be imported later
80
+ /** Hooks for custom processing */
81
+ hooks?: {
82
+ beforeConvert?: (csv: string, options: CsvToJsonOptions) => string;
83
+ perRow?: (row: Record<string, any>, index: number, context?: { options: CsvToJsonOptions }) => Record<string, any>;
84
+ afterConvert?: (result: any[], options: CsvToJsonOptions) => any[];
85
+ transformHooks?: import('../core/transform-hooks').TransformHooks;
86
+ onError?: (error: Error, csv: string, options: CsvToJsonOptions) => void;
87
+ };
88
+ /** Prevent CSV injection attacks by escaping formulas (default: true) */
89
+ preventCsvInjection?: boolean;
90
+ /** Ensure RFC 4180 compliance (proper quoting, line endings) (default: true) */
91
+ rfc4180Compliant?: boolean;
92
+ /** Warn about extra fields not in headers (default: false) */
93
+ warnExtraFields?: boolean;
94
+ /** Error recovery strategy for row-level errors (default: 'throw') */
95
+ onError?: 'skip' | 'warn' | 'throw';
96
+ /** Custom error handler for row-level errors */
97
+ errorHandler?: (error: Error, line: string, lineNumber: number) => void;
98
+ /** Warn when row count exceeds this threshold (default: 1000000) */
99
+ memoryWarningThreshold?: number;
100
+ /** Safety limit for in-memory conversion (default: 5000000). Set to Infinity to disable. */
101
+ memoryLimit?: number;
102
+ /** Attempt to repair shifted rows with trailing empty fields (default: true) */
103
+ repairRowShifts?: boolean;
104
+ /** Normalize excessive quotes in parsed fields (default: true) */
105
+ normalizeQuotes?: boolean;
106
+ }
107
+
108
+ // JSON save интерфейсы
109
+ export interface SaveAsJsonOptions {
110
+ /** Format JSON with indentation (default: false) */
111
+ prettyPrint?: boolean;
112
+ /** Maximum file size in bytes (default: 10MB = 10485760) */
113
+ maxSize?: number;
114
+ }
115
+
116
+ // Streaming интерфейсы
117
+ export interface JsonToCsvStreamOptions extends JsonToCsvOptions {
118
+ /** Custom transform function for each row */
119
+ transform?: (row: Record<string, any>) => Record<string, any>;
120
+ /** JSON schema for validation and formatting */
121
+ schema?: Record<string, any>;
122
+ /** Add UTF-8 BOM for Excel compatibility (default: true) */
123
+ addBOM?: boolean;
124
+ }
125
+
126
+ export interface CsvToJsonStreamOptions extends CsvToJsonOptions {
127
+ /** Custom transform function for each row */
128
+ transform?: (row: Record<string, any>) => Record<string, any>;
129
+ /** JSON schema for validation and formatting */
130
+ schema?: Record<string, any>;
131
+ }
132
+
133
+ // NDJSON интерфейсы
134
+ export interface NdjsonOptions {
135
+ /** Buffer size for streaming (default: 64KB) */
136
+ bufferSize?: number;
137
+ /** Maximum line length (default: 10MB) */
138
+ maxLineLength?: number;
139
+ /** Error handler callback */
140
+ onError?: (error: Error, line: string, lineNumber: number) => void;
141
+ /** JSON stringify replacer function */
142
+ replacer?: (key: string, value: any) => any;
143
+ /** JSON stringify space (indentation) */
144
+ space?: number | string;
145
+ /** Filter function for rows */
146
+ filter?: (obj: Record<string, any>, index: number) => boolean;
147
+ /** Transform function for rows */
148
+ transform?: (obj: Record<string, any>, index: number) => any;
149
+ }
150
+
151
+ export interface NdjsonToCsvStreamOptions {
152
+ /** Delimiter for CSV output (default: ',') */
153
+ delimiter?: string;
154
+ /** Include headers row (default: true) */
155
+ includeHeaders?: boolean;
156
+ /** Rename column headers { oldKey: newKey } */
157
+ renameMap?: Record<string, string>;
158
+ /** Maximum number of records to process */
159
+ maxRecords?: number;
160
+ /** Prevent CSV injection attacks by escaping formulas (default: true) */
161
+ preventCsvInjection?: boolean;
162
+ /** Ensure RFC 4180 compliance (proper quoting, line endings) (default: true) */
163
+ rfc4180Compliant?: boolean;
164
+ /** JSON schema for validation and formatting */
165
+ schema?: Record<string, any>;
166
+ /** Custom transform function for each row */
167
+ transform?: (row: Record<string, any>) => Record<string, any>;
168
+ /** Add UTF-8 BOM for Excel compatibility (default: true) */
169
+ addBOM?: boolean;
170
+ }
171
+
172
+ // TSV интерфейсы
173
+ export interface TsvOptions {
174
+ /** Whether TSV has headers row (default: true) */
175
+ hasHeaders?: boolean;
176
+ /** Trim whitespace from values (default: true) */
177
+ trim?: boolean;
178
+ /** Parse numeric values (default: false) */
179
+ parseNumbers?: boolean;
180
+ /** Parse boolean values (default: false) */
181
+ parseBooleans?: boolean;
182
+ /** Maximum number of rows to process */
183
+ maxRows?: number;
184
+ /** JSON schema for validation and formatting */
185
+ schema?: Record<string, any>;
186
+ /** Custom transform function for each row */
187
+ transform?: (row: Record<string, any>) => Record<string, any>;
188
+ }
189
+
190
+ export interface TsvValidationResult {
191
+ /** Whether the content is valid TSV */
192
+ isValid: boolean;
193
+ /** Number of rows detected */
194
+ rowCount: number;
195
+ /** Number of columns (if consistent) */
196
+ columnCount?: number;
197
+ /** Error message if invalid */
198
+ error?: string;
199
+ /** Line number where error occurred */
200
+ errorLine?: number;
201
+ }
202
+
203
+ export interface ValidateTsvOptions {
204
+ /** Maximum number of rows to check */
205
+ maxRows?: number;
206
+ /** Whether to check for consistent column count */
207
+ checkConsistency?: boolean;
208
+ /** Whether to validate TSV format strictly */
209
+ strict?: boolean;
210
+ }
211
+
212
+ // Worker интерфейсы для многопоточной обработки
213
+ export interface WorkerTask<T = any, R = any> {
214
+ id: string;
215
+ data: T;
216
+ type: string;
217
+ options?: Record<string, any>;
218
+ }
219
+
220
+ export interface WorkerResult<R = any> {
221
+ id: string;
222
+ result: R;
223
+ error?: Error;
224
+ duration: number;
225
+ }
226
+
227
+ export interface WorkerPoolStats {
228
+ totalWorkers: number;
229
+ activeWorkers: number;
230
+ idleWorkers: number;
231
+ totalTasks: number;
232
+ completedTasks: number;
233
+ failedTasks: number;
234
+ averageTaskDuration: number;
235
+ memoryUsage?: NodeJS.MemoryUsage;
236
+ }
237
+
238
+ // Асинхронные интерфейсы
239
+ export interface AsyncJsonToCsvOptions extends JsonToCsvOptions {
240
+ /** Use worker threads for processing (default: auto-detect based on data size) */
241
+ useWorkers?: boolean;
242
+ /** Number of worker threads to use (default: CPU cores - 1) */
243
+ workerCount?: number;
244
+ /** Size of data chunks for parallel processing */
245
+ chunkSize?: number;
246
+ /** Progress callback function */
247
+ onProgress?: (progress: { processed: number; total: number; percentage: number }) => void;
248
+ }
249
+
250
+ export interface AsyncCsvToJsonOptions extends CsvToJsonOptions {
251
+ /** Use worker threads for processing (default: auto-detect based on data size) */
252
+ useWorkers?: boolean;
253
+ /** Number of worker threads to use (default: CPU cores - 1) */
254
+ workerCount?: number;
255
+ /** Size of data chunks for parallel processing */
256
+ chunkSize?: number;
257
+ /** Progress callback function */
258
+ onProgress?: (progress: { processed: number; total: number; percentage: number }) => void;
259
+ }
260
+
261
+ // Утилитарные типы
262
+ export type PreprocessOptions = {
263
+ flatten?: boolean;
264
+ flattenSeparator?: string;
265
+ flattenMaxDepth?: number;
266
+ arrayHandling?: 'stringify' | 'join' | 'expand';
267
+ };
268
+
269
+ export type DeepUnwrapOptions = {
270
+ maxDepth?: number;
271
+ preserveArrays?: boolean;
272
+ };
273
+
274
+ // Экспорт всех интерфейсов
275
+ // Примечание: Типы ошибок экспортируются из errors.ts
@@ -0,0 +1,373 @@
1
+ /**
2
+ * BOM (Byte Order Mark) Utilities for jtcsv
3
+ *
4
+ * Provides functions to detect and strip BOM characters from UTF-8, UTF-16 LE/BE,
5
+ * and UTF-32 encoded strings/buffers.
6
+ *
7
+ * @module bom-utils
8
+ */
9
+
10
+ import { Transform } from 'stream';
11
+ import * as fs from 'fs';
12
+ import * as fsPromises from 'fs/promises';
13
+
14
+ /**
15
+ * BOM signatures for different encodings
16
+ */
17
+ export const BOM_SIGNATURES = {
18
+ 'utf-8': Buffer.from([0xEF, 0xBB, 0xBF]),
19
+ 'utf-16le': Buffer.from([0xFF, 0xFE]),
20
+ 'utf-16be': Buffer.from([0xFE, 0xFF]),
21
+ 'utf-32le': Buffer.from([0xFF, 0xFE, 0x00, 0x00]),
22
+ 'utf-32be': Buffer.from([0x00, 0x00, 0xFE, 0xFF])
23
+ } as const;
24
+
25
+ export type Encoding = keyof typeof BOM_SIGNATURES;
26
+
27
+ export interface BomDetectionResult {
28
+ encoding: Encoding;
29
+ bomLength: number;
30
+ hasBom: boolean;
31
+ }
32
+
33
+ export interface ReadFileWithBomResult {
34
+ data: Buffer | string;
35
+ encoding: string;
36
+ hadBom: boolean;
37
+ bomInfo: BomDetectionResult | null;
38
+ }
39
+
40
+ export interface NormalizeCsvInputOptions {
41
+ encoding?: string;
42
+ normalizeLineEndings?: boolean;
43
+ }
44
+
45
+ /**
46
+ * Detects if a buffer or string starts with a BOM
47
+ *
48
+ * @param input - Input to check for BOM
49
+ * @returns Detection result or null if no BOM found
50
+ */
51
+ export function detectBom(input: Buffer | string | null | undefined): BomDetectionResult | null {
52
+ if (!input) {
53
+ return null;
54
+ }
55
+
56
+ let buffer: Buffer;
57
+ if (typeof input === 'string') {
58
+ buffer = Buffer.from(input, 'utf8');
59
+ } else if (Buffer.isBuffer(input)) {
60
+ buffer = input;
61
+ } else {
62
+ return null;
63
+ }
64
+
65
+ // Check each BOM signature
66
+ for (const [encoding, signature] of Object.entries(BOM_SIGNATURES)) {
67
+ if (buffer.length >= signature.length) {
68
+ if (buffer.slice(0, signature.length).equals(signature)) {
69
+ return {
70
+ encoding: encoding as Encoding,
71
+ bomLength: signature.length,
72
+ hasBom: true
73
+ };
74
+ }
75
+ }
76
+ }
77
+
78
+ return null;
79
+ }
80
+
81
+ /**
82
+ * Strips BOM from a buffer or string
83
+ *
84
+ * @param input - Input to strip BOM from
85
+ * @returns Input without BOM
86
+ */
87
+ export function stripBom(input: Buffer | string | null | undefined): Buffer | string {
88
+ if (!input) {
89
+ return input as any;
90
+ }
91
+
92
+ const bomInfo = detectBom(input);
93
+ if (!bomInfo) {
94
+ return input;
95
+ }
96
+
97
+ if (Buffer.isBuffer(input)) {
98
+ return input.slice(bomInfo.bomLength);
99
+ }
100
+
101
+ if (typeof input === 'string') {
102
+ // Convert to buffer, strip BOM, then convert back to string
103
+ const buffer = Buffer.from(input, 'utf8');
104
+ const strippedBuffer = buffer.slice(bomInfo.bomLength);
105
+
106
+ // Determine correct encoding for conversion
107
+ let encoding: BufferEncoding = 'utf8';
108
+ if (bomInfo.encoding === 'utf-16le') {
109
+ encoding = 'utf16le';
110
+ } else if (bomInfo.encoding === 'utf-16be') {
111
+ encoding = 'utf16le'; // Node.js uses utf16le for both LE and BE, conversion handled by Buffer
112
+ }
113
+
114
+ return strippedBuffer.toString(encoding);
115
+ }
116
+
117
+ return input;
118
+ }
119
+
120
+ /**
121
+ * Strips BOM from a string (optimized for strings)
122
+ *
123
+ * @param str - String to strip BOM from
124
+ * @returns String without BOM
125
+ */
126
+ export function stripBomFromString(str: string): string {
127
+ if (typeof str !== 'string') {
128
+ return str as any;
129
+ }
130
+
131
+ // Check for UTF-8 BOM (most common)
132
+ if (str.charCodeAt(0) === 0xFEFF) {
133
+ return str.slice(1);
134
+ }
135
+
136
+ // Check for UTF-8 BOM bytes as characters
137
+ if (str.length >= 3 &&
138
+ str.charCodeAt(0) === 0xEF &&
139
+ str.charCodeAt(1) === 0xBB &&
140
+ str.charCodeAt(2) === 0xBF) {
141
+ return str.slice(3);
142
+ }
143
+
144
+ return str;
145
+ }
146
+
147
+ /**
148
+ * Creates a transform stream that strips BOM from incoming data
149
+ *
150
+ * @returns Transform stream
151
+ */
152
+ export function createBomStripStream(): Transform {
153
+ let bomStripped = false;
154
+
155
+ return new Transform({
156
+ transform(chunk: Buffer, encoding: string, callback: (error?: Error | null, data?: Buffer) => void) {
157
+ if (!bomStripped) {
158
+ const bomInfo = detectBom(chunk);
159
+ if (bomInfo) {
160
+ // Strip BOM from first chunk
161
+ chunk = chunk.slice(bomInfo.bomLength);
162
+ bomStripped = true;
163
+ } else {
164
+ bomStripped = true; // No BOM found, but we've checked
165
+ }
166
+ }
167
+
168
+ this.push(chunk);
169
+ callback();
170
+ }
171
+ });
172
+ }
173
+
174
+ /**
175
+ * Reads a file and automatically handles BOM
176
+ *
177
+ * @param filePath - Path to file
178
+ * @param options - Read options
179
+ * @returns Promise with file data and BOM info
180
+ */
181
+ export async function readFileWithBomHandling(
182
+ filePath: string,
183
+ options: { encoding?: BufferEncoding } = {}
184
+ ): Promise<ReadFileWithBomResult> {
185
+ const buffer = await fsPromises.readFile(filePath);
186
+
187
+ const bomInfo = detectBom(buffer);
188
+ const hadBom = !!bomInfo;
189
+
190
+ let data: Buffer | string;
191
+ let encoding = options.encoding || 'utf8';
192
+
193
+ if (bomInfo) {
194
+ // Strip BOM
195
+ data = buffer.slice(bomInfo.bomLength);
196
+
197
+ // Use detected encoding if not specified
198
+ if (!options.encoding) {
199
+ // Convert our encoding names to Node.js BufferEncoding
200
+ if (bomInfo.encoding === 'utf-8') {
201
+ encoding = 'utf8';
202
+ } else if (bomInfo.encoding === 'utf-16le') {
203
+ encoding = 'utf16le';
204
+ } else if (bomInfo.encoding === 'utf-16be') {
205
+ encoding = 'utf16le'; // Node.js uses utf16le for both
206
+ } else {
207
+ encoding = 'utf8'; // fallback
208
+ }
209
+ }
210
+ } else {
211
+ data = buffer;
212
+ }
213
+
214
+ // Convert to string if encoding is specified
215
+ if (options.encoding || bomInfo) {
216
+ data = data.toString(encoding);
217
+ }
218
+
219
+ return {
220
+ data,
221
+ encoding,
222
+ hadBom,
223
+ bomInfo: bomInfo || null
224
+ };
225
+ }
226
+
227
+ /**
228
+ * Checks if a file has BOM (synchronous)
229
+ *
230
+ * @param filePath - Path to file
231
+ * @returns BOM info or null
232
+ */
233
+ export function fileHasBomSync(filePath: string): BomDetectionResult | null {
234
+ const fd = fs.openSync(filePath, 'r');
235
+ const buffer = Buffer.alloc(4);
236
+ const bytesRead = fs.readSync(fd, buffer, 0, 4, 0);
237
+ fs.closeSync(fd);
238
+
239
+ if (bytesRead < 2) {
240
+ return null;
241
+ }
242
+
243
+ return detectBom(buffer.slice(0, bytesRead));
244
+ }
245
+
246
+ /**
247
+ * Normalizes CSV input by stripping BOM and ensuring proper encoding
248
+ *
249
+ * @param csvInput - CSV input
250
+ * @param options - Processing options
251
+ * @returns Normalized CSV string
252
+ */
253
+ export function normalizeCsvInput(
254
+ csvInput: string | Buffer,
255
+ options: NormalizeCsvInputOptions = {}
256
+ ): string {
257
+ if (!csvInput) {
258
+ return '';
259
+ }
260
+
261
+ let normalized: string;
262
+
263
+ if (Buffer.isBuffer(csvInput)) {
264
+ const bomInfo = detectBom(csvInput);
265
+ if (bomInfo) {
266
+ normalized = csvInput.slice(bomInfo.bomLength).toString(bomInfo.encoding as BufferEncoding);
267
+ } else {
268
+ normalized = csvInput.toString((options.encoding as BufferEncoding) || 'utf8');
269
+ }
270
+ } else if (typeof csvInput === 'string') {
271
+ normalized = stripBomFromString(csvInput);
272
+ } else {
273
+ throw new Error('CSV input must be a string or Buffer');
274
+ }
275
+
276
+ // Ensure proper line endings
277
+ if (options.normalizeLineEndings !== false) {
278
+ normalized = normalized.replace(/\r\n|\r/g, '\n');
279
+ }
280
+
281
+ return normalized;
282
+ }
283
+
284
+ /**
285
+ * Async version of normalizeCsvInput that can handle large files
286
+ *
287
+ * @param csvInput - CSV input as string, Buffer, or file path
288
+ * @param options - Processing options
289
+ * @returns Promise with normalized CSV string
290
+ */
291
+ export async function normalizeCsvInputAsync(
292
+ csvInput: string | Buffer | { filePath: string },
293
+ options: NormalizeCsvInputOptions = {}
294
+ ): Promise<string> {
295
+ if (typeof csvInput === 'object' && 'filePath' in csvInput) {
296
+ // Read file asynchronously
297
+ const result = await readFileWithBomHandling(csvInput.filePath, {
298
+ encoding: options.encoding as BufferEncoding || 'utf8'
299
+ });
300
+ let normalized = typeof result.data === 'string' ? result.data : result.data.toString();
301
+
302
+ // Ensure proper line endings
303
+ if (options.normalizeLineEndings !== false) {
304
+ normalized = normalized.replace(/\r\n|\r/g, '\n');
305
+ }
306
+
307
+ return normalized;
308
+ }
309
+
310
+ // Handle string or Buffer input
311
+ return normalizeCsvInput(csvInput as string | Buffer, options);
312
+ }
313
+
314
+ /**
315
+ * Creates an async iterator that strips BOM from a stream
316
+ *
317
+ * @param stream - Readable stream
318
+ * @returns Async iterator yielding chunks without BOM
319
+ */
320
+ export async function* createBomStrippingIterator(
321
+ stream: NodeJS.ReadableStream
322
+ ): AsyncIterableIterator<Buffer> {
323
+ let bomStripped = false;
324
+
325
+ for await (const chunk of stream) {
326
+ if (!bomStripped) {
327
+ const bomInfo = detectBom(chunk as Buffer);
328
+ if (bomInfo) {
329
+ // Strip BOM from first chunk
330
+ yield (chunk as Buffer).slice(bomInfo.bomLength);
331
+ bomStripped = true;
332
+ continue;
333
+ } else {
334
+ bomStripped = true;
335
+ }
336
+ }
337
+
338
+ yield chunk as Buffer;
339
+ }
340
+ }
341
+
342
+ /**
343
+ * Detects BOM asynchronously for large files
344
+ *
345
+ * @param filePath - Path to file
346
+ * @returns Promise with BOM info or null
347
+ */
348
+ export async function detectBomAsync(filePath: string): Promise<BomDetectionResult | null> {
349
+ const fd = await fsPromises.open(filePath, 'r');
350
+ const buffer = Buffer.alloc(4);
351
+ const { bytesRead } = await fd.read(buffer, 0, 4, 0);
352
+ await fd.close();
353
+
354
+ if (bytesRead < 2) {
355
+ return null;
356
+ }
357
+
358
+ return detectBom(buffer.slice(0, bytesRead));
359
+ }
360
+
361
+ export default {
362
+ detectBom,
363
+ stripBom,
364
+ stripBomFromString,
365
+ createBomStripStream,
366
+ readFileWithBomHandling,
367
+ fileHasBomSync,
368
+ normalizeCsvInput,
369
+ normalizeCsvInputAsync,
370
+ createBomStrippingIterator,
371
+ detectBomAsync,
372
+ BOM_SIGNATURES
373
+ };