convert-buddy-js 0.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.
- package/dist/chunk-B44HYXEP.js +161 -0
- package/dist/chunk-DESHN2IK.js +151 -0
- package/dist/chunk-HFHFJO2R.js +44 -0
- package/dist/chunk-VUNV25KB.js +16 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +7 -0
- package/package.json +52 -0
- package/wasm-node.cjs +1 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { Transform } from "stream";
|
|
3
|
+
async function loadWasmModule() {
|
|
4
|
+
const isNode = typeof process !== "undefined" && !!process.versions?.node;
|
|
5
|
+
if (isNode) {
|
|
6
|
+
const { createRequire } = await import("module");
|
|
7
|
+
const require2 = createRequire(import.meta.url);
|
|
8
|
+
const mod2 = require2("../wasm-node.cjs");
|
|
9
|
+
return mod2;
|
|
10
|
+
}
|
|
11
|
+
const mod = await import("../wasm/web/convert_buddy.js");
|
|
12
|
+
return mod;
|
|
13
|
+
}
|
|
14
|
+
var ConvertBuddy = class _ConvertBuddy {
|
|
15
|
+
converter;
|
|
16
|
+
debug;
|
|
17
|
+
profile;
|
|
18
|
+
constructor(converter, debug, profile) {
|
|
19
|
+
this.converter = converter;
|
|
20
|
+
this.debug = debug;
|
|
21
|
+
this.profile = profile;
|
|
22
|
+
}
|
|
23
|
+
static async create(opts = {}) {
|
|
24
|
+
const debug = !!opts.debug;
|
|
25
|
+
const profile = !!opts.profile;
|
|
26
|
+
const wasmModule = await loadWasmModule();
|
|
27
|
+
if (typeof wasmModule.default === "function") {
|
|
28
|
+
await wasmModule.default();
|
|
29
|
+
}
|
|
30
|
+
wasmModule.init(debug);
|
|
31
|
+
let converter;
|
|
32
|
+
if (opts.inputFormat && opts.outputFormat) {
|
|
33
|
+
const Converter = wasmModule.Converter;
|
|
34
|
+
converter = Converter.withConfig(
|
|
35
|
+
debug,
|
|
36
|
+
opts.inputFormat,
|
|
37
|
+
opts.outputFormat,
|
|
38
|
+
opts.chunkTargetBytes || 1024 * 1024,
|
|
39
|
+
profile
|
|
40
|
+
);
|
|
41
|
+
} else {
|
|
42
|
+
converter = new wasmModule.Converter(debug);
|
|
43
|
+
}
|
|
44
|
+
if (debug) console.log("[convert-buddy-js] initialized", opts);
|
|
45
|
+
return new _ConvertBuddy(converter, debug, profile);
|
|
46
|
+
}
|
|
47
|
+
push(chunk) {
|
|
48
|
+
if (this.debug) console.log("[convert-buddy-js] push", chunk.byteLength);
|
|
49
|
+
return this.converter.push(chunk);
|
|
50
|
+
}
|
|
51
|
+
finish() {
|
|
52
|
+
if (this.debug) console.log("[convert-buddy-js] finish");
|
|
53
|
+
return this.converter.finish();
|
|
54
|
+
}
|
|
55
|
+
stats() {
|
|
56
|
+
return this.converter.getStats();
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
function createNodeTransform(opts = {}) {
|
|
60
|
+
let buddy = null;
|
|
61
|
+
let initPromise = null;
|
|
62
|
+
const transform = new Transform({
|
|
63
|
+
async transform(chunk, encoding, callback) {
|
|
64
|
+
try {
|
|
65
|
+
if (!buddy) {
|
|
66
|
+
if (!initPromise) {
|
|
67
|
+
initPromise = ConvertBuddy.create(opts).then((b) => {
|
|
68
|
+
buddy = b;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
await initPromise;
|
|
72
|
+
}
|
|
73
|
+
const input = new Uint8Array(chunk);
|
|
74
|
+
const output = buddy.push(input);
|
|
75
|
+
if (output.length > 0) {
|
|
76
|
+
this.push(Buffer.from(output));
|
|
77
|
+
}
|
|
78
|
+
callback();
|
|
79
|
+
} catch (err) {
|
|
80
|
+
callback(err);
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
async flush(callback) {
|
|
84
|
+
try {
|
|
85
|
+
if (buddy) {
|
|
86
|
+
const output = buddy.finish();
|
|
87
|
+
if (output.length > 0) {
|
|
88
|
+
this.push(Buffer.from(output));
|
|
89
|
+
}
|
|
90
|
+
if (opts.profile) {
|
|
91
|
+
const stats = buddy.stats();
|
|
92
|
+
console.log("[convert-buddy] Performance Stats:", stats);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
callback();
|
|
96
|
+
} catch (err) {
|
|
97
|
+
callback(err);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
return transform;
|
|
102
|
+
}
|
|
103
|
+
var ConvertBuddyTransformStream = class extends TransformStream {
|
|
104
|
+
constructor(opts = {}) {
|
|
105
|
+
let buddy = null;
|
|
106
|
+
super({
|
|
107
|
+
async start(controller) {
|
|
108
|
+
buddy = await ConvertBuddy.create(opts);
|
|
109
|
+
},
|
|
110
|
+
transform(chunk, controller) {
|
|
111
|
+
if (!buddy) {
|
|
112
|
+
throw new Error("ConvertBuddy not initialized");
|
|
113
|
+
}
|
|
114
|
+
const output = buddy.push(chunk);
|
|
115
|
+
if (output.length > 0) {
|
|
116
|
+
controller.enqueue(output);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
flush(controller) {
|
|
120
|
+
if (!buddy) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
const output = buddy.finish();
|
|
124
|
+
if (output.length > 0) {
|
|
125
|
+
controller.enqueue(output);
|
|
126
|
+
}
|
|
127
|
+
if (opts.profile) {
|
|
128
|
+
const stats = buddy.stats();
|
|
129
|
+
console.log("[convert-buddy] Performance Stats:", stats);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
async function convert(input, opts = {}) {
|
|
136
|
+
const buddy = await ConvertBuddy.create(opts);
|
|
137
|
+
const inputBytes = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
138
|
+
const output = buddy.push(inputBytes);
|
|
139
|
+
const final = buddy.finish();
|
|
140
|
+
const result = new Uint8Array(output.length + final.length);
|
|
141
|
+
result.set(output, 0);
|
|
142
|
+
result.set(final, output.length);
|
|
143
|
+
if (opts.profile) {
|
|
144
|
+
const stats = buddy.stats();
|
|
145
|
+
console.log("[convert-buddy] Performance Stats:", stats);
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
149
|
+
async function convertToString(input, opts = {}) {
|
|
150
|
+
const result = await convert(input, opts);
|
|
151
|
+
return new TextDecoder().decode(result);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export {
|
|
155
|
+
ConvertBuddy,
|
|
156
|
+
createNodeTransform,
|
|
157
|
+
ConvertBuddyTransformStream,
|
|
158
|
+
convert,
|
|
159
|
+
convertToString
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=chunk-B44HYXEP.js.map
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// bench/datasets.ts
|
|
2
|
+
function generateCsvDataset(rows, cols) {
|
|
3
|
+
const encoder = new TextEncoder();
|
|
4
|
+
let csv = "";
|
|
5
|
+
const headers = Array.from({ length: cols }, (_, i) => `column_${i}`);
|
|
6
|
+
csv += headers.join(",") + "\n";
|
|
7
|
+
for (let i = 0; i < rows; i++) {
|
|
8
|
+
const row = Array.from({ length: cols }, (_, j) => {
|
|
9
|
+
if (j % 4 === 0) {
|
|
10
|
+
return `"text_${i}_${j}"`;
|
|
11
|
+
} else if (j % 4 === 1) {
|
|
12
|
+
return i * j;
|
|
13
|
+
} else if (j % 4 === 2) {
|
|
14
|
+
return `value_${i}`;
|
|
15
|
+
} else {
|
|
16
|
+
return `"quoted, with comma ${i}"`;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
csv += row.join(",") + "\n";
|
|
20
|
+
}
|
|
21
|
+
return encoder.encode(csv);
|
|
22
|
+
}
|
|
23
|
+
function generateNdjsonDataset(records, fields) {
|
|
24
|
+
const encoder = new TextEncoder();
|
|
25
|
+
let ndjson = "";
|
|
26
|
+
for (let i = 0; i < records; i++) {
|
|
27
|
+
const obj = {};
|
|
28
|
+
for (let j = 0; j < fields; j++) {
|
|
29
|
+
const key = `field_${j}`;
|
|
30
|
+
if (j % 5 === 0) {
|
|
31
|
+
obj[key] = `string_value_${i}_${j}`;
|
|
32
|
+
} else if (j % 5 === 1) {
|
|
33
|
+
obj[key] = i * j;
|
|
34
|
+
} else if (j % 5 === 2) {
|
|
35
|
+
obj[key] = i % 2 === 0;
|
|
36
|
+
} else if (j % 5 === 3) {
|
|
37
|
+
obj[key] = null;
|
|
38
|
+
} else {
|
|
39
|
+
obj[key] = { nested: `value_${i}`, count: j };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
ndjson += JSON.stringify(obj) + "\n";
|
|
43
|
+
}
|
|
44
|
+
return encoder.encode(ndjson);
|
|
45
|
+
}
|
|
46
|
+
function generateXmlDataset(records, fields) {
|
|
47
|
+
const encoder = new TextEncoder();
|
|
48
|
+
let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<root>\n';
|
|
49
|
+
for (let i = 0; i < records; i++) {
|
|
50
|
+
xml += ` <record id="${i}">
|
|
51
|
+
`;
|
|
52
|
+
for (let j = 0; j < fields; j++) {
|
|
53
|
+
const value = `value_${i}_${j}`;
|
|
54
|
+
xml += ` <field_${j}>${value}</field_${j}>
|
|
55
|
+
`;
|
|
56
|
+
}
|
|
57
|
+
xml += ` </record>
|
|
58
|
+
`;
|
|
59
|
+
}
|
|
60
|
+
xml += "</root>\n";
|
|
61
|
+
return encoder.encode(xml);
|
|
62
|
+
}
|
|
63
|
+
function generateJsonDataset(records, fields) {
|
|
64
|
+
const encoder = new TextEncoder();
|
|
65
|
+
const array = [];
|
|
66
|
+
for (let i = 0; i < records; i++) {
|
|
67
|
+
const obj = {};
|
|
68
|
+
for (let j = 0; j < fields; j++) {
|
|
69
|
+
const key = `field_${j}`;
|
|
70
|
+
if (j % 4 === 0) {
|
|
71
|
+
obj[key] = `string_value_${i}_${j}`;
|
|
72
|
+
} else if (j % 4 === 1) {
|
|
73
|
+
obj[key] = i * j;
|
|
74
|
+
} else if (j % 4 === 2) {
|
|
75
|
+
obj[key] = i % 2 === 0;
|
|
76
|
+
} else {
|
|
77
|
+
obj[key] = { nested: `value_${i}` };
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
array.push(obj);
|
|
81
|
+
}
|
|
82
|
+
return encoder.encode(JSON.stringify(array));
|
|
83
|
+
}
|
|
84
|
+
function generateRealisticCsv(rows) {
|
|
85
|
+
const encoder = new TextEncoder();
|
|
86
|
+
let csv = "id,name,email,age,city,description\n";
|
|
87
|
+
const cities = ["New York", "London", "Tokyo", "Paris", "Berlin"];
|
|
88
|
+
const names = ["Alice", "Bob", "Charlie", "Diana", "Eve"];
|
|
89
|
+
for (let i = 0; i < rows; i++) {
|
|
90
|
+
const name = names[i % names.length];
|
|
91
|
+
const email = `${name.toLowerCase()}${i}@example.com`;
|
|
92
|
+
const age = 20 + i % 50;
|
|
93
|
+
const city = cities[i % cities.length];
|
|
94
|
+
const description = `"This is a longer description with, commas and ""quotes"" for record ${i}"`;
|
|
95
|
+
csv += `${i},${name},${email},${age},${city},${description}
|
|
96
|
+
`;
|
|
97
|
+
}
|
|
98
|
+
return encoder.encode(csv);
|
|
99
|
+
}
|
|
100
|
+
function generateWideCsv(rows, cols = 100) {
|
|
101
|
+
const encoder = new TextEncoder();
|
|
102
|
+
const headers = Array.from({ length: cols }, (_, i) => `col_${i}`);
|
|
103
|
+
let csv = headers.join(",") + "\n";
|
|
104
|
+
for (let i = 0; i < rows; i++) {
|
|
105
|
+
const row = Array.from({ length: cols }, (_, j) => i * cols + j);
|
|
106
|
+
csv += row.join(",") + "\n";
|
|
107
|
+
}
|
|
108
|
+
return encoder.encode(csv);
|
|
109
|
+
}
|
|
110
|
+
function generateLargeObjectNdjson(records) {
|
|
111
|
+
const encoder = new TextEncoder();
|
|
112
|
+
let ndjson = "";
|
|
113
|
+
for (let i = 0; i < records; i++) {
|
|
114
|
+
const obj = {
|
|
115
|
+
id: i,
|
|
116
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
117
|
+
user: {
|
|
118
|
+
name: `User ${i}`,
|
|
119
|
+
email: `user${i}@example.com`,
|
|
120
|
+
profile: {
|
|
121
|
+
age: 20 + i % 50,
|
|
122
|
+
city: "City",
|
|
123
|
+
bio: "A".repeat(100)
|
|
124
|
+
// Large string
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
data: Array.from({ length: 10 }, (_, j) => ({
|
|
128
|
+
key: `key_${j}`,
|
|
129
|
+
value: i * j
|
|
130
|
+
})),
|
|
131
|
+
metadata: {
|
|
132
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
133
|
+
updated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
134
|
+
tags: ["tag1", "tag2", "tag3"]
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
ndjson += JSON.stringify(obj) + "\n";
|
|
138
|
+
}
|
|
139
|
+
return encoder.encode(ndjson);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export {
|
|
143
|
+
generateCsvDataset,
|
|
144
|
+
generateNdjsonDataset,
|
|
145
|
+
generateXmlDataset,
|
|
146
|
+
generateJsonDataset,
|
|
147
|
+
generateRealisticCsv,
|
|
148
|
+
generateWideCsv,
|
|
149
|
+
generateLargeObjectNdjson
|
|
150
|
+
};
|
|
151
|
+
//# sourceMappingURL=chunk-DESHN2IK.js.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
async function loadWasmModule() {
|
|
3
|
+
const isNode = typeof process !== "undefined" && !!process.versions?.node;
|
|
4
|
+
if (isNode) {
|
|
5
|
+
const { createRequire } = await import("module");
|
|
6
|
+
const require2 = createRequire(import.meta.url);
|
|
7
|
+
const mod2 = require2("../wasm-node.cjs");
|
|
8
|
+
return mod2;
|
|
9
|
+
}
|
|
10
|
+
const mod = await import("../wasm/web/convert_buddy.js");
|
|
11
|
+
return mod;
|
|
12
|
+
}
|
|
13
|
+
var ConvertBuddy = class _ConvertBuddy {
|
|
14
|
+
converter;
|
|
15
|
+
debug;
|
|
16
|
+
constructor(converter, debug) {
|
|
17
|
+
this.converter = converter;
|
|
18
|
+
this.debug = debug;
|
|
19
|
+
}
|
|
20
|
+
static async create(opts = {}) {
|
|
21
|
+
const debug = !!opts.debug;
|
|
22
|
+
const wasmModule = await loadWasmModule();
|
|
23
|
+
if (typeof wasmModule.default === "function") {
|
|
24
|
+
await wasmModule.default();
|
|
25
|
+
}
|
|
26
|
+
wasmModule.init(debug);
|
|
27
|
+
const converter = new wasmModule.Converter(debug);
|
|
28
|
+
if (debug) console.log("[convert-buddy-js] initialized with debug logging");
|
|
29
|
+
return new _ConvertBuddy(converter, debug);
|
|
30
|
+
}
|
|
31
|
+
push(chunk) {
|
|
32
|
+
if (this.debug) console.log("[convert-buddy-js] push", chunk.byteLength);
|
|
33
|
+
return this.converter.push(chunk);
|
|
34
|
+
}
|
|
35
|
+
finish() {
|
|
36
|
+
if (this.debug) console.log("[convert-buddy-js] finish");
|
|
37
|
+
return this.converter.finish();
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export {
|
|
42
|
+
ConvertBuddy
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=chunk-HFHFJO2R.js.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
8
|
+
var __commonJS = (cb, mod) => function __require2() {
|
|
9
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
__require,
|
|
14
|
+
__commonJS
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=chunk-VUNV25KB.js.map
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
type ConvertBuddyOptions = {
|
|
2
|
+
debug?: boolean;
|
|
3
|
+
};
|
|
4
|
+
declare class ConvertBuddy {
|
|
5
|
+
private converter;
|
|
6
|
+
private debug;
|
|
7
|
+
private constructor();
|
|
8
|
+
static create(opts?: ConvertBuddyOptions): Promise<ConvertBuddy>;
|
|
9
|
+
push(chunk: Uint8Array): Uint8Array;
|
|
10
|
+
finish(): Uint8Array;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export { ConvertBuddy, type ConvertBuddyOptions };
|
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "convert-buddy-js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript wrapper for convert-buddy (Rust/WASM core)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist/index.js",
|
|
17
|
+
"dist/index.d.ts",
|
|
18
|
+
"dist/chunk-*.js",
|
|
19
|
+
"dist/chunk-*.d.ts",
|
|
20
|
+
"wasm",
|
|
21
|
+
"wasm-node.cjs",
|
|
22
|
+
"!dist/smoke-test.*",
|
|
23
|
+
"!dist/bench"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"clean": "node ./scripts/clean.mjs",
|
|
27
|
+
"build:wasm:web": "set CONVERT_BUDDY_WASM_TARGET=web&& node ./scripts/build-wasm.mjs",
|
|
28
|
+
"build:wasm:node": "set CONVERT_BUDDY_WASM_TARGET=nodejs&& node ./scripts/build-wasm.mjs",
|
|
29
|
+
"build:wasm": "npm run build:wasm:web && npm run build:wasm:node",
|
|
30
|
+
"build": "npm run build:wasm && tsup",
|
|
31
|
+
"test": "npm run build && node ./dist/smoke-test.js",
|
|
32
|
+
"test:edge-cases": "npm run build && node --test ./dist/tests/edge-cases/*.test.js",
|
|
33
|
+
"test:all": "npm run test && npm run test:edge-cases",
|
|
34
|
+
"bench": "npm run build && node ./dist/bench/runner.js",
|
|
35
|
+
"bench:single-thread": "npm run build && UV_THREADPOOL_SIZE=1 node ./dist/bench/single-thread.js",
|
|
36
|
+
"bench:multi-thread": "npm run build && node ./dist/bench/multi-thread.js",
|
|
37
|
+
"bench:compare": "npm run build && node ./dist/bench/compare-threads.js",
|
|
38
|
+
"bench:competitors": "npm run build && node ./dist/bench/runner-with-competitors.js",
|
|
39
|
+
"bench:competitors-comprehensive": "npm run build && node ./dist/bench/runner-competitors-comprehensive.js",
|
|
40
|
+
"bench:all": "npm run bench:single-thread && npm run bench:multi-thread && npm run bench:compare && npm run bench:competitors-comprehensive",
|
|
41
|
+
"lint": "node ./scripts/lint-placeholder.mjs"
|
|
42
|
+
},
|
|
43
|
+
"devDependencies": {
|
|
44
|
+
"@types/node": "^25.0.3",
|
|
45
|
+
"@types/papaparse": "^5.3.15",
|
|
46
|
+
"csv-parse": "^5.6.0",
|
|
47
|
+
"fast-csv": "^5.0.1",
|
|
48
|
+
"papaparse": "^5.4.1",
|
|
49
|
+
"tsup": "^8.0.0",
|
|
50
|
+
"typescript": "^5.5.0"
|
|
51
|
+
}
|
|
52
|
+
}
|
package/wasm-node.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
module.exports = require("./wasm/nodejs/convert_buddy.js");
|