jtcsv 2.2.7 → 3.0.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 (140) hide show
  1. package/README.md +31 -1
  2. package/bin/jtcsv.js +891 -821
  3. package/bin/jtcsv.ts +2534 -0
  4. package/csv-to-json.js +168 -145
  5. package/dist/jtcsv-core.cjs.js +1407 -0
  6. package/dist/jtcsv-core.cjs.js.map +1 -0
  7. package/dist/jtcsv-core.esm.js +1379 -0
  8. package/dist/jtcsv-core.esm.js.map +1 -0
  9. package/dist/jtcsv-core.umd.js +1413 -0
  10. package/dist/jtcsv-core.umd.js.map +1 -0
  11. package/dist/jtcsv-full.cjs.js +1912 -0
  12. package/dist/jtcsv-full.cjs.js.map +1 -0
  13. package/dist/jtcsv-full.esm.js +1880 -0
  14. package/dist/jtcsv-full.esm.js.map +1 -0
  15. package/dist/jtcsv-full.umd.js +1918 -0
  16. package/dist/jtcsv-full.umd.js.map +1 -0
  17. package/dist/jtcsv-workers.esm.js +759 -0
  18. package/dist/jtcsv-workers.esm.js.map +1 -0
  19. package/dist/jtcsv-workers.umd.js +773 -0
  20. package/dist/jtcsv-workers.umd.js.map +1 -0
  21. package/dist/jtcsv.cjs.js +61 -19
  22. package/dist/jtcsv.cjs.js.map +1 -1
  23. package/dist/jtcsv.esm.js +61 -19
  24. package/dist/jtcsv.esm.js.map +1 -1
  25. package/dist/jtcsv.umd.js +61 -19
  26. package/dist/jtcsv.umd.js.map +1 -1
  27. package/errors.js +188 -2
  28. package/examples/advanced/conditional-transformations.js +446 -0
  29. package/examples/advanced/conditional-transformations.ts +446 -0
  30. package/examples/advanced/csv-parser.worker.js +89 -0
  31. package/examples/advanced/csv-parser.worker.ts +89 -0
  32. package/examples/advanced/nested-objects-example.js +306 -0
  33. package/examples/advanced/nested-objects-example.ts +306 -0
  34. package/examples/advanced/performance-optimization.js +504 -0
  35. package/examples/advanced/performance-optimization.ts +504 -0
  36. package/examples/advanced/run-demo-server.js +116 -0
  37. package/examples/advanced/run-demo-server.ts +116 -0
  38. package/examples/advanced/web-worker-usage.html +874 -0
  39. package/examples/async-multithreaded-example.ts +335 -0
  40. package/examples/cli-advanced-usage.md +288 -0
  41. package/examples/cli-batch-processing.ts +38 -0
  42. package/examples/cli-tool.js +0 -3
  43. package/examples/cli-tool.ts +183 -0
  44. package/examples/error-handling.js +21 -7
  45. package/examples/error-handling.ts +356 -0
  46. package/examples/express-api.js +0 -3
  47. package/examples/express-api.ts +164 -0
  48. package/examples/large-dataset-example.js +0 -3
  49. package/examples/large-dataset-example.ts +204 -0
  50. package/examples/ndjson-processing.js +1 -1
  51. package/examples/ndjson-processing.ts +456 -0
  52. package/examples/plugin-excel-exporter.js +3 -4
  53. package/examples/plugin-excel-exporter.ts +406 -0
  54. package/examples/react-integration.tsx +637 -0
  55. package/examples/schema-validation.ts +640 -0
  56. package/examples/simple-usage.js +254 -254
  57. package/examples/simple-usage.ts +194 -0
  58. package/examples/streaming-example.js +4 -5
  59. package/examples/streaming-example.ts +419 -0
  60. package/examples/web-workers-advanced.ts +28 -0
  61. package/index.d.ts +1 -3
  62. package/index.js +15 -1
  63. package/json-save.js +9 -3
  64. package/json-to-csv.js +168 -21
  65. package/package.json +69 -10
  66. package/plugins/express-middleware/README.md +21 -2
  67. package/plugins/express-middleware/example.js +3 -4
  68. package/plugins/express-middleware/example.ts +135 -0
  69. package/plugins/express-middleware/index.d.ts +1 -1
  70. package/plugins/express-middleware/index.js +270 -118
  71. package/plugins/express-middleware/index.ts +557 -0
  72. package/plugins/fastify-plugin/index.js +2 -4
  73. package/plugins/fastify-plugin/index.ts +443 -0
  74. package/plugins/hono/index.ts +226 -0
  75. package/plugins/nestjs/index.ts +201 -0
  76. package/plugins/nextjs-api/examples/ConverterComponent.tsx +386 -0
  77. package/plugins/nextjs-api/examples/api-convert.js +0 -2
  78. package/plugins/nextjs-api/examples/api-convert.ts +67 -0
  79. package/plugins/nextjs-api/index.tsx +339 -0
  80. package/plugins/nextjs-api/route.js +2 -3
  81. package/plugins/nextjs-api/route.ts +370 -0
  82. package/plugins/nuxt/index.ts +94 -0
  83. package/plugins/nuxt/runtime/composables/useJtcsv.ts +100 -0
  84. package/plugins/nuxt/runtime/plugin.ts +71 -0
  85. package/plugins/remix/index.js +1 -1
  86. package/plugins/remix/index.ts +260 -0
  87. package/plugins/sveltekit/index.js +1 -1
  88. package/plugins/sveltekit/index.ts +301 -0
  89. package/plugins/trpc/index.ts +267 -0
  90. package/src/browser/browser-functions.ts +402 -0
  91. package/src/browser/core.js +92 -0
  92. package/src/browser/core.ts +152 -0
  93. package/src/browser/csv-to-json-browser.d.ts +3 -0
  94. package/src/browser/csv-to-json-browser.js +36 -14
  95. package/src/browser/csv-to-json-browser.ts +264 -0
  96. package/src/browser/errors-browser.ts +303 -0
  97. package/src/browser/extensions/plugins.js +92 -0
  98. package/src/browser/extensions/plugins.ts +93 -0
  99. package/src/browser/extensions/workers.js +39 -0
  100. package/src/browser/extensions/workers.ts +39 -0
  101. package/src/browser/globals.d.ts +5 -0
  102. package/src/browser/index.ts +192 -0
  103. package/src/browser/json-to-csv-browser.d.ts +3 -0
  104. package/src/browser/json-to-csv-browser.js +13 -3
  105. package/src/browser/json-to-csv-browser.ts +262 -0
  106. package/src/browser/streams.js +12 -2
  107. package/src/browser/streams.ts +336 -0
  108. package/src/browser/workers/csv-parser.worker.ts +377 -0
  109. package/src/browser/workers/worker-pool.ts +548 -0
  110. package/src/core/delimiter-cache.js +22 -8
  111. package/src/core/delimiter-cache.ts +310 -0
  112. package/src/core/node-optimizations.ts +449 -0
  113. package/src/core/plugin-system.js +29 -11
  114. package/src/core/plugin-system.ts +400 -0
  115. package/src/core/transform-hooks.ts +558 -0
  116. package/src/engines/fast-path-engine-new.ts +347 -0
  117. package/src/engines/fast-path-engine.ts +854 -0
  118. package/src/errors.ts +72 -0
  119. package/src/formats/ndjson-parser.ts +469 -0
  120. package/src/formats/tsv-parser.ts +334 -0
  121. package/src/index-with-plugins.js +16 -9
  122. package/src/index-with-plugins.ts +395 -0
  123. package/src/types/index.ts +255 -0
  124. package/src/utils/bom-utils.js +259 -0
  125. package/src/utils/bom-utils.ts +373 -0
  126. package/src/utils/encoding-support.js +124 -0
  127. package/src/utils/encoding-support.ts +155 -0
  128. package/src/utils/schema-validator.js +19 -19
  129. package/src/utils/schema-validator.ts +819 -0
  130. package/src/utils/transform-loader.js +1 -1
  131. package/src/utils/transform-loader.ts +389 -0
  132. package/src/utils/zod-adapter.js +170 -0
  133. package/src/utils/zod-adapter.ts +280 -0
  134. package/src/web-server/index.js +10 -10
  135. package/src/web-server/index.ts +683 -0
  136. package/src/workers/csv-multithreaded.ts +310 -0
  137. package/src/workers/csv-parser.worker.ts +227 -0
  138. package/src/workers/worker-pool.ts +409 -0
  139. package/stream-csv-to-json.js +26 -8
  140. package/stream-json-to-csv.js +1 -0
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Encoding detection and conversion utilities.
3
+ *
4
+ * Provides basic auto‑detection of UTF‑8, UTF‑16LE, UTF‑16BE with BOM,
5
+ * and fallback to a default encoding.
6
+ *
7
+ * @example
8
+ * const { detectEncoding, convertToUtf8 } = require('./encoding-support');
9
+ *
10
+ * const buffer = fs.readFileSync('data.csv');
11
+ * const encoding = detectEncoding(buffer, { fallback: 'utf8' });
12
+ * const utf8Text = convertToUtf8(buffer, encoding);
13
+ */
14
+
15
+ const { ValidationError } = require('../errors');
16
+
17
+ /**
18
+ * Detects encoding from buffer based on BOM.
19
+ *
20
+ * @param {Buffer} buffer - Input buffer
21
+ * @param {Object} options - Detection options
22
+ * @param {string} options.fallback - Fallback encoding if detection fails (default: 'utf8')
23
+ * @returns {string} Detected encoding: 'utf8', 'utf16le', 'utf16be', or fallback
24
+ */
25
+ function detectEncoding(buffer, options = {}) {
26
+ const { fallback = 'utf8' } = options;
27
+
28
+ if (!Buffer.isBuffer(buffer)) {
29
+ throw new ValidationError('Input must be a Buffer');
30
+ }
31
+
32
+ // Check BOM
33
+ if (buffer.length >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
34
+ return 'utf8';
35
+ }
36
+ if (buffer.length >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
37
+ return 'utf16be';
38
+ }
39
+ if (buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
40
+ return 'utf16le';
41
+ }
42
+
43
+ // No BOM detected, use fallback
44
+ return fallback;
45
+ }
46
+
47
+ /**
48
+ * Converts buffer to UTF‑8 string using detected encoding.
49
+ * Strips BOM if present.
50
+ *
51
+ * @param {Buffer} buffer - Input buffer
52
+ * @param {string} encoding - Source encoding ('utf8', 'utf16le', 'utf16be')
53
+ * @returns {string} UTF‑8 string without BOM
54
+ */
55
+ function convertToUtf8(buffer, encoding = 'utf8') {
56
+ if (!Buffer.isBuffer(buffer)) {
57
+ throw new ValidationError('Input must be a Buffer');
58
+ }
59
+
60
+ let offset = 0;
61
+
62
+ // Skip BOM
63
+ if (encoding === 'utf8' && buffer.length >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
64
+ offset = 3;
65
+ } else if (encoding === 'utf16be' && buffer.length >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
66
+ offset = 2;
67
+ } else if (encoding === 'utf16le' && buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
68
+ offset = 2;
69
+ }
70
+
71
+ const slice = buffer.slice(offset);
72
+ return slice.toString(encoding);
73
+ }
74
+
75
+ /**
76
+ * Auto‑detects encoding and converts buffer to UTF‑8 string.
77
+ *
78
+ * @param {Buffer} buffer - Input buffer
79
+ * @param {Object} options - Options
80
+ * @param {string} options.fallback - Fallback encoding (default: 'utf8')
81
+ * @returns {{ encoding: string, text: string }} Detected encoding and converted text
82
+ */
83
+ function autoDetectAndConvert(buffer, options = {}) {
84
+ const encoding = detectEncoding(buffer, options);
85
+ const text = convertToUtf8(buffer, encoding);
86
+ return { encoding, text };
87
+ }
88
+
89
+ /**
90
+ * Creates a wrapper around csvToJson that accepts Buffer or string with encoding detection.
91
+ *
92
+ * @param {Buffer|string} input - CSV as Buffer or string
93
+ * @param {Object} parseOptions - Options for csvToJson
94
+ * @param {string} parseOptions.encoding - Explicit encoding (default: 'auto')
95
+ * @param {string} parseOptions.fallbackEncoding - Fallback if auto detection fails (default: 'utf8')
96
+ * @returns {Promise<Array>} Parsed JSON data
97
+ */
98
+ async function csvToJsonWithEncoding(input, parseOptions = {}) {
99
+ const { csvToJson } = require('../index');
100
+ const { encoding = 'auto', fallbackEncoding = 'utf8', ...restOptions } = parseOptions;
101
+
102
+ let text;
103
+ if (Buffer.isBuffer(input)) {
104
+ if (encoding === 'auto') {
105
+ const detected = autoDetectAndConvert(input, { fallback: fallbackEncoding });
106
+ text = detected.text;
107
+ } else {
108
+ text = convertToUtf8(input, encoding);
109
+ }
110
+ } else if (typeof input === 'string') {
111
+ text = input;
112
+ } else {
113
+ throw new ValidationError('Input must be a Buffer or string');
114
+ }
115
+
116
+ return csvToJson(text, restOptions);
117
+ }
118
+
119
+ module.exports = {
120
+ detectEncoding,
121
+ convertToUtf8,
122
+ autoDetectAndConvert,
123
+ csvToJsonWithEncoding
124
+ };
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Encoding detection and conversion utilities.
3
+ *
4
+ * Provides basic auto‑detection of UTF‑8, UTF‑16LE, UTF‑16BE with BOM,
5
+ * and fallback to a default encoding.
6
+ *
7
+ * @example
8
+ * import { detectEncoding, convertToUtf8 } from './encoding-support';
9
+ *
10
+ * const buffer = fs.readFileSync('data.csv');
11
+ * const encoding = detectEncoding(buffer, { fallback: 'utf8' });
12
+ * const utf8Text = convertToUtf8(buffer, encoding);
13
+ */
14
+
15
+ import { ValidationError } from '../errors';
16
+
17
+ export interface DetectEncodingOptions {
18
+ fallback?: 'utf8' | 'utf16le' | 'utf16be' | string;
19
+ }
20
+
21
+ export interface AutoDetectAndConvertOptions {
22
+ fallback?: string;
23
+ }
24
+
25
+ export interface CsvToJsonWithEncodingOptions {
26
+ encoding?: 'auto' | 'utf8' | 'utf16le' | 'utf16be' | string;
27
+ fallbackEncoding?: string;
28
+ [key: string]: any;
29
+ }
30
+
31
+ /**
32
+ * Detects encoding from buffer based on BOM.
33
+ *
34
+ * @param buffer - Input buffer
35
+ * @param options - Detection options
36
+ * @param options.fallback - Fallback encoding if detection fails (default: 'utf8')
37
+ * @returns Detected encoding: 'utf8', 'utf16le', 'utf16be', or fallback
38
+ */
39
+ export function detectEncoding(buffer: Buffer, options: DetectEncodingOptions = {}): string {
40
+ const { fallback = 'utf8' } = options;
41
+
42
+ if (!Buffer.isBuffer(buffer)) {
43
+ throw new ValidationError('Input must be a Buffer');
44
+ }
45
+
46
+ // Check BOM
47
+ if (buffer.length >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
48
+ return 'utf8';
49
+ }
50
+ if (buffer.length >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
51
+ return 'utf16be';
52
+ }
53
+ if (buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
54
+ return 'utf16le';
55
+ }
56
+
57
+ // No BOM detected, use fallback
58
+ return fallback;
59
+ }
60
+
61
+ /**
62
+ * Converts buffer to UTF‑8 string using detected encoding.
63
+ * Strips BOM if present.
64
+ *
65
+ * @param buffer - Input buffer
66
+ * @param encoding - Source encoding ('utf8', 'utf16le', 'utf16be')
67
+ * @returns UTF‑8 string without BOM
68
+ */
69
+ export function convertToUtf8(buffer: Buffer, encoding: string = 'utf8'): string {
70
+ if (!Buffer.isBuffer(buffer)) {
71
+ throw new ValidationError('Input must be a Buffer');
72
+ }
73
+
74
+ let offset = 0;
75
+
76
+ // Skip BOM
77
+ if (encoding === 'utf8' && buffer.length >= 3 && buffer[0] === 0xEF && buffer[1] === 0xBB && buffer[2] === 0xBF) {
78
+ offset = 3;
79
+ } else if (encoding === 'utf16be' && buffer.length >= 2 && buffer[0] === 0xFE && buffer[1] === 0xFF) {
80
+ offset = 2;
81
+ } else if (encoding === 'utf16le' && buffer.length >= 2 && buffer[0] === 0xFF && buffer[1] === 0xFE) {
82
+ offset = 2;
83
+ }
84
+
85
+ const slice = buffer.slice(offset);
86
+ return slice.toString(encoding as BufferEncoding);
87
+ }
88
+
89
+ /**
90
+ * Auto‑detects encoding and converts buffer to UTF‑8 string.
91
+ *
92
+ * @param buffer - Input buffer
93
+ * @param options - Options
94
+ * @param options.fallback - Fallback encoding (default: 'utf8')
95
+ * @returns Detected encoding and converted text
96
+ */
97
+ export function autoDetectAndConvert(
98
+ buffer: Buffer,
99
+ options: AutoDetectAndConvertOptions = {}
100
+ ): { encoding: string; text: string } {
101
+ const encoding = detectEncoding(buffer, options);
102
+ const text = convertToUtf8(buffer, encoding);
103
+ return { encoding, text };
104
+ }
105
+
106
+ /**
107
+ * Creates a wrapper around csvToJson that accepts Buffer or string with encoding detection.
108
+ *
109
+ * @param input - CSV as Buffer or string
110
+ * @param parseOptions - Options for csvToJson
111
+ * @param parseOptions.encoding - Explicit encoding (default: 'auto')
112
+ * @param parseOptions.fallbackEncoding - Fallback if auto detection fails (default: 'utf8')
113
+ * @returns Promise with parsed JSON data
114
+ */
115
+ export async function csvToJsonWithEncoding(
116
+ input: Buffer | string,
117
+ parseOptions: CsvToJsonWithEncodingOptions = {}
118
+ ): Promise<any[]> {
119
+ const { encoding = 'auto', fallbackEncoding = 'utf8', ...restOptions } = parseOptions;
120
+
121
+ let text: string;
122
+ if (Buffer.isBuffer(input)) {
123
+ if (encoding === 'auto') {
124
+ const detected = autoDetectAndConvert(input, { fallback: fallbackEncoding });
125
+ text = detected.text;
126
+ } else {
127
+ text = convertToUtf8(input, encoding);
128
+ }
129
+ } else if (typeof input === 'string') {
130
+ text = input;
131
+ } else {
132
+ throw new ValidationError('Input must be a Buffer or string');
133
+ }
134
+
135
+ // csvToJson will be provided by the caller or imported elsewhere
136
+ throw new Error('csvToJson function not available. This function requires csvToJson to be provided.');
137
+ }
138
+
139
+ /**
140
+ * Async version of csvToJsonWithEncoding
141
+ */
142
+ export async function csvToJsonWithEncodingAsync(
143
+ input: Buffer | string,
144
+ parseOptions: CsvToJsonWithEncodingOptions = {}
145
+ ): Promise<any[]> {
146
+ return csvToJsonWithEncoding(input, parseOptions);
147
+ }
148
+
149
+ export default {
150
+ detectEncoding,
151
+ convertToUtf8,
152
+ autoDetectAndConvert,
153
+ csvToJsonWithEncoding,
154
+ csvToJsonWithEncodingAsync
155
+ };
@@ -125,7 +125,7 @@ function createValidationHook(schema) {
125
125
  }
126
126
 
127
127
  // Return a hook function compatible with hooks.perRow
128
- return function(row, index, context) {
128
+ return function (row, index, context) {
129
129
  try {
130
130
  const result = validator.validate([row], {
131
131
  stopOnFirstError: true,
@@ -323,24 +323,24 @@ function createSimpleValidator(schema) {
323
323
  */
324
324
  function checkType(value, type) {
325
325
  switch (type) {
326
- case 'string':
327
- return typeof value === 'string';
328
- case 'number':
329
- return typeof value === 'number' && !isNaN(value);
330
- case 'boolean':
331
- return typeof value === 'boolean';
332
- case 'integer':
333
- return Number.isInteger(value);
334
- case 'float':
335
- return typeof value === 'number' && !Number.isInteger(value);
336
- case 'date':
337
- return value instanceof Date && !isNaN(value);
338
- case 'array':
339
- return Array.isArray(value);
340
- case 'object':
341
- return typeof value === 'object' && value !== null && !Array.isArray(value);
342
- default:
343
- return false;
326
+ case 'string':
327
+ return typeof value === 'string';
328
+ case 'number':
329
+ return typeof value === 'number' && !isNaN(value);
330
+ case 'boolean':
331
+ return typeof value === 'boolean';
332
+ case 'integer':
333
+ return Number.isInteger(value);
334
+ case 'float':
335
+ return typeof value === 'number' && !Number.isInteger(value);
336
+ case 'date':
337
+ return value instanceof Date && !isNaN(value);
338
+ case 'array':
339
+ return Array.isArray(value);
340
+ case 'object':
341
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
342
+ default:
343
+ return false;
344
344
  }
345
345
  }
346
346