convert-buddy-js 0.9.2 → 0.9.5
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.
- package/README.md +142 -5
- package/dist/src/browser.d.ts +74 -0
- package/dist/src/browser.js +140 -0
- package/dist/src/browser.js.map +1 -0
- package/dist/src/index.d.ts +23 -2
- package/dist/src/index.js +82 -8
- package/dist/src/index.js.map +1 -1
- package/dist/src/node.d.ts +83 -2
- package/dist/src/node.js +270 -2
- package/dist/src/node.js.map +1 -1
- package/dist/tests/edge-cases/control-features.test.d.ts +2 -0
- package/dist/tests/edge-cases/control-features.test.js +87 -0
- package/dist/tests/edge-cases/control-features.test.js.map +1 -0
- package/dist/tests/edge-cases/csv-edge-cases.test.d.ts +2 -0
- package/dist/tests/edge-cases/csv-edge-cases.test.js +547 -0
- package/dist/tests/edge-cases/csv-edge-cases.test.js.map +1 -0
- package/dist/tests/edge-cases/detection.test.d.ts +2 -0
- package/dist/tests/edge-cases/detection.test.js +129 -0
- package/dist/tests/edge-cases/detection.test.js.map +1 -0
- package/dist/tests/edge-cases/error-handling.test.d.ts +2 -0
- package/dist/tests/edge-cases/error-handling.test.js +448 -0
- package/dist/tests/edge-cases/error-handling.test.js.map +1 -0
- package/dist/tests/edge-cases/ndjson-edge-cases.test.d.ts +2 -0
- package/dist/tests/edge-cases/ndjson-edge-cases.test.js +539 -0
- package/dist/tests/edge-cases/ndjson-edge-cases.test.js.map +1 -0
- package/dist/tests/edge-cases/node-helpers.test.d.ts +2 -0
- package/dist/tests/edge-cases/node-helpers.test.js +114 -0
- package/dist/tests/edge-cases/node-helpers.test.js.map +1 -0
- package/dist/wasm/nodejs/convert_buddy_bg.wasm +0 -0
- package/dist/wasm/web/convert_buddy_bg.wasm +0 -0
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -2,15 +2,152 @@
|
|
|
2
2
|
|
|
3
3
|
A high-performance, streaming-first parser and converter for CSV, XML, NDJSON, and JSON. `convert-buddy-js` is a TypeScript wrapper around a Rust/WASM core, offering fast parsing and multiple usage styles for Node.js and browsers.
|
|
4
4
|
|
|
5
|
+
## Status & Quality
|
|
6
|
+
|
|
7
|
+
[](https://snyk.io/test/github/brunohanss/convert-buddy)
|
|
8
|
+
[](https://github.com/brunohanss/convert-buddy/actions)
|
|
9
|
+
[](https://codecov.io/gh/brunohanss/convert-buddy)
|
|
10
|
+
[](https://www.npmjs.com/package/convert-buddy-js)
|
|
11
|
+
[](https://bundlephobia.com/package/convert-buddy-js)
|
|
12
|
+
|
|
5
13
|
## Install
|
|
6
14
|
|
|
7
15
|
```bash
|
|
8
16
|
npm install convert-buddy-js
|
|
9
17
|
```
|
|
10
18
|
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
### Browser - Convert File Input
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
import { convertFileToString } from "convert-buddy-js/browser";
|
|
25
|
+
|
|
26
|
+
const fileInput = document.querySelector('input[type="file"]');
|
|
27
|
+
fileInput.addEventListener('change', async (e) => {
|
|
28
|
+
const file = e.target.files[0];
|
|
29
|
+
const result = await convertFileToString(file, {
|
|
30
|
+
inputFormat: "auto",
|
|
31
|
+
outputFormat: "json"
|
|
32
|
+
});
|
|
33
|
+
console.log(result);
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Node.js - Convert File
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { convertFileToString } from "convert-buddy-js/node";
|
|
41
|
+
|
|
42
|
+
const result = await convertFileToString("input.csv", {
|
|
43
|
+
inputFormat: "auto",
|
|
44
|
+
outputFormat: "json"
|
|
45
|
+
});
|
|
46
|
+
console.log(result);
|
|
47
|
+
```
|
|
48
|
+
|
|
11
49
|
## Usage
|
|
12
50
|
|
|
13
|
-
###
|
|
51
|
+
### High-Level API (Recommended)
|
|
52
|
+
|
|
53
|
+
#### Browser Helpers
|
|
54
|
+
|
|
55
|
+
Simple file conversion without manual buffer handling:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import {
|
|
59
|
+
convertFileToString,
|
|
60
|
+
convertFile,
|
|
61
|
+
convertFileToFile,
|
|
62
|
+
convertFileStream
|
|
63
|
+
} from "convert-buddy-js/browser";
|
|
64
|
+
|
|
65
|
+
// Convert to string
|
|
66
|
+
const json = await convertFileToString(file, {
|
|
67
|
+
inputFormat: "csv",
|
|
68
|
+
outputFormat: "json"
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// Convert and download
|
|
72
|
+
await convertFileToFile(file, "output.json", {
|
|
73
|
+
inputFormat: "csv",
|
|
74
|
+
outputFormat: "json"
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Get streaming API
|
|
78
|
+
const stream = await convertFileStream(file, {
|
|
79
|
+
inputFormat: "csv",
|
|
80
|
+
outputFormat: "ndjson"
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### Node.js Helpers
|
|
85
|
+
|
|
86
|
+
Convenient file path and stream conversions:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import {
|
|
90
|
+
convertFileToString,
|
|
91
|
+
convertFileToFile,
|
|
92
|
+
convertBuffer,
|
|
93
|
+
convertStream
|
|
94
|
+
} from "convert-buddy-js/node";
|
|
95
|
+
|
|
96
|
+
// File to string
|
|
97
|
+
const json = await convertFileToString("input.csv", {
|
|
98
|
+
inputFormat: "csv",
|
|
99
|
+
outputFormat: "json"
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// File to file
|
|
103
|
+
await convertFileToFile("input.csv", "output.json", {
|
|
104
|
+
inputFormat: "csv",
|
|
105
|
+
outputFormat: "json"
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// From stream (HTTP, stdin, etc.)
|
|
109
|
+
const result = await convertStream(inputStream, {
|
|
110
|
+
inputFormat: "auto",
|
|
111
|
+
outputFormat: "json"
|
|
112
|
+
});
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
#### Progress Tracking & Control
|
|
116
|
+
|
|
117
|
+
Monitor long-running conversions and allow cancellation:
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
const buddy = await ConvertBuddy.create({
|
|
121
|
+
inputFormat: "csv",
|
|
122
|
+
outputFormat: "json",
|
|
123
|
+
onProgress: (stats) => {
|
|
124
|
+
console.log(`${stats.recordsProcessed} records processed`);
|
|
125
|
+
console.log(`${stats.throughputMbPerSec.toFixed(2)} MB/s`);
|
|
126
|
+
},
|
|
127
|
+
progressIntervalBytes: 1024 * 1024 // Every 1MB
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// User cancels
|
|
131
|
+
cancelButton.addEventListener('click', () => buddy.abort());
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
#### Auto-Detection
|
|
135
|
+
|
|
136
|
+
Let the library detect format automatically:
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
const result = await convertFileToString(file, {
|
|
140
|
+
inputFormat: "auto", // Auto-detect CSV, JSON, NDJSON, XML
|
|
141
|
+
outputFormat: "json",
|
|
142
|
+
csvConfig: { // Optional: still apply config
|
|
143
|
+
delimiter: ","
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Low-Level API
|
|
149
|
+
|
|
150
|
+
#### Convert a full string or buffer
|
|
14
151
|
|
|
15
152
|
```ts
|
|
16
153
|
import { convertToString } from "convert-buddy-js";
|
|
@@ -25,7 +162,7 @@ const output = await convertToString(csv, {
|
|
|
25
162
|
console.log(output);
|
|
26
163
|
```
|
|
27
164
|
|
|
28
|
-
|
|
165
|
+
#### Manual streaming (chunked)
|
|
29
166
|
|
|
30
167
|
```ts
|
|
31
168
|
import { ConvertBuddy } from "convert-buddy-js";
|
|
@@ -42,7 +179,7 @@ const finalOutput = buddy.finish();
|
|
|
42
179
|
console.log(buddy.stats());
|
|
43
180
|
```
|
|
44
181
|
|
|
45
|
-
|
|
182
|
+
#### Node.js Transform stream
|
|
46
183
|
|
|
47
184
|
Use the Node-specific entrypoint so bundlers keep `node:stream` out of the browser bundle.
|
|
48
185
|
|
|
@@ -62,7 +199,7 @@ createReadStream("input.csv")
|
|
|
62
199
|
.pipe(createWriteStream("output.ndjson"));
|
|
63
200
|
```
|
|
64
201
|
|
|
65
|
-
|
|
202
|
+
#### Web Streams
|
|
66
203
|
|
|
67
204
|
```ts
|
|
68
205
|
import { ConvertBuddyTransformStream } from "convert-buddy-js";
|
|
@@ -76,7 +213,7 @@ const response = await fetch("/data.csv");
|
|
|
76
213
|
const outputStream = response.body?.pipeThrough(transform);
|
|
77
214
|
```
|
|
78
215
|
|
|
79
|
-
|
|
216
|
+
#### Detect format and CSV fields/delimiter
|
|
80
217
|
|
|
81
218
|
Use streaming inputs to keep detection fast on large files.
|
|
82
219
|
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ConvertBuddyOptions } from './index.js';
|
|
2
|
+
export { ConvertBuddy, ConvertBuddyTransformStream, CsvConfig, CsvDetection, DetectInput, DetectOptions, Format, ProgressCallback, Stats, XmlConfig, XmlDetection, autoDetectConfig, convert, convertToString, detectCsvFieldsAndDelimiter, detectFormat, detectXmlElements } from './index.js';
|
|
3
|
+
|
|
4
|
+
type BrowserConvertOptions = ConvertBuddyOptions & {};
|
|
5
|
+
/**
|
|
6
|
+
* Convert a browser File or Blob object to a string.
|
|
7
|
+
* Handles streaming internally using FileReader and web streams.
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* // From file input
|
|
11
|
+
* const fileInput = document.querySelector('input[type="file"]');
|
|
12
|
+
* const file = fileInput.files[0];
|
|
13
|
+
* const result = await convertFileToString(file, {
|
|
14
|
+
* inputFormat: "csv",
|
|
15
|
+
* outputFormat: "json"
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // With auto-detection
|
|
20
|
+
* const result = await convertFileToString(file, {
|
|
21
|
+
* inputFormat: "auto",
|
|
22
|
+
* outputFormat: "ndjson"
|
|
23
|
+
* });
|
|
24
|
+
*/
|
|
25
|
+
declare function convertFileToString(file: File | Blob, opts?: BrowserConvertOptions): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Convert a browser File or Blob object to a Uint8Array.
|
|
28
|
+
* Handles streaming internally using FileReader and web streams.
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* const file = fileInput.files[0];
|
|
32
|
+
* const result = await convertFile(file, {
|
|
33
|
+
* inputFormat: "csv",
|
|
34
|
+
* outputFormat: "json",
|
|
35
|
+
* onProgress: (stats) => {
|
|
36
|
+
* console.log(`Progress: ${stats.bytesIn} bytes processed`);
|
|
37
|
+
* }
|
|
38
|
+
* });
|
|
39
|
+
*/
|
|
40
|
+
declare function convertFile(file: File | Blob, opts?: BrowserConvertOptions): Promise<Uint8Array>;
|
|
41
|
+
/**
|
|
42
|
+
* Convert a browser File or Blob and download the result as a file.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* const fileInput = document.querySelector('input[type="file"]');
|
|
46
|
+
* const file = fileInput.files[0];
|
|
47
|
+
* await convertFileToFile(file, "output.json", {
|
|
48
|
+
* inputFormat: "csv",
|
|
49
|
+
* outputFormat: "json"
|
|
50
|
+
* });
|
|
51
|
+
*/
|
|
52
|
+
declare function convertFileToFile(inputFile: File | Blob, outputFilename: string, opts?: BrowserConvertOptions): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Create a ReadableStream that converts data on-the-fly from a File or Blob.
|
|
55
|
+
* Useful for piping through other stream processors.
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* const file = fileInput.files[0];
|
|
59
|
+
* const stream = convertFileStream(file, {
|
|
60
|
+
* inputFormat: "csv",
|
|
61
|
+
* outputFormat: "ndjson"
|
|
62
|
+
* });
|
|
63
|
+
*
|
|
64
|
+
* const reader = stream.getReader();
|
|
65
|
+
* while (true) {
|
|
66
|
+
* const { done, value } = await reader.read();
|
|
67
|
+
* if (done) break;
|
|
68
|
+
* // Process each chunk as it's converted
|
|
69
|
+
* console.log(new TextDecoder().decode(value));
|
|
70
|
+
* }
|
|
71
|
+
*/
|
|
72
|
+
declare function convertFileStream(file: File | Blob, opts?: BrowserConvertOptions): Promise<ReadableStream<Uint8Array>>;
|
|
73
|
+
|
|
74
|
+
export { type BrowserConvertOptions, ConvertBuddyOptions, convertFile, convertFileStream, convertFileToFile, convertFileToString };
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { ConvertBuddy, autoDetectConfig } from "./index.js";
|
|
2
|
+
export * from "./index.js";
|
|
3
|
+
async function convertFileToString(file, opts = {}) {
|
|
4
|
+
const bytes = await convertFile(file, opts);
|
|
5
|
+
return new TextDecoder().decode(bytes);
|
|
6
|
+
}
|
|
7
|
+
async function convertFile(file, opts = {}) {
|
|
8
|
+
let actualOpts = { ...opts };
|
|
9
|
+
if (opts.inputFormat === "auto") {
|
|
10
|
+
const sampleSize = 256 * 1024;
|
|
11
|
+
const sampleBlob = file.slice(0, sampleSize);
|
|
12
|
+
const sampleBuffer = await sampleBlob.arrayBuffer();
|
|
13
|
+
const sample = new Uint8Array(sampleBuffer);
|
|
14
|
+
const detected = await autoDetectConfig(sample, { debug: opts.debug });
|
|
15
|
+
if (detected.format !== "unknown") {
|
|
16
|
+
actualOpts.inputFormat = detected.format;
|
|
17
|
+
if (detected.csvConfig) {
|
|
18
|
+
actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;
|
|
19
|
+
}
|
|
20
|
+
if (detected.xmlConfig) {
|
|
21
|
+
actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;
|
|
22
|
+
}
|
|
23
|
+
if (opts.debug) {
|
|
24
|
+
console.log("[convert-buddy] Auto-detected format:", detected.format);
|
|
25
|
+
}
|
|
26
|
+
} else {
|
|
27
|
+
throw new Error("Could not auto-detect input format. Please specify inputFormat explicitly.");
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
const buddy = await ConvertBuddy.create(actualOpts);
|
|
31
|
+
const stream = file.stream();
|
|
32
|
+
const reader = stream.getReader();
|
|
33
|
+
const chunks = [];
|
|
34
|
+
try {
|
|
35
|
+
while (true) {
|
|
36
|
+
const { done, value } = await reader.read();
|
|
37
|
+
if (done) break;
|
|
38
|
+
if (buddy.isAborted()) {
|
|
39
|
+
throw new Error("Conversion aborted");
|
|
40
|
+
}
|
|
41
|
+
const output = buddy.push(value);
|
|
42
|
+
if (output.length > 0) {
|
|
43
|
+
chunks.push(output);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const final = buddy.finish();
|
|
47
|
+
if (final.length > 0) {
|
|
48
|
+
chunks.push(final);
|
|
49
|
+
}
|
|
50
|
+
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
51
|
+
const result = new Uint8Array(totalLength);
|
|
52
|
+
let offset = 0;
|
|
53
|
+
for (const chunk of chunks) {
|
|
54
|
+
result.set(chunk, offset);
|
|
55
|
+
offset += chunk.length;
|
|
56
|
+
}
|
|
57
|
+
if (opts.profile) {
|
|
58
|
+
console.log("[convert-buddy] Performance Stats:", buddy.stats());
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
reader.releaseLock();
|
|
63
|
+
throw error;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function convertFileToFile(inputFile, outputFilename, opts = {}) {
|
|
67
|
+
const result = await convertFile(inputFile, opts);
|
|
68
|
+
const blob = new Blob([new Uint8Array(result)], { type: "application/octet-stream" });
|
|
69
|
+
const url = URL.createObjectURL(blob);
|
|
70
|
+
const link = document.createElement("a");
|
|
71
|
+
link.href = url;
|
|
72
|
+
link.download = outputFilename;
|
|
73
|
+
link.style.display = "none";
|
|
74
|
+
document.body.appendChild(link);
|
|
75
|
+
link.click();
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
document.body.removeChild(link);
|
|
78
|
+
URL.revokeObjectURL(url);
|
|
79
|
+
}, 100);
|
|
80
|
+
}
|
|
81
|
+
async function convertFileStream(file, opts = {}) {
|
|
82
|
+
let actualOpts = { ...opts };
|
|
83
|
+
if (opts.inputFormat === "auto") {
|
|
84
|
+
const sampleSize = 256 * 1024;
|
|
85
|
+
const sampleBlob = file.slice(0, sampleSize);
|
|
86
|
+
const sampleBuffer = await sampleBlob.arrayBuffer();
|
|
87
|
+
const sample = new Uint8Array(sampleBuffer);
|
|
88
|
+
const detected = await autoDetectConfig(sample, { debug: opts.debug });
|
|
89
|
+
if (detected.format !== "unknown") {
|
|
90
|
+
actualOpts.inputFormat = detected.format;
|
|
91
|
+
if (detected.csvConfig) {
|
|
92
|
+
actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;
|
|
93
|
+
}
|
|
94
|
+
if (detected.xmlConfig) {
|
|
95
|
+
actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
throw new Error("Could not auto-detect input format.");
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const buddy = await ConvertBuddy.create(actualOpts);
|
|
102
|
+
const inputStream = file.stream();
|
|
103
|
+
return new ReadableStream({
|
|
104
|
+
async start(controller) {
|
|
105
|
+
const reader = inputStream.getReader();
|
|
106
|
+
try {
|
|
107
|
+
while (true) {
|
|
108
|
+
const { done, value } = await reader.read();
|
|
109
|
+
if (done) {
|
|
110
|
+
const final = buddy.finish();
|
|
111
|
+
if (final.length > 0) {
|
|
112
|
+
controller.enqueue(final);
|
|
113
|
+
}
|
|
114
|
+
controller.close();
|
|
115
|
+
break;
|
|
116
|
+
}
|
|
117
|
+
if (buddy.isAborted()) {
|
|
118
|
+
controller.error(new Error("Conversion aborted"));
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
const output = buddy.push(value);
|
|
122
|
+
if (output.length > 0) {
|
|
123
|
+
controller.enqueue(output);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
controller.error(error);
|
|
128
|
+
} finally {
|
|
129
|
+
reader.releaseLock();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
convertFile,
|
|
136
|
+
convertFileStream,
|
|
137
|
+
convertFileToFile,
|
|
138
|
+
convertFileToString
|
|
139
|
+
};
|
|
140
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/browser.ts"],"sourcesContent":["import { ConvertBuddy, type ConvertBuddyOptions, type Format, autoDetectConfig } from \"./index.js\";\r\n\r\nexport * from \"./index.js\";\r\n\r\nexport type BrowserConvertOptions = ConvertBuddyOptions & {\r\n // Additional browser-specific options can go here\r\n};\r\n\r\n/**\r\n * Convert a browser File or Blob object to a string.\r\n * Handles streaming internally using FileReader and web streams.\r\n * \r\n * @example\r\n * // From file input\r\n * const fileInput = document.querySelector('input[type=\"file\"]');\r\n * const file = fileInput.files[0];\r\n * const result = await convertFileToString(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\"\r\n * });\r\n * \r\n * @example\r\n * // With auto-detection\r\n * const result = await convertFileToString(file, {\r\n * inputFormat: \"auto\",\r\n * outputFormat: \"ndjson\"\r\n * });\r\n */\r\nexport async function convertFileToString(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<string> {\r\n const bytes = await convertFile(file, opts);\r\n return new TextDecoder().decode(bytes);\r\n}\r\n\r\n/**\r\n * Convert a browser File or Blob object to a Uint8Array.\r\n * Handles streaming internally using FileReader and web streams.\r\n * \r\n * @example\r\n * const file = fileInput.files[0];\r\n * const result = await convertFile(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\",\r\n * onProgress: (stats) => {\r\n * console.log(`Progress: ${stats.bytesIn} bytes processed`);\r\n * }\r\n * });\r\n */\r\nexport async function convertFile(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<Uint8Array> {\r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n // Read a sample for auto-detection\r\n const sampleSize = 256 * 1024; // 256KB\r\n const sampleBlob = file.slice(0, sampleSize);\r\n const sampleBuffer = await sampleBlob.arrayBuffer();\r\n const sample = new Uint8Array(sampleBuffer);\r\n \r\n const detected = await autoDetectConfig(sample, { debug: opts.debug });\r\n \r\n if (detected.format !== \"unknown\") {\r\n actualOpts.inputFormat = detected.format as Format;\r\n \r\n if (detected.csvConfig) {\r\n actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;\r\n }\r\n \r\n if (detected.xmlConfig) {\r\n actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;\r\n }\r\n \r\n if (opts.debug) {\r\n console.log(\"[convert-buddy] Auto-detected format:\", detected.format);\r\n }\r\n } else {\r\n throw new Error(\"Could not auto-detect input format. Please specify inputFormat explicitly.\");\r\n }\r\n }\r\n \r\n const buddy = await ConvertBuddy.create(actualOpts);\r\n \r\n // Use streams API for efficient processing\r\n const stream = file.stream();\r\n const reader = stream.getReader();\r\n \r\n const chunks: Uint8Array[] = [];\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n \r\n if (done) break;\r\n \r\n if (buddy.isAborted()) {\r\n throw new Error(\"Conversion aborted\");\r\n }\r\n \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n chunks.push(output);\r\n }\r\n }\r\n \r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n chunks.push(final);\r\n }\r\n \r\n // Combine all chunks\r\n const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);\r\n const result = new Uint8Array(totalLength);\r\n let offset = 0;\r\n for (const chunk of chunks) {\r\n result.set(chunk, offset);\r\n offset += chunk.length;\r\n }\r\n \r\n if (opts.profile) {\r\n console.log(\"[convert-buddy] Performance Stats:\", buddy.stats());\r\n }\r\n \r\n return result;\r\n } catch (error) {\r\n reader.releaseLock();\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Convert a browser File or Blob and download the result as a file.\r\n * \r\n * @example\r\n * const fileInput = document.querySelector('input[type=\"file\"]');\r\n * const file = fileInput.files[0];\r\n * await convertFileToFile(file, \"output.json\", {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"json\"\r\n * });\r\n */\r\nexport async function convertFileToFile(\r\n inputFile: File | Blob,\r\n outputFilename: string,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<void> {\r\n const result = await convertFile(inputFile, opts);\r\n \r\n // Create a download link\r\n const blob = new Blob([new Uint8Array(result)], { type: \"application/octet-stream\" });\r\n const url = URL.createObjectURL(blob);\r\n \r\n const link = document.createElement(\"a\");\r\n link.href = url;\r\n link.download = outputFilename;\r\n link.style.display = \"none\";\r\n \r\n document.body.appendChild(link);\r\n link.click();\r\n \r\n // Cleanup\r\n setTimeout(() => {\r\n document.body.removeChild(link);\r\n URL.revokeObjectURL(url);\r\n }, 100);\r\n}\r\n\r\n/**\r\n * Create a ReadableStream that converts data on-the-fly from a File or Blob.\r\n * Useful for piping through other stream processors.\r\n * \r\n * @example\r\n * const file = fileInput.files[0];\r\n * const stream = convertFileStream(file, {\r\n * inputFormat: \"csv\",\r\n * outputFormat: \"ndjson\"\r\n * });\r\n * \r\n * const reader = stream.getReader();\r\n * while (true) {\r\n * const { done, value } = await reader.read();\r\n * if (done) break;\r\n * // Process each chunk as it's converted\r\n * console.log(new TextDecoder().decode(value));\r\n * }\r\n */\r\nexport async function convertFileStream(\r\n file: File | Blob,\r\n opts: BrowserConvertOptions = {}\r\n): Promise<ReadableStream<Uint8Array>> {\r\n // Handle auto-detection\r\n let actualOpts = { ...opts };\r\n \r\n if (opts.inputFormat === \"auto\") {\r\n const sampleSize = 256 * 1024;\r\n const sampleBlob = file.slice(0, sampleSize);\r\n const sampleBuffer = await sampleBlob.arrayBuffer();\r\n const sample = new Uint8Array(sampleBuffer);\r\n \r\n const detected = await autoDetectConfig(sample, { debug: opts.debug });\r\n \r\n if (detected.format !== \"unknown\") {\r\n actualOpts.inputFormat = detected.format as Format;\r\n if (detected.csvConfig) {\r\n actualOpts.csvConfig = opts.csvConfig ? { ...detected.csvConfig, ...opts.csvConfig } : detected.csvConfig;\r\n }\r\n if (detected.xmlConfig) {\r\n actualOpts.xmlConfig = opts.xmlConfig ? { ...detected.xmlConfig, ...opts.xmlConfig } : detected.xmlConfig;\r\n }\r\n } else {\r\n throw new Error(\"Could not auto-detect input format.\");\r\n }\r\n }\r\n \r\n const buddy = await ConvertBuddy.create(actualOpts);\r\n const inputStream = file.stream();\r\n \r\n return new ReadableStream<Uint8Array>({\r\n async start(controller) {\r\n const reader = inputStream.getReader();\r\n \r\n try {\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n \r\n if (done) {\r\n const final = buddy.finish();\r\n if (final.length > 0) {\r\n controller.enqueue(final);\r\n }\r\n controller.close();\r\n break;\r\n }\r\n \r\n if (buddy.isAborted()) {\r\n controller.error(new Error(\"Conversion aborted\"));\r\n break;\r\n }\r\n \r\n const output = buddy.push(value);\r\n if (output.length > 0) {\r\n controller.enqueue(output);\r\n }\r\n }\r\n } catch (error) {\r\n controller.error(error);\r\n } finally {\r\n reader.releaseLock();\r\n }\r\n },\r\n });\r\n}\r\n"],"mappings":"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","names":[]}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -6,20 +6,24 @@ type CsvDetection = {
|
|
|
6
6
|
};
|
|
7
7
|
type XmlDetection = {
|
|
8
8
|
elements: string[];
|
|
9
|
+
recordElement?: string;
|
|
9
10
|
};
|
|
10
11
|
type DetectOptions = {
|
|
11
12
|
maxBytes?: number;
|
|
12
13
|
debug?: boolean;
|
|
13
14
|
};
|
|
15
|
+
type ProgressCallback = (stats: Stats) => void;
|
|
14
16
|
type ConvertBuddyOptions = {
|
|
15
17
|
debug?: boolean;
|
|
16
18
|
profile?: boolean;
|
|
17
|
-
inputFormat?: Format;
|
|
19
|
+
inputFormat?: Format | "auto";
|
|
18
20
|
outputFormat?: Format;
|
|
19
21
|
chunkTargetBytes?: number;
|
|
20
22
|
parallelism?: number;
|
|
21
23
|
csvConfig?: CsvConfig;
|
|
22
24
|
xmlConfig?: XmlConfig;
|
|
25
|
+
onProgress?: ProgressCallback;
|
|
26
|
+
progressIntervalBytes?: number;
|
|
23
27
|
};
|
|
24
28
|
type CsvConfig = {
|
|
25
29
|
delimiter?: string;
|
|
@@ -49,19 +53,36 @@ declare class ConvertBuddy {
|
|
|
49
53
|
private converter;
|
|
50
54
|
private debug;
|
|
51
55
|
private profile;
|
|
56
|
+
private aborted;
|
|
57
|
+
private paused;
|
|
58
|
+
private onProgress?;
|
|
59
|
+
private progressIntervalBytes;
|
|
60
|
+
private lastProgressBytes;
|
|
52
61
|
private constructor();
|
|
53
62
|
static create(opts?: ConvertBuddyOptions): Promise<ConvertBuddy>;
|
|
54
63
|
push(chunk: Uint8Array): Uint8Array;
|
|
55
64
|
finish(): Uint8Array;
|
|
56
65
|
stats(): Stats;
|
|
66
|
+
abort(): void;
|
|
67
|
+
pause(): void;
|
|
68
|
+
resume(): void;
|
|
69
|
+
isAborted(): boolean;
|
|
70
|
+
isPaused(): boolean;
|
|
57
71
|
}
|
|
58
72
|
declare function detectFormat(input: DetectInput, opts?: DetectOptions): Promise<Format | "unknown">;
|
|
59
73
|
declare function detectCsvFieldsAndDelimiter(input: DetectInput, opts?: DetectOptions): Promise<CsvDetection | null>;
|
|
60
74
|
declare function detectXmlElements(input: DetectInput, opts?: DetectOptions): Promise<XmlDetection | null>;
|
|
75
|
+
declare function autoDetectConfig(sample: Uint8Array, opts?: {
|
|
76
|
+
debug?: boolean;
|
|
77
|
+
}): Promise<{
|
|
78
|
+
format: Format | "unknown";
|
|
79
|
+
csvConfig?: CsvConfig;
|
|
80
|
+
xmlConfig?: XmlConfig;
|
|
81
|
+
}>;
|
|
61
82
|
declare class ConvertBuddyTransformStream extends TransformStream<Uint8Array, Uint8Array> {
|
|
62
83
|
constructor(opts?: ConvertBuddyOptions);
|
|
63
84
|
}
|
|
64
85
|
declare function convert(input: Uint8Array | string, opts?: ConvertBuddyOptions): Promise<Uint8Array>;
|
|
65
86
|
declare function convertToString(input: Uint8Array | string, opts?: ConvertBuddyOptions): Promise<string>;
|
|
66
87
|
|
|
67
|
-
export { ConvertBuddy, type ConvertBuddyOptions, ConvertBuddyTransformStream, type CsvConfig, type CsvDetection, type DetectInput, type DetectOptions, type Format, type Stats, type XmlConfig, type XmlDetection, convert, convertToString, detectCsvFieldsAndDelimiter, detectFormat, detectXmlElements };
|
|
88
|
+
export { ConvertBuddy, type ConvertBuddyOptions, ConvertBuddyTransformStream, type CsvConfig, type CsvDetection, type DetectInput, type DetectOptions, type Format, type ProgressCallback, type Stats, type XmlConfig, type XmlDetection, autoDetectConfig, convert, convertToString, detectCsvFieldsAndDelimiter, detectFormat, detectXmlElements };
|
package/dist/src/index.js
CHANGED
|
@@ -14,10 +14,17 @@ class ConvertBuddy {
|
|
|
14
14
|
converter;
|
|
15
15
|
debug;
|
|
16
16
|
profile;
|
|
17
|
-
|
|
17
|
+
aborted = false;
|
|
18
|
+
paused = false;
|
|
19
|
+
onProgress;
|
|
20
|
+
progressIntervalBytes;
|
|
21
|
+
lastProgressBytes = 0;
|
|
22
|
+
constructor(converter, debug, profile, opts = {}) {
|
|
18
23
|
this.converter = converter;
|
|
19
24
|
this.debug = debug;
|
|
20
25
|
this.profile = profile;
|
|
26
|
+
this.onProgress = opts.onProgress;
|
|
27
|
+
this.progressIntervalBytes = opts.progressIntervalBytes || 1024 * 1024;
|
|
21
28
|
}
|
|
22
29
|
static async create(opts = {}) {
|
|
23
30
|
const debug = !!opts.debug;
|
|
@@ -27,35 +34,79 @@ class ConvertBuddy {
|
|
|
27
34
|
await wasmModule.default();
|
|
28
35
|
}
|
|
29
36
|
wasmModule.init(debug);
|
|
37
|
+
let inputFormat = opts.inputFormat;
|
|
38
|
+
let csvConfig = opts.csvConfig;
|
|
39
|
+
if (inputFormat === "auto") {
|
|
40
|
+
inputFormat = void 0;
|
|
41
|
+
}
|
|
30
42
|
let converter;
|
|
31
|
-
if (
|
|
43
|
+
if (inputFormat && opts.outputFormat) {
|
|
32
44
|
const Converter = wasmModule.Converter;
|
|
33
45
|
converter = Converter.withConfig(
|
|
34
46
|
debug,
|
|
35
|
-
|
|
47
|
+
inputFormat,
|
|
36
48
|
opts.outputFormat,
|
|
37
49
|
opts.chunkTargetBytes || 1024 * 1024,
|
|
38
50
|
profile,
|
|
39
|
-
|
|
40
|
-
opts.xmlConfig
|
|
51
|
+
csvConfig || null,
|
|
52
|
+
opts.xmlConfig || null
|
|
41
53
|
);
|
|
42
54
|
} else {
|
|
43
55
|
converter = new wasmModule.Converter(debug);
|
|
44
56
|
}
|
|
45
57
|
if (debug) console.log("[convert-buddy-js] initialized", opts);
|
|
46
|
-
return new ConvertBuddy(converter, debug, profile);
|
|
58
|
+
return new ConvertBuddy(converter, debug, profile, opts);
|
|
47
59
|
}
|
|
48
60
|
push(chunk) {
|
|
61
|
+
if (this.aborted) {
|
|
62
|
+
throw new Error("Conversion has been aborted");
|
|
63
|
+
}
|
|
64
|
+
if (this.paused) {
|
|
65
|
+
throw new Error("Conversion is paused. Call resume() before pushing more data.");
|
|
66
|
+
}
|
|
49
67
|
if (this.debug) console.log("[convert-buddy-js] push", chunk.byteLength);
|
|
50
|
-
|
|
68
|
+
const output = this.converter.push(chunk);
|
|
69
|
+
if (this.onProgress) {
|
|
70
|
+
const stats = this.stats();
|
|
71
|
+
if (stats.bytesIn - this.lastProgressBytes >= this.progressIntervalBytes) {
|
|
72
|
+
this.onProgress(stats);
|
|
73
|
+
this.lastProgressBytes = stats.bytesIn;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return output;
|
|
51
77
|
}
|
|
52
78
|
finish() {
|
|
79
|
+
if (this.aborted) {
|
|
80
|
+
throw new Error("Conversion has been aborted");
|
|
81
|
+
}
|
|
53
82
|
if (this.debug) console.log("[convert-buddy-js] finish");
|
|
54
|
-
|
|
83
|
+
const output = this.converter.finish();
|
|
84
|
+
if (this.onProgress) {
|
|
85
|
+
this.onProgress(this.stats());
|
|
86
|
+
}
|
|
87
|
+
return output;
|
|
55
88
|
}
|
|
56
89
|
stats() {
|
|
57
90
|
return this.converter.getStats();
|
|
58
91
|
}
|
|
92
|
+
abort() {
|
|
93
|
+
this.aborted = true;
|
|
94
|
+
if (this.debug) console.log("[convert-buddy-js] aborted");
|
|
95
|
+
}
|
|
96
|
+
pause() {
|
|
97
|
+
this.paused = true;
|
|
98
|
+
if (this.debug) console.log("[convert-buddy-js] paused");
|
|
99
|
+
}
|
|
100
|
+
resume() {
|
|
101
|
+
this.paused = false;
|
|
102
|
+
if (this.debug) console.log("[convert-buddy-js] resumed");
|
|
103
|
+
}
|
|
104
|
+
isAborted() {
|
|
105
|
+
return this.aborted;
|
|
106
|
+
}
|
|
107
|
+
isPaused() {
|
|
108
|
+
return this.paused;
|
|
109
|
+
}
|
|
59
110
|
}
|
|
60
111
|
async function readSample(input, maxBytes = 256 * 1024) {
|
|
61
112
|
if (typeof input === "string") {
|
|
@@ -136,6 +187,28 @@ async function detectXmlElements(input, opts = {}) {
|
|
|
136
187
|
const result = wasmModule.detectXmlElements?.(sample);
|
|
137
188
|
return result ?? null;
|
|
138
189
|
}
|
|
190
|
+
async function autoDetectConfig(sample, opts = {}) {
|
|
191
|
+
const wasmModule = await loadDetectionWasm(!!opts.debug);
|
|
192
|
+
const format = wasmModule.detectFormat?.(sample) ?? "unknown";
|
|
193
|
+
const result = { format };
|
|
194
|
+
if (format === "csv") {
|
|
195
|
+
const csvDetection = wasmModule.detectCsvFields?.(sample);
|
|
196
|
+
if (csvDetection) {
|
|
197
|
+
result.csvConfig = {
|
|
198
|
+
delimiter: csvDetection.delimiter,
|
|
199
|
+
hasHeaders: csvDetection.fields.length > 0
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
} else if (format === "xml") {
|
|
203
|
+
const xmlDetection = wasmModule.detectXmlElements?.(sample);
|
|
204
|
+
if (xmlDetection?.recordElement) {
|
|
205
|
+
result.xmlConfig = {
|
|
206
|
+
recordElement: xmlDetection.recordElement
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
return result;
|
|
211
|
+
}
|
|
139
212
|
class ConvertBuddyTransformStream extends TransformStream {
|
|
140
213
|
constructor(opts = {}) {
|
|
141
214
|
let buddy = null;
|
|
@@ -189,6 +262,7 @@ async function convertToString(input, opts = {}) {
|
|
|
189
262
|
export {
|
|
190
263
|
ConvertBuddy,
|
|
191
264
|
ConvertBuddyTransformStream,
|
|
265
|
+
autoDetectConfig,
|
|
192
266
|
convert,
|
|
193
267
|
convertToString,
|
|
194
268
|
detectCsvFieldsAndDelimiter,
|