convert-buddy-js 0.4.0 → 0.6.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.
package/README.md CHANGED
@@ -146,11 +146,22 @@ if (csvInfo) {
146
146
  ## How it works
147
147
 
148
148
  - **Rust core** (`crates/convert-buddy`) implements streaming parsers and stats tracking.
149
- - **WASM bindings** are generated via `wasm-bindgen` and bundled into this package.
149
+ - **WASM bindings** are generated via `wasm-bindgen` and bundled into this package as prebuilt binaries.
150
150
  - **TypeScript wrapper** (`src/index.ts`) exposes the `ConvertBuddy` class and stream adapters.
151
151
 
152
+ ## Package contents (what ships)
153
+
154
+ The published npm package includes only the runtime artifacts needed to use Convert Buddy:
155
+
156
+ - Prebuilt WASM binaries (in `wasm/` plus `wasm-node.cjs` for Node.js).
157
+ - Compiled TypeScript output (in `dist/`).
158
+
159
+ The monorepo demo app, Rust sources, and build/benchmark tooling live in this repository but are **not** published with the npm package.
160
+
152
161
  ### Build (repository)
153
162
 
163
+ These steps are **only** for contributors working in this monorepo. If you install `convert-buddy-js` from npm, you do **not** need to run them.
164
+
154
165
  ```bash
155
166
  npm install
156
167
  npm -w convert-buddy-js run build
@@ -0,0 +1,63 @@
1
+ import {
2
+ ConvertBuddy
3
+ } from "./chunk-WBKHAQCT.js";
4
+
5
+ // src/node.ts
6
+ async function loadNodeTransform() {
7
+ const isNode = typeof process !== "undefined" && !!process.versions?.node;
8
+ if (!isNode) {
9
+ throw new Error("createNodeTransform is only available in Node.js runtimes.");
10
+ }
11
+ const streamModule = await import("stream");
12
+ return streamModule.Transform;
13
+ }
14
+ async function createNodeTransform(opts = {}) {
15
+ let buddy = null;
16
+ let initPromise = null;
17
+ const Transform = await loadNodeTransform();
18
+ const transform = new Transform({
19
+ async transform(chunk, encoding, callback) {
20
+ try {
21
+ if (!buddy) {
22
+ if (!initPromise) {
23
+ initPromise = ConvertBuddy.create(opts).then((b) => {
24
+ buddy = b;
25
+ });
26
+ }
27
+ await initPromise;
28
+ }
29
+ const input = new Uint8Array(chunk);
30
+ const output = buddy.push(input);
31
+ if (output.length > 0) {
32
+ this.push(Buffer.from(output));
33
+ }
34
+ callback();
35
+ } catch (err) {
36
+ callback(err);
37
+ }
38
+ },
39
+ async flush(callback) {
40
+ try {
41
+ if (buddy) {
42
+ const output = buddy.finish();
43
+ if (output.length > 0) {
44
+ this.push(Buffer.from(output));
45
+ }
46
+ if (opts.profile) {
47
+ const stats = buddy.stats();
48
+ console.log("[convert-buddy] Performance Stats:", stats);
49
+ }
50
+ }
51
+ callback();
52
+ } catch (err) {
53
+ callback(err);
54
+ }
55
+ }
56
+ });
57
+ return transform;
58
+ }
59
+
60
+ export {
61
+ createNodeTransform
62
+ };
63
+ //# sourceMappingURL=chunk-C3RSVYQF.js.map
@@ -35,7 +35,9 @@ var ConvertBuddy = class _ConvertBuddy {
35
35
  opts.inputFormat,
36
36
  opts.outputFormat,
37
37
  opts.chunkTargetBytes || 1024 * 1024,
38
- profile
38
+ profile,
39
+ opts.csvConfig,
40
+ opts.xmlConfig
39
41
  );
40
42
  } else {
41
43
  converter = new wasmModule.Converter(debug);
@@ -55,58 +57,78 @@ var ConvertBuddy = class _ConvertBuddy {
55
57
  return this.converter.getStats();
56
58
  }
57
59
  };
58
- async function loadNodeTransform() {
59
- const isNode = typeof process !== "undefined" && !!process.versions?.node;
60
- if (!isNode) {
61
- throw new Error("createNodeTransform is only available in Node.js runtimes.");
60
+ async function readSample(input, maxBytes = 256 * 1024) {
61
+ if (typeof input === "string") {
62
+ const encoded = new TextEncoder().encode(input);
63
+ return encoded.length > maxBytes ? encoded.slice(0, maxBytes) : encoded;
62
64
  }
63
- const streamModule = await import("stream");
64
- return streamModule.Transform;
65
- }
66
- async function createNodeTransform(opts = {}) {
67
- let buddy = null;
68
- let initPromise = null;
69
- const Transform = await loadNodeTransform();
70
- const transform = new Transform({
71
- async transform(chunk, encoding, callback) {
72
- try {
73
- if (!buddy) {
74
- if (!initPromise) {
75
- initPromise = ConvertBuddy.create(opts).then((b) => {
76
- buddy = b;
77
- });
78
- }
79
- await initPromise;
80
- }
81
- const input = new Uint8Array(chunk);
82
- const output = buddy.push(input);
83
- if (output.length > 0) {
84
- this.push(Buffer.from(output));
85
- }
86
- callback();
87
- } catch (err) {
88
- callback(err);
89
- }
90
- },
91
- async flush(callback) {
92
- try {
93
- if (buddy) {
94
- const output = buddy.finish();
95
- if (output.length > 0) {
96
- this.push(Buffer.from(output));
97
- }
98
- if (opts.profile) {
99
- const stats = buddy.stats();
100
- console.log("[convert-buddy] Performance Stats:", stats);
101
- }
102
- }
103
- callback();
104
- } catch (err) {
105
- callback(err);
106
- }
65
+ if (input instanceof Uint8Array) {
66
+ return input.length > maxBytes ? input.slice(0, maxBytes) : input;
67
+ }
68
+ if (input instanceof ArrayBuffer) {
69
+ const bytes = new Uint8Array(input);
70
+ return bytes.length > maxBytes ? bytes.slice(0, maxBytes) : bytes;
71
+ }
72
+ if (isReadableStream(input)) {
73
+ const reader = input.getReader();
74
+ const chunks2 = [];
75
+ let total2 = 0;
76
+ while (total2 < maxBytes) {
77
+ const { value, done } = await reader.read();
78
+ if (done || !value) break;
79
+ const slice = total2 + value.length > maxBytes ? value.slice(0, maxBytes - total2) : value;
80
+ chunks2.push(slice);
81
+ total2 += slice.length;
82
+ }
83
+ if (total2 >= maxBytes) {
84
+ await reader.cancel();
107
85
  }
108
- });
109
- return transform;
86
+ return concatChunks(chunks2, total2);
87
+ }
88
+ const chunks = [];
89
+ let total = 0;
90
+ for await (const chunk of input) {
91
+ if (total >= maxBytes) {
92
+ break;
93
+ }
94
+ const data = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
95
+ const slice = total + data.length > maxBytes ? data.slice(0, maxBytes - total) : data;
96
+ chunks.push(slice);
97
+ total += slice.length;
98
+ }
99
+ return concatChunks(chunks, total);
100
+ }
101
+ function concatChunks(chunks, total) {
102
+ const result = new Uint8Array(total);
103
+ let offset = 0;
104
+ for (const chunk of chunks) {
105
+ result.set(chunk, offset);
106
+ offset += chunk.length;
107
+ }
108
+ return result;
109
+ }
110
+ function isReadableStream(input) {
111
+ return typeof input?.getReader === "function";
112
+ }
113
+ async function loadDetectionWasm(debug) {
114
+ const wasmModule = await loadWasmModule();
115
+ if (typeof wasmModule.default === "function") {
116
+ await wasmModule.default();
117
+ }
118
+ wasmModule.init(debug);
119
+ return wasmModule;
120
+ }
121
+ async function detectFormat(input, opts = {}) {
122
+ const wasmModule = await loadDetectionWasm(!!opts.debug);
123
+ const sample = await readSample(input, opts.maxBytes);
124
+ const format = wasmModule.detectFormat?.(sample);
125
+ return format ?? "unknown";
126
+ }
127
+ async function detectCsvFieldsAndDelimiter(input, opts = {}) {
128
+ const wasmModule = await loadDetectionWasm(!!opts.debug);
129
+ const sample = await readSample(input, opts.maxBytes);
130
+ const result = wasmModule.detectCsvFields?.(sample);
131
+ return result ?? null;
110
132
  }
111
133
  var ConvertBuddyTransformStream = class extends TransformStream {
112
134
  constructor(opts = {}) {
@@ -161,9 +183,10 @@ async function convertToString(input, opts = {}) {
161
183
 
162
184
  export {
163
185
  ConvertBuddy,
164
- createNodeTransform,
186
+ detectFormat,
187
+ detectCsvFieldsAndDelimiter,
165
188
  ConvertBuddyTransformStream,
166
189
  convert,
167
190
  convertToString
168
191
  };
169
- //# sourceMappingURL=chunk-27H3T556.js.map
192
+ //# sourceMappingURL=chunk-WBKHAQCT.js.map
@@ -1,6 +1,13 @@
1
- import { Transform } from 'node:stream';
2
-
3
1
  type Format = "csv" | "ndjson" | "json" | "xml";
2
+ type DetectInput = Uint8Array | ArrayBuffer | string | ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>;
3
+ type CsvDetection = {
4
+ delimiter: string;
5
+ fields: string[];
6
+ };
7
+ type DetectOptions = {
8
+ maxBytes?: number;
9
+ debug?: boolean;
10
+ };
4
11
  type ConvertBuddyOptions = {
5
12
  debug?: boolean;
6
13
  profile?: boolean;
@@ -21,6 +28,7 @@ type XmlConfig = {
21
28
  recordElement?: string;
22
29
  trimText?: boolean;
23
30
  includeAttributes?: boolean;
31
+ expandEntities?: boolean;
24
32
  };
25
33
  type Stats = {
26
34
  bytesIn: number;
@@ -44,11 +52,12 @@ declare class ConvertBuddy {
44
52
  finish(): Uint8Array;
45
53
  stats(): Stats;
46
54
  }
47
- declare function createNodeTransform(opts?: ConvertBuddyOptions): Promise<Transform>;
55
+ declare function detectFormat(input: DetectInput, opts?: DetectOptions): Promise<Format | "unknown">;
56
+ declare function detectCsvFieldsAndDelimiter(input: DetectInput, opts?: DetectOptions): Promise<CsvDetection | null>;
48
57
  declare class ConvertBuddyTransformStream extends TransformStream<Uint8Array, Uint8Array> {
49
58
  constructor(opts?: ConvertBuddyOptions);
50
59
  }
51
60
  declare function convert(input: Uint8Array | string, opts?: ConvertBuddyOptions): Promise<Uint8Array>;
52
61
  declare function convertToString(input: Uint8Array | string, opts?: ConvertBuddyOptions): Promise<string>;
53
62
 
54
- export { ConvertBuddy, type ConvertBuddyOptions, ConvertBuddyTransformStream, type CsvConfig, type Format, type Stats, type XmlConfig, convert, convertToString, createNodeTransform };
63
+ export { ConvertBuddy, type ConvertBuddyOptions, ConvertBuddyTransformStream, type CsvConfig, type CsvDetection, type DetectInput, type DetectOptions, type Format, type Stats, type XmlConfig, convert, convertToString, detectCsvFieldsAndDelimiter, detectFormat };
package/dist/src/index.js CHANGED
@@ -3,13 +3,15 @@ import {
3
3
  ConvertBuddyTransformStream,
4
4
  convert,
5
5
  convertToString,
6
- createNodeTransform
7
- } from "../chunk-27H3T556.js";
6
+ detectCsvFieldsAndDelimiter,
7
+ detectFormat
8
+ } from "../chunk-WBKHAQCT.js";
8
9
  export {
9
10
  ConvertBuddy,
10
11
  ConvertBuddyTransformStream,
11
12
  convert,
12
13
  convertToString,
13
- createNodeTransform
14
+ detectCsvFieldsAndDelimiter,
15
+ detectFormat
14
16
  };
15
17
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ import { Transform } from 'node:stream';
2
+ import { ConvertBuddyOptions } from './index.js';
3
+ export { ConvertBuddy, ConvertBuddyTransformStream, CsvConfig, CsvDetection, DetectInput, DetectOptions, Format, Stats, XmlConfig, convert, convertToString, detectCsvFieldsAndDelimiter, detectFormat } from './index.js';
4
+
5
+ declare function createNodeTransform(opts?: ConvertBuddyOptions): Promise<Transform>;
6
+
7
+ export { ConvertBuddyOptions, createNodeTransform };
@@ -0,0 +1,21 @@
1
+ import {
2
+ createNodeTransform
3
+ } from "../chunk-C3RSVYQF.js";
4
+ import {
5
+ ConvertBuddy,
6
+ ConvertBuddyTransformStream,
7
+ convert,
8
+ convertToString,
9
+ detectCsvFieldsAndDelimiter,
10
+ detectFormat
11
+ } from "../chunk-WBKHAQCT.js";
12
+ export {
13
+ ConvertBuddy,
14
+ ConvertBuddyTransformStream,
15
+ convert,
16
+ convertToString,
17
+ createNodeTransform,
18
+ detectCsvFieldsAndDelimiter,
19
+ detectFormat
20
+ };
21
+ //# sourceMappingURL=node.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "convert-buddy-js",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "TypeScript wrapper for convert-buddy (Rust/WASM core)",
5
5
  "license": "MIT",
6
6
  "type": "module",