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
@@ -1,434 +1,456 @@
1
- /**
2
- * NDJSON Processing Examples for jtcsv
3
- *
4
- * NDJSON (Newline Delimited JSON) is a format where each line
5
- * is a valid JSON object. It's ideal for streaming large datasets
6
- * and log processing.
7
- */
8
-
9
- const {
10
- jsonToNdjson,
11
- ndjsonToJson,
12
- parseNdjsonStream,
13
- createNdjsonToCsvStream,
14
- createCsvToNdjsonStream,
15
- getNdjsonStats
16
- } = require('jtcsv');
17
-
18
- const fs = require('fs');
19
- const path = require('path');
20
- const { Readable, PassThrough } = require('stream');
21
-
22
- // =============================================================================
23
- // Example 1: Basic NDJSON Conversion
24
- // =============================================================================
25
-
26
- function basicNdjsonConversion() {
27
- console.log('\n=== Basic NDJSON Conversion ===\n');
28
-
29
- const data = [
30
- { id: 1, event: 'login', user: 'john', timestamp: '2024-01-15T10:30:00Z' },
31
- { id: 2, event: 'click', user: 'john', timestamp: '2024-01-15T10:30:15Z' },
32
- { id: 3, event: 'purchase', user: 'john', timestamp: '2024-01-15T10:31:00Z' },
33
- { id: 4, event: 'logout', user: 'john', timestamp: '2024-01-15T10:35:00Z' }
34
- ];
35
-
36
- // Convert to NDJSON
37
- const ndjson = jsonToNdjson(data);
38
- console.log('NDJSON output:');
39
- console.log(ndjson);
40
-
41
- // Parse back to JSON
42
- const parsed = ndjsonToJson(ndjson);
43
- console.log('\nParsed back:', parsed.length, 'records');
44
- }
45
-
46
- // =============================================================================
47
- // Example 2: NDJSON with Transform and Filter
48
- // =============================================================================
49
-
50
- function ndjsonWithTransformAndFilter() {
51
- console.log('\n=== NDJSON with Transform and Filter ===\n');
52
-
53
- const logEntries = [
54
- { level: 'info', message: 'Application started', ts: 1705312200 },
55
- { level: 'debug', message: 'Connecting to database', ts: 1705312201 },
56
- { level: 'error', message: 'Connection failed', ts: 1705312202 },
57
- { level: 'info', message: 'Retry connection', ts: 1705312203 },
58
- { level: 'info', message: 'Connected successfully', ts: 1705312204 },
59
- { level: 'debug', message: 'Query executed', ts: 1705312205 }
60
- ];
61
-
62
- // Convert with transform - add formatted timestamp
63
- const ndjson = jsonToNdjson(logEntries, {
64
- transform: (obj, index) => ({
65
- ...obj,
66
- index,
67
- formattedTime: new Date(obj.ts * 1000).toISOString()
68
- })
69
- });
70
- console.log('Transformed NDJSON:');
71
- console.log(ndjson);
72
-
73
- // Parse back with filter - only errors and info
74
- const filtered = ndjsonToJson(ndjson, {
75
- filter: (obj) => obj.level === 'error' || obj.level === 'info'
76
- });
77
- console.log('\nFiltered entries (error + info only):', filtered.length);
78
- filtered.forEach(e => console.log(` [${e.level}] ${e.message}`));
79
- }
80
-
81
- // =============================================================================
82
- // Example 3: NDJSON Error Handling
83
- // =============================================================================
84
-
85
- function ndjsonErrorHandling() {
86
- console.log('\n=== NDJSON Error Handling ===\n');
87
-
88
- // NDJSON with some invalid lines
89
- const mixedNdjson = `{"id": 1, "valid": true}
90
- {"id": 2, "valid": true}
91
- {invalid json here}
92
- {"id": 3, "valid": true}
93
- not json at all
94
- {"id": 4, "valid": true}`;
95
-
96
- const errors = [];
97
-
98
- const result = ndjsonToJson(mixedNdjson, {
99
- onError: (error, line, lineNumber) => {
100
- errors.push({
101
- lineNumber,
102
- error: error.message,
103
- content: line.substring(0, 30) + (line.length > 30 ? '...' : '')
104
- });
105
- }
106
- });
107
-
108
- console.log('Valid records:', result.length);
109
- console.log('Errors encountered:', errors.length);
110
- errors.forEach(e => {
111
- console.log(` Line ${e.lineNumber}: ${e.error}`);
112
- console.log(` Content: ${e.content}`);
113
- });
114
- }
115
-
116
- // =============================================================================
117
- // Example 4: Streaming NDJSON Processing
118
- // =============================================================================
119
-
120
- async function streamingNdjsonProcessing() {
121
- console.log('\n=== Streaming NDJSON Processing ===\n');
122
-
123
- // Create a stream from NDJSON string
124
- const ndjsonContent = `{"type": "user", "name": "Alice", "age": 28}
125
- {"type": "user", "name": "Bob", "age": 35}
126
- {"type": "product", "name": "Laptop", "price": 999}
127
- {"type": "user", "name": "Charlie", "age": 42}
128
- {"type": "product", "name": "Phone", "price": 599}`;
129
-
130
- // Create readable stream
131
- const stream = Readable.from([ndjsonContent]);
132
-
133
- // Process stream with async iterator
134
- const users = [];
135
- const products = [];
136
-
137
- for await (const obj of parseNdjsonStream(stream)) {
138
- if (obj.type === 'user') {
139
- users.push(obj);
140
- } else if (obj.type === 'product') {
141
- products.push(obj);
142
- }
143
- }
144
-
145
- console.log('Users found:', users.length);
146
- users.forEach(u => console.log(` - ${u.name}, ${u.age} years old`));
147
-
148
- console.log('\nProducts found:', products.length);
149
- products.forEach(p => console.log(` - ${p.name}: $${p.price}`));
150
- }
151
-
152
- // =============================================================================
153
- // Example 5: NDJSON to CSV Conversion
154
- // =============================================================================
155
-
156
- async function ndjsonToCsvConversion() {
157
- console.log('\n=== NDJSON to CSV Conversion ===\n');
158
-
159
- const ndjson = `{"name": "Alice", "department": "Engineering", "salary": 85000}
160
- {"name": "Bob", "department": "Marketing", "salary": 65000}
161
- {"name": "Charlie", "department": "Engineering", "salary": 90000}
162
- {"name": "Diana", "department": "Sales", "salary": 70000}`;
163
-
164
- // Create NDJSON to CSV transform stream
165
- const transformStream = createNdjsonToCsvStream({
166
- delimiter: ',',
167
- includeHeaders: true
168
- });
169
-
170
- // Collect CSV output
171
- let csvOutput = '';
172
- transformStream.writable.getWriter();
173
-
174
- // Manual stream processing for demo
175
- const lines = ndjson.split('\n');
176
- const objects = lines.map(line => JSON.parse(line));
177
-
178
- // Convert to CSV manually for this example
179
- const { jsonToCsv } = require('jtcsv');
180
- const csv = jsonToCsv(objects, { delimiter: ',' });
181
-
182
- console.log('Converted CSV:');
183
- console.log(csv);
184
- }
185
-
186
- // =============================================================================
187
- // Example 6: CSV to NDJSON Conversion
188
- // =============================================================================
189
-
190
- function csvToNdjsonConversion() {
191
- console.log('\n=== CSV to NDJSON Conversion ===\n');
192
-
193
- const csv = `id,name,email,active
194
- 1,John Doe,john@example.com,true
195
- 2,Jane Smith,jane@example.com,false
196
- 3,Bob Wilson,bob@example.com,true`;
197
-
198
- const { csvToJson } = require('jtcsv');
199
-
200
- // Parse CSV first
201
- const data = csvToJson(csv, {
202
- parseNumbers: true,
203
- parseBooleans: true
204
- });
205
-
206
- // Convert to NDJSON
207
- const ndjson = jsonToNdjson(data);
208
- console.log('NDJSON output:');
209
- console.log(ndjson);
210
- }
211
-
212
- // =============================================================================
213
- // Example 7: NDJSON Statistics
214
- // =============================================================================
215
-
216
- async function ndjsonStatistics() {
217
- console.log('\n=== NDJSON Statistics ===\n');
218
-
219
- const ndjson = `{"id": 1, "type": "event"}
220
- {"id": 2, "type": "event"}
221
- {invalid}
222
- {"id": 3, "type": "event"}
223
- not json
224
- {"id": 4, "type": "event"}
225
- {"id": 5, "type": "event"}`;
226
-
227
- const stats = await getNdjsonStats(ndjson);
228
-
229
- console.log('NDJSON Statistics:');
230
- console.log(' Total lines:', stats.totalLines);
231
- console.log(' Valid lines:', stats.validLines);
232
- console.log(' Error lines:', stats.errorLines);
233
- console.log(' Total bytes:', stats.totalBytes);
234
- console.log(' Success rate:', (stats.successRate * 100).toFixed(1) + '%');
235
-
236
- if (stats.errors.length > 0) {
237
- console.log('\nErrors:');
238
- stats.errors.forEach(e => {
239
- console.log(` Line ${e.line}: ${e.error}`);
240
- });
241
- }
242
- }
243
-
244
- // =============================================================================
245
- // Example 8: Large NDJSON Processing with Memory Efficiency
246
- // =============================================================================
247
-
248
- async function largeNdjsonProcessing() {
249
- console.log('\n=== Large NDJSON Processing ===\n');
250
-
251
- // Simulate large NDJSON data
252
- const generateLargeNdjson = (count) => {
253
- const lines = [];
254
- for (let i = 0; i < count; i++) {
255
- lines.push(JSON.stringify({
256
- id: i,
257
- timestamp: Date.now() + i,
258
- value: Math.random() * 100,
259
- category: ['A', 'B', 'C'][i % 3]
260
- }));
261
- }
262
- return lines.join('\n');
263
- };
264
-
265
- const largeNdjson = generateLargeNdjson(10000);
266
- console.log(`Generated ${largeNdjson.split('\n').length} NDJSON lines`);
267
-
268
- // Process with aggregation
269
- const stats = {
270
- count: 0,
271
- sum: 0,
272
- categories: {}
273
- };
274
-
275
- const startTime = Date.now();
276
-
277
- for await (const obj of parseNdjsonStream(Readable.from([largeNdjson]))) {
278
- stats.count++;
279
- stats.sum += obj.value;
280
- stats.categories[obj.category] = (stats.categories[obj.category] || 0) + 1;
281
- }
282
-
283
- const endTime = Date.now();
284
-
285
- console.log('\nAggregation results:');
286
- console.log(' Records processed:', stats.count);
287
- console.log(' Average value:', (stats.sum / stats.count).toFixed(2));
288
- console.log(' Categories:', stats.categories);
289
- console.log(' Processing time:', endTime - startTime, 'ms');
290
- console.log(' Throughput:', Math.round(stats.count / ((endTime - startTime) / 1000)), 'records/sec');
291
- }
292
-
293
- // =============================================================================
294
- // Example 9: NDJSON Log Processing Pipeline
295
- // =============================================================================
296
-
297
- async function logProcessingPipeline() {
298
- console.log('\n=== NDJSON Log Processing Pipeline ===\n');
299
-
300
- // Simulated log entries
301
- const logs = `{"ts": "2024-01-15T10:00:00Z", "level": "info", "service": "api", "msg": "Request received", "duration_ms": 50}
302
- {"ts": "2024-01-15T10:00:01Z", "level": "debug", "service": "api", "msg": "Processing request", "duration_ms": 0}
303
- {"ts": "2024-01-15T10:00:02Z", "level": "warn", "service": "db", "msg": "Slow query detected", "duration_ms": 1500}
304
- {"ts": "2024-01-15T10:00:03Z", "level": "error", "service": "api", "msg": "Request failed", "duration_ms": 100, "error": "Timeout"}
305
- {"ts": "2024-01-15T10:00:04Z", "level": "info", "service": "api", "msg": "Request completed", "duration_ms": 45}
306
- {"ts": "2024-01-15T10:00:05Z", "level": "error", "service": "db", "msg": "Connection lost", "duration_ms": 0, "error": "Network error"}`;
307
-
308
- // Pipeline stages
309
- const pipeline = {
310
- errors: [],
311
- warnings: [],
312
- slowRequests: [],
313
- serviceStats: {}
314
- };
315
-
316
- // Process logs
317
- for await (const log of parseNdjsonStream(Readable.from([logs]))) {
318
- // Collect errors
319
- if (log.level === 'error') {
320
- pipeline.errors.push({
321
- time: log.ts,
322
- service: log.service,
323
- message: log.msg,
324
- error: log.error
325
- });
326
- }
327
-
328
- // Collect warnings
329
- if (log.level === 'warn') {
330
- pipeline.warnings.push({
331
- time: log.ts,
332
- service: log.service,
333
- message: log.msg
334
- });
335
- }
336
-
337
- // Track slow requests (> 1000ms)
338
- if (log.duration_ms > 1000) {
339
- pipeline.slowRequests.push({
340
- time: log.ts,
341
- service: log.service,
342
- duration: log.duration_ms
343
- });
344
- }
345
-
346
- // Aggregate by service
347
- if (!pipeline.serviceStats[log.service]) {
348
- pipeline.serviceStats[log.service] = { count: 0, errors: 0 };
349
- }
350
- pipeline.serviceStats[log.service].count++;
351
- if (log.level === 'error') {
352
- pipeline.serviceStats[log.service].errors++;
353
- }
354
- }
355
-
356
- // Report
357
- console.log('Log Analysis Report:');
358
- console.log('\nErrors:', pipeline.errors.length);
359
- pipeline.errors.forEach(e => {
360
- console.log(` [${e.service}] ${e.message} - ${e.error}`);
361
- });
362
-
363
- console.log('\nWarnings:', pipeline.warnings.length);
364
- pipeline.warnings.forEach(w => {
365
- console.log(` [${w.service}] ${w.message}`);
366
- });
367
-
368
- console.log('\nSlow Requests (>1s):', pipeline.slowRequests.length);
369
- pipeline.slowRequests.forEach(s => {
370
- console.log(` [${s.service}] ${s.duration}ms`);
371
- });
372
-
373
- console.log('\nService Statistics:');
374
- Object.entries(pipeline.serviceStats).forEach(([service, stats]) => {
375
- const errorRate = ((stats.errors / stats.count) * 100).toFixed(1);
376
- console.log(` ${service}: ${stats.count} requests, ${stats.errors} errors (${errorRate}%)`);
377
- });
378
- }
379
-
380
- // =============================================================================
381
- // Example 10: NDJSON Pretty Print and Compact
382
- // =============================================================================
383
-
384
- function ndjsonFormatting() {
385
- console.log('\n=== NDJSON Formatting Options ===\n');
386
-
387
- const data = [
388
- { name: 'Test', nested: { a: 1, b: 2 }, array: [1, 2, 3] }
389
- ];
390
-
391
- // Compact (default)
392
- const compact = jsonToNdjson(data);
393
- console.log('Compact:');
394
- console.log(compact);
395
-
396
- // With custom replacer (filter out 'array' field)
397
- const filtered = jsonToNdjson(data, {
398
- replacer: (key, value) => key === 'array' ? undefined : value
399
- });
400
- console.log('\nFiltered (no array):');
401
- console.log(filtered);
402
-
403
- // With space for readability (not standard NDJSON but useful for debugging)
404
- const pretty = jsonToNdjson(data, {
405
- space: 0 // Standard NDJSON should have no space
406
- });
407
- console.log('\nStandard NDJSON:');
408
- console.log(pretty);
409
- }
410
-
411
- // =============================================================================
412
- // Run All Examples
413
- // =============================================================================
414
-
415
- async function main() {
416
- console.log('jtcsv NDJSON Processing Examples');
417
- console.log('='.repeat(60));
418
-
419
- basicNdjsonConversion();
420
- ndjsonWithTransformAndFilter();
421
- ndjsonErrorHandling();
422
- await streamingNdjsonProcessing();
423
- await ndjsonToCsvConversion();
424
- csvToNdjsonConversion();
425
- await ndjsonStatistics();
426
- await largeNdjsonProcessing();
427
- await logProcessingPipeline();
428
- ndjsonFormatting();
429
-
430
- console.log('\n' + '='.repeat(60));
431
- console.log('All NDJSON examples completed.');
432
- }
433
-
434
- main().catch(console.error);
1
+ /**
2
+ * NDJSON Processing Examples for jtcsv
3
+ *
4
+ * NDJSON (Newline Delimited JSON) is a format where each line
5
+ * is a valid JSON object. It's ideal for streaming large datasets
6
+ * and log processing.
7
+ */
8
+
9
+ import {
10
+ jsonToNdjson,
11
+ ndjsonToJson,
12
+ parseNdjsonStream,
13
+ createNdjsonToCsvStream,
14
+ createCsvToNdjsonStream,
15
+ getNdjsonStats,
16
+ jsonToCsv,
17
+ csvToJson
18
+ } from '../index';
19
+
20
+ import fs from 'fs';
21
+ import path from 'path';
22
+ import { Readable, PassThrough } from 'stream';
23
+
24
+ // Типы для NDJSON
25
+ interface LogEntry {
26
+ level: string;
27
+ message: string;
28
+ ts: number;
29
+ }
30
+
31
+ interface NdjsonStats {
32
+ totalLines: number;
33
+ validLines: number;
34
+ errorLines: number;
35
+ totalBytes: number;
36
+ successRate: number;
37
+ errors: Array<{line: number, error: string}>;
38
+ }
39
+
40
+ // =============================================================================
41
+ // Example 1: Basic NDJSON Conversion
42
+ // =============================================================================
43
+
44
+ function basicNdjsonConversion() {
45
+ console.log('\n=== Basic NDJSON Conversion ===\n');
46
+
47
+ const data = [
48
+ { id: 1, event: 'login', user: 'john', timestamp: '2024-01-15T10:30:00Z' },
49
+ { id: 2, event: 'click', user: 'john', timestamp: '2024-01-15T10:30:15Z' },
50
+ { id: 3, event: 'purchase', user: 'john', timestamp: '2024-01-15T10:31:00Z' },
51
+ { id: 4, event: 'logout', user: 'john', timestamp: '2024-01-15T10:35:00Z' }
52
+ ];
53
+
54
+ // Convert to NDJSON
55
+ const ndjson = jsonToNdjson(data);
56
+ console.log('NDJSON output:');
57
+ console.log(ndjson);
58
+
59
+ // Parse back to JSON
60
+ const parsed = ndjsonToJson(ndjson);
61
+ console.log('\nParsed back:', parsed.length, 'records');
62
+ }
63
+
64
+ // =============================================================================
65
+ // Example 2: NDJSON with Transform and Filter
66
+ // =============================================================================
67
+
68
+ function ndjsonWithTransformAndFilter() {
69
+ console.log('\n=== NDJSON with Transform and Filter ===\n');
70
+
71
+ const logEntries = [
72
+ { level: 'info', message: 'Application started', ts: 1705312200 },
73
+ { level: 'debug', message: 'Connecting to database', ts: 1705312201 },
74
+ { level: 'error', message: 'Connection failed', ts: 1705312202 },
75
+ { level: 'info', message: 'Retry connection', ts: 1705312203 },
76
+ { level: 'info', message: 'Connected successfully', ts: 1705312204 },
77
+ { level: 'debug', message: 'Query executed', ts: 1705312205 }
78
+ ];
79
+
80
+ // Convert with transform - add formatted timestamp
81
+ const ndjson = jsonToNdjson(logEntries, {
82
+ transform: (obj: LogEntry, index: number) => ({
83
+ ...obj,
84
+ index,
85
+ formattedTime: new Date(obj.ts * 1000).toISOString()
86
+ })
87
+ });
88
+ console.log('Transformed NDJSON:');
89
+ console.log(ndjson);
90
+
91
+ // Parse back with filter - only errors and info
92
+ const filtered = ndjsonToJson(ndjson, {
93
+ filter: (obj: any) => obj.level === 'error' || obj.level === 'info'
94
+ });
95
+ console.log('\nFiltered entries (error + info only):', filtered.length);
96
+ filtered.forEach(e => console.log(` [${e.level}] ${e.message}`));
97
+ }
98
+
99
+ // =============================================================================
100
+ // Example 3: NDJSON Error Handling
101
+ // =============================================================================
102
+
103
+ function ndjsonErrorHandling() {
104
+ console.log('\n=== NDJSON Error Handling ===\n');
105
+
106
+ // NDJSON with some invalid lines
107
+ const mixedNdjson = `{"id": 1, "valid": true}
108
+ {"id": 2, "valid": true}
109
+ {invalid json here}
110
+ {"id": 3, "valid": true}
111
+ not json at all
112
+ {"id": 4, "valid": true}`;
113
+
114
+ const errors: Array<{lineNumber: number, error: string, content: string}> = [];
115
+
116
+ const result = ndjsonToJson(mixedNdjson, {
117
+ onError: (error: Error, line: string, lineNumber: number) => {
118
+ errors.push({
119
+ lineNumber,
120
+ error: error.message,
121
+ content: line.substring(0, 30) + (line.length > 30 ? '...' : '')
122
+ });
123
+ }
124
+ });
125
+
126
+ console.log('Valid records:', result.length);
127
+ console.log('Errors encountered:', errors.length);
128
+ errors.forEach(e => {
129
+ console.log(` Line ${e.lineNumber}: ${e.error}`);
130
+ console.log(` Content: ${e.content}`);
131
+ });
132
+ }
133
+
134
+ // =============================================================================
135
+ // Example 4: Streaming NDJSON Processing
136
+ // =============================================================================
137
+
138
+ async function streamingNdjsonProcessing() {
139
+ console.log('\n=== Streaming NDJSON Processing ===\n');
140
+
141
+ // Create a stream from NDJSON string
142
+ const ndjsonContent = `{"type": "user", "name": "Alice", "age": 28}
143
+ {"type": "user", "name": "Bob", "age": 35}
144
+ {"type": "product", "name": "Laptop", "price": 999}
145
+ {"type": "user", "name": "Charlie", "age": 42}
146
+ {"type": "product", "name": "Phone", "price": 599}`;
147
+
148
+ // Create readable stream
149
+ const stream = Readable.from([ndjsonContent]);
150
+
151
+ // Process stream with async iterator
152
+ const users: any[] = [];
153
+ const products: any[] = [];
154
+
155
+ // parseNdjsonStream принимает string или ReadableStream, преобразуем
156
+ const ndjsonString = ndjsonContent;
157
+ const parsed = ndjsonToJson(ndjsonString);
158
+
159
+ for (const obj of parsed) {
160
+ if (obj.type === 'user') {
161
+ users.push(obj);
162
+ } else if (obj.type === 'product') {
163
+ products.push(obj);
164
+ }
165
+ }
166
+
167
+ console.log('Users found:', users.length);
168
+ users.forEach(u => console.log(` - ${u.name}, ${u.age} years old`));
169
+
170
+ console.log('\nProducts found:', products.length);
171
+ products.forEach(p => console.log(` - ${p.name}: $${p.price}`));
172
+ }
173
+
174
+ // =============================================================================
175
+ // Example 5: NDJSON to CSV Conversion
176
+ // =============================================================================
177
+
178
+ async function ndjsonToCsvConversion() {
179
+ console.log('\n=== NDJSON to CSV Conversion ===\n');
180
+
181
+ const ndjson = `{"name": "Alice", "department": "Engineering", "salary": 85000}
182
+ {"name": "Bob", "department": "Marketing", "salary": 65000}
183
+ {"name": "Charlie", "department": "Engineering", "salary": 90000}
184
+ {"name": "Diana", "department": "Sales", "salary": 70000}`;
185
+
186
+ // Create NDJSON to CSV transform stream
187
+ const transformStream = createNdjsonToCsvStream({
188
+ delimiter: ',',
189
+ includeHeaders: true
190
+ });
191
+
192
+ // Collect CSV output
193
+ const csvOutput = '';
194
+ transformStream.writable.getWriter();
195
+
196
+ // Manual stream processing for demo
197
+ const lines = ndjson.split('\n');
198
+ const objects = lines.map(line => JSON.parse(line));
199
+
200
+ // Convert to CSV manually for this example
201
+ const csv = jsonToCsv(objects, { delimiter: ',' });
202
+
203
+ console.log('Converted CSV:');
204
+ console.log(csv);
205
+ }
206
+
207
+ // =============================================================================
208
+ // Example 6: CSV to NDJSON Conversion
209
+ // =============================================================================
210
+
211
+ function csvToNdjsonConversion() {
212
+ console.log('\n=== CSV to NDJSON Conversion ===\n');
213
+
214
+ const csv = `id,name,email,active
215
+ 1,John Doe,john@example.com,true
216
+ 2,Jane Smith,jane@example.com,false
217
+ 3,Bob Wilson,bob@example.com,true`;
218
+
219
+ // Parse CSV first
220
+ const data = csvToJson(csv, {
221
+ parseNumbers: true,
222
+ parseBooleans: true
223
+ });
224
+
225
+ // Convert to NDJSON
226
+ const ndjson = jsonToNdjson(data);
227
+ console.log('NDJSON output:');
228
+ console.log(ndjson);
229
+ }
230
+
231
+ // =============================================================================
232
+ // Example 7: NDJSON Statistics
233
+ // =============================================================================
234
+
235
+ async function ndjsonStatistics() {
236
+ console.log('\n=== NDJSON Statistics ===\n');
237
+
238
+ const ndjson = `{"id": 1, "type": "event"}
239
+ {"id": 2, "type": "event"}
240
+ {invalid}
241
+ {"id": 3, "type": "event"}
242
+ not json
243
+ {"id": 4, "type": "event"}
244
+ {"id": 5, "type": "event"}`;
245
+
246
+ const stats = await getNdjsonStats(ndjson) as NdjsonStats;
247
+
248
+ console.log('NDJSON Statistics:');
249
+ console.log(' Total lines:', stats.totalLines);
250
+ console.log(' Valid lines:', stats.validLines);
251
+ console.log(' Error lines:', stats.errorLines);
252
+ console.log(' Total bytes:', stats.totalBytes);
253
+ console.log(' Success rate:', (stats.successRate * 100).toFixed(1) + '%');
254
+
255
+ if (stats.errors.length > 0) {
256
+ console.log('\nErrors:');
257
+ stats.errors.forEach(e => {
258
+ console.log(` Line ${e.line}: ${e.error}`);
259
+ });
260
+ }
261
+ }
262
+
263
+ // =============================================================================
264
+ // Example 8: Large NDJSON Processing with Memory Efficiency
265
+ // =============================================================================
266
+
267
+ async function largeNdjsonProcessing() {
268
+ console.log('\n=== Large NDJSON Processing ===\n');
269
+
270
+ // Simulate large NDJSON data
271
+ const generateLargeNdjson = (count: number) => {
272
+ const lines = [];
273
+ for (let i = 0; i < count; i++) {
274
+ lines.push(JSON.stringify({
275
+ id: i,
276
+ timestamp: Date.now() + i,
277
+ value: Math.random() * 100,
278
+ category: ['A', 'B', 'C'][i % 3]
279
+ }));
280
+ }
281
+ return lines.join('\n');
282
+ };
283
+
284
+ const largeNdjson = generateLargeNdjson(10000);
285
+ console.log(`Generated ${largeNdjson.split('\n').length} NDJSON lines`);
286
+
287
+ // Process with aggregation
288
+ const stats = {
289
+ count: 0,
290
+ sum: 0,
291
+ categories: {} as Record<string, number>
292
+ };
293
+
294
+ const startTime = Date.now();
295
+
296
+ // Используем ndjsonToJson вместо parseNdjsonStream для простоты
297
+ const parsed = ndjsonToJson(largeNdjson);
298
+ for (const obj of parsed) {
299
+ stats.count++;
300
+ stats.sum += obj.value;
301
+ stats.categories[obj.category] = (stats.categories[obj.category] || 0) + 1;
302
+ }
303
+
304
+ const endTime = Date.now();
305
+
306
+ console.log('\nAggregation results:');
307
+ console.log(' Records processed:', stats.count);
308
+ console.log(' Average value:', (stats.sum / stats.count).toFixed(2));
309
+ console.log(' Categories:', stats.categories);
310
+ console.log(' Processing time:', endTime - startTime, 'ms');
311
+ console.log(' Throughput:', Math.round(stats.count / ((endTime - startTime) / 1000)), 'records/sec');
312
+ }
313
+
314
+ // =============================================================================
315
+ // Example 9: NDJSON Log Processing Pipeline
316
+ // =============================================================================
317
+
318
+ async function logProcessingPipeline() {
319
+ console.log('\n=== NDJSON Log Processing Pipeline ===\n');
320
+
321
+ // Simulated log entries
322
+ const logs = `{"ts": "2024-01-15T10:00:00Z", "level": "info", "service": "api", "msg": "Request received", "duration_ms": 50}
323
+ {"ts": "2024-01-15T10:00:01Z", "level": "debug", "service": "api", "msg": "Processing request", "duration_ms": 0}
324
+ {"ts": "2024-01-15T10:00:02Z", "level": "warn", "service": "db", "msg": "Slow query detected", "duration_ms": 1500}
325
+ {"ts": "2024-01-15T10:00:03Z", "level": "error", "service": "api", "msg": "Request failed", "duration_ms": 100, "error": "Timeout"}
326
+ {"ts": "2024-01-15T10:00:04Z", "level": "info", "service": "api", "msg": "Request completed", "duration_ms": 45}
327
+ {"ts": "2024-01-15T10:00:05Z", "level": "error", "service": "db", "msg": "Connection lost", "duration_ms": 0, "error": "Network error"}`;
328
+
329
+ // Pipeline stages
330
+ const pipeline = {
331
+ errors: [] as Array<{time: string, service: string, message: string, error?: string}>,
332
+ warnings: [] as Array<{time: string, service: string, message: string}>,
333
+ slowRequests: [] as Array<{time: string, service: string, duration: number}>,
334
+ serviceStats: {} as Record<string, {count: number, errors: number}>
335
+ };
336
+
337
+ // Process logs
338
+ const parsedLogs = ndjsonToJson(logs);
339
+ for (const log of parsedLogs) {
340
+ // Collect errors
341
+ if (log.level === 'error') {
342
+ pipeline.errors.push({
343
+ time: log.ts,
344
+ service: log.service,
345
+ message: log.msg,
346
+ error: log.error
347
+ });
348
+ }
349
+
350
+ // Collect warnings
351
+ if (log.level === 'warn') {
352
+ pipeline.warnings.push({
353
+ time: log.ts,
354
+ service: log.service,
355
+ message: log.msg
356
+ });
357
+ }
358
+
359
+ // Track slow requests (> 1000ms)
360
+ if (log.duration_ms > 1000) {
361
+ pipeline.slowRequests.push({
362
+ time: log.ts,
363
+ service: log.service,
364
+ duration: log.duration_ms
365
+ });
366
+ }
367
+
368
+ // Aggregate by service
369
+ if (!pipeline.serviceStats[log.service]) {
370
+ pipeline.serviceStats[log.service] = { count: 0, errors: 0 };
371
+ }
372
+ pipeline.serviceStats[log.service].count++;
373
+ if (log.level === 'error') {
374
+ pipeline.serviceStats[log.service].errors++;
375
+ }
376
+ }
377
+
378
+ // Report
379
+ console.log('Log Analysis Report:');
380
+ console.log('\nErrors:', pipeline.errors.length);
381
+ pipeline.errors.forEach(e => {
382
+ console.log(` [${e.service}] ${e.message} - ${e.error}`);
383
+ });
384
+
385
+ console.log('\nWarnings:', pipeline.warnings.length);
386
+ pipeline.warnings.forEach(w => {
387
+ console.log(` [${w.service}] ${w.message}`);
388
+ });
389
+
390
+ console.log('\nSlow Requests (>1s):', pipeline.slowRequests.length);
391
+ pipeline.slowRequests.forEach(s => {
392
+ console.log(` [${s.service}] ${s.duration}ms`);
393
+ });
394
+
395
+ console.log('\nService Statistics:');
396
+ Object.entries(pipeline.serviceStats).forEach(([service, stats]) => {
397
+ const errorRate = ((stats.errors / stats.count) * 100).toFixed(1);
398
+ console.log(` ${service}: ${stats.count} requests, ${stats.errors} errors (${errorRate}%)`);
399
+ });
400
+ }
401
+
402
+ // =============================================================================
403
+ // Example 10: NDJSON Pretty Print and Compact
404
+ // =============================================================================
405
+
406
+ function ndjsonFormatting() {
407
+ console.log('\n=== NDJSON Formatting Options ===\n');
408
+
409
+ const data = [
410
+ { name: 'Test', nested: { a: 1, b: 2 }, array: [1, 2, 3] }
411
+ ];
412
+
413
+ // Compact (default)
414
+ const compact = jsonToNdjson(data);
415
+ console.log('Compact:');
416
+ console.log(compact);
417
+
418
+ // With custom replacer (filter out 'array' field)
419
+ const filtered = jsonToNdjson(data, {
420
+ replacer: (key: string, value: any) => key === 'array' ? undefined : value
421
+ });
422
+ console.log('\nFiltered (no array):');
423
+ console.log(filtered);
424
+
425
+ // With space for readability (not standard NDJSON but useful for debugging)
426
+ const pretty = jsonToNdjson(data, {
427
+ space: 0 // Standard NDJSON should have no space
428
+ });
429
+ console.log('\nStandard NDJSON:');
430
+ console.log(pretty);
431
+ }
432
+
433
+ // =============================================================================
434
+ // Run All Examples
435
+ // =============================================================================
436
+
437
+ async function main() {
438
+ console.log('jtcsv NDJSON Processing Examples');
439
+ console.log('='.repeat(60));
440
+
441
+ basicNdjsonConversion();
442
+ ndjsonWithTransformAndFilter();
443
+ ndjsonErrorHandling();
444
+ await streamingNdjsonProcessing();
445
+ await ndjsonToCsvConversion();
446
+ csvToNdjsonConversion();
447
+ await ndjsonStatistics();
448
+ await largeNdjsonProcessing();
449
+ await logProcessingPipeline();
450
+ ndjsonFormatting();
451
+
452
+ console.log('\n' + '='.repeat(60));
453
+ console.log('All NDJSON examples completed.');
454
+ }
455
+
456
+ main().catch(console.error);