convert-buddy-js 0.3.0 → 0.5.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
@@ -44,8 +44,10 @@ console.log(buddy.stats());
44
44
 
45
45
  ### Node.js Transform stream
46
46
 
47
+ Use the Node-specific entrypoint so bundlers keep `node:stream` out of the browser bundle.
48
+
47
49
  ```ts
48
- import { createNodeTransform } from "convert-buddy-js";
50
+ import { createNodeTransform } from "convert-buddy-js/node";
49
51
  import { createReadStream, createWriteStream } from "node:fs";
50
52
 
51
53
  const transform = await createNodeTransform({
@@ -74,6 +76,28 @@ const response = await fetch("/data.csv");
74
76
  const outputStream = response.body?.pipeThrough(transform);
75
77
  ```
76
78
 
79
+ ### Detect format and CSV fields/delimiter
80
+
81
+ Use streaming inputs to keep detection fast on large files.
82
+
83
+ ```ts
84
+ import {
85
+ detectFormat,
86
+ detectCsvFieldsAndDelimiter,
87
+ } from "convert-buddy-js";
88
+
89
+ const fileStream = (await fetch("/data")).body!;
90
+
91
+ const format = await detectFormat(fileStream, { maxBytes: 256 * 1024 });
92
+ console.log(format); // "csv" | "json" | "ndjson" | "xml" | "unknown"
93
+
94
+ const csvInfo = await detectCsvFieldsAndDelimiter(fileStream);
95
+ if (csvInfo) {
96
+ console.log(csvInfo.delimiter);
97
+ console.log(csvInfo.fields);
98
+ }
99
+ ```
100
+
77
101
  ## Configuration
78
102
 
79
103
  ### Formats
@@ -55,58 +55,78 @@ var ConvertBuddy = class _ConvertBuddy {
55
55
  return this.converter.getStats();
56
56
  }
57
57
  };
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.");
58
+ async function readSample(input, maxBytes = 256 * 1024) {
59
+ if (typeof input === "string") {
60
+ const encoded = new TextEncoder().encode(input);
61
+ return encoded.length > maxBytes ? encoded.slice(0, maxBytes) : encoded;
62
62
  }
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
- }
63
+ if (input instanceof Uint8Array) {
64
+ return input.length > maxBytes ? input.slice(0, maxBytes) : input;
65
+ }
66
+ if (input instanceof ArrayBuffer) {
67
+ const bytes = new Uint8Array(input);
68
+ return bytes.length > maxBytes ? bytes.slice(0, maxBytes) : bytes;
69
+ }
70
+ if (isReadableStream(input)) {
71
+ const reader = input.getReader();
72
+ const chunks2 = [];
73
+ let total2 = 0;
74
+ while (total2 < maxBytes) {
75
+ const { value, done } = await reader.read();
76
+ if (done || !value) break;
77
+ const slice = total2 + value.length > maxBytes ? value.slice(0, maxBytes - total2) : value;
78
+ chunks2.push(slice);
79
+ total2 += slice.length;
80
+ }
81
+ if (total2 >= maxBytes) {
82
+ await reader.cancel();
107
83
  }
108
- });
109
- return transform;
84
+ return concatChunks(chunks2, total2);
85
+ }
86
+ const chunks = [];
87
+ let total = 0;
88
+ for await (const chunk of input) {
89
+ if (total >= maxBytes) {
90
+ break;
91
+ }
92
+ const data = chunk instanceof Uint8Array ? chunk : new Uint8Array(chunk);
93
+ const slice = total + data.length > maxBytes ? data.slice(0, maxBytes - total) : data;
94
+ chunks.push(slice);
95
+ total += slice.length;
96
+ }
97
+ return concatChunks(chunks, total);
98
+ }
99
+ function concatChunks(chunks, total) {
100
+ const result = new Uint8Array(total);
101
+ let offset = 0;
102
+ for (const chunk of chunks) {
103
+ result.set(chunk, offset);
104
+ offset += chunk.length;
105
+ }
106
+ return result;
107
+ }
108
+ function isReadableStream(input) {
109
+ return typeof input?.getReader === "function";
110
+ }
111
+ async function loadDetectionWasm(debug) {
112
+ const wasmModule = await loadWasmModule();
113
+ if (typeof wasmModule.default === "function") {
114
+ await wasmModule.default();
115
+ }
116
+ wasmModule.init(debug);
117
+ return wasmModule;
118
+ }
119
+ async function detectFormat(input, opts = {}) {
120
+ const wasmModule = await loadDetectionWasm(!!opts.debug);
121
+ const sample = await readSample(input, opts.maxBytes);
122
+ const format = wasmModule.detectFormat?.(sample);
123
+ return format ?? "unknown";
124
+ }
125
+ async function detectCsvFieldsAndDelimiter(input, opts = {}) {
126
+ const wasmModule = await loadDetectionWasm(!!opts.debug);
127
+ const sample = await readSample(input, opts.maxBytes);
128
+ const result = wasmModule.detectCsvFields?.(sample);
129
+ return result ?? null;
110
130
  }
111
131
  var ConvertBuddyTransformStream = class extends TransformStream {
112
132
  constructor(opts = {}) {
@@ -161,9 +181,10 @@ async function convertToString(input, opts = {}) {
161
181
 
162
182
  export {
163
183
  ConvertBuddy,
164
- createNodeTransform,
184
+ detectFormat,
185
+ detectCsvFieldsAndDelimiter,
165
186
  ConvertBuddyTransformStream,
166
187
  convert,
167
188
  convertToString
168
189
  };
169
- //# sourceMappingURL=chunk-27H3T556.js.map
190
+ //# sourceMappingURL=chunk-IOVM4CIO.js.map
@@ -0,0 +1,63 @@
1
+ import {
2
+ ConvertBuddy
3
+ } from "./chunk-IOVM4CIO.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-XKIJB7Y4.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;
@@ -44,11 +51,12 @@ declare class ConvertBuddy {
44
51
  finish(): Uint8Array;
45
52
  stats(): Stats;
46
53
  }
47
- declare function createNodeTransform(opts?: ConvertBuddyOptions): Promise<Transform>;
54
+ declare function detectFormat(input: DetectInput, opts?: DetectOptions): Promise<Format | "unknown">;
55
+ declare function detectCsvFieldsAndDelimiter(input: DetectInput, opts?: DetectOptions): Promise<CsvDetection | null>;
48
56
  declare class ConvertBuddyTransformStream extends TransformStream<Uint8Array, Uint8Array> {
49
57
  constructor(opts?: ConvertBuddyOptions);
50
58
  }
51
59
  declare function convert(input: Uint8Array | string, opts?: ConvertBuddyOptions): Promise<Uint8Array>;
52
60
  declare function convertToString(input: Uint8Array | string, opts?: ConvertBuddyOptions): Promise<string>;
53
61
 
54
- export { ConvertBuddy, type ConvertBuddyOptions, ConvertBuddyTransformStream, type CsvConfig, type Format, type Stats, type XmlConfig, convert, convertToString, createNodeTransform };
62
+ 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-IOVM4CIO.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-XKIJB7Y4.js";
4
+ import {
5
+ ConvertBuddy,
6
+ ConvertBuddyTransformStream,
7
+ convert,
8
+ convertToString,
9
+ detectCsvFieldsAndDelimiter,
10
+ detectFormat
11
+ } from "../chunk-IOVM4CIO.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.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "TypeScript wrapper for convert-buddy (Rust/WASM core)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -10,11 +10,17 @@
10
10
  ".": {
11
11
  "types": "./dist/src/index.d.ts",
12
12
  "default": "./dist/src/index.js"
13
+ },
14
+ "./node": {
15
+ "types": "./dist/src/node.d.ts",
16
+ "default": "./dist/src/node.js"
13
17
  }
14
18
  },
15
19
  "files": [
16
20
  "dist/src/index.js",
17
21
  "dist/src/index.d.ts",
22
+ "dist/src/node.js",
23
+ "dist/src/node.d.ts",
18
24
  "dist/chunk-*.js",
19
25
  "dist/chunk-*.d.ts",
20
26
  "dist/*.js",