breeze-bindgen 1.0.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/index.mjs ADDED
@@ -0,0 +1,737 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
8
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
9
+ }) : x)(function(x) {
10
+ if (typeof require !== "undefined") return require.apply(this, arguments);
11
+ throw Error('Dynamic require of "' + x + '" is not supported');
12
+ });
13
+ var __commonJS = (cb, mod) => function __require2() {
14
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
15
+ };
16
+ var __copyProps = (to, from, except, desc) => {
17
+ if (from && typeof from === "object" || typeof from === "function") {
18
+ for (let key of __getOwnPropNames(from))
19
+ if (!__hasOwnProp.call(to, key) && key !== except)
20
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
21
+ }
22
+ return to;
23
+ };
24
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
25
+ // If the importer is in node compatibility mode or this is not an ESM
26
+ // file that has been converted to a CommonJS file using a Babel-
27
+ // compatible transform (i.e. "__esModule" has not been set), then set
28
+ // "default" to the CommonJS "module.exports" for node compatibility.
29
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
30
+ mod
31
+ ));
32
+
33
+ // node_modules/color-support/index.js
34
+ var require_color_support = __commonJS({
35
+ "node_modules/color-support/index.js"(exports, module) {
36
+ module.exports = colorSupport({ alwaysReturn: true }, colorSupport);
37
+ function hasNone(obj, options) {
38
+ obj.level = 0;
39
+ obj.hasBasic = false;
40
+ obj.has256 = false;
41
+ obj.has16m = false;
42
+ if (!options.alwaysReturn) {
43
+ return false;
44
+ }
45
+ return obj;
46
+ }
47
+ function hasBasic(obj) {
48
+ obj.hasBasic = true;
49
+ obj.has256 = false;
50
+ obj.has16m = false;
51
+ obj.level = 1;
52
+ return obj;
53
+ }
54
+ function has256(obj) {
55
+ obj.hasBasic = true;
56
+ obj.has256 = true;
57
+ obj.has16m = false;
58
+ obj.level = 2;
59
+ return obj;
60
+ }
61
+ function has16m(obj) {
62
+ obj.hasBasic = true;
63
+ obj.has256 = true;
64
+ obj.has16m = true;
65
+ obj.level = 3;
66
+ return obj;
67
+ }
68
+ function colorSupport(options, obj) {
69
+ options = options || {};
70
+ obj = obj || {};
71
+ if (typeof options.level === "number") {
72
+ switch (options.level) {
73
+ case 0:
74
+ return hasNone(obj, options);
75
+ case 1:
76
+ return hasBasic(obj);
77
+ case 2:
78
+ return has256(obj);
79
+ case 3:
80
+ return has16m(obj);
81
+ }
82
+ }
83
+ obj.level = 0;
84
+ obj.hasBasic = false;
85
+ obj.has256 = false;
86
+ obj.has16m = false;
87
+ if (typeof process === "undefined" || !process || !process.stdout || !process.env || !process.platform) {
88
+ return hasNone(obj, options);
89
+ }
90
+ var env = options.env || process.env;
91
+ var stream = options.stream || process.stdout;
92
+ var term = options.term || env.TERM || "";
93
+ var platform = options.platform || process.platform;
94
+ if (!options.ignoreTTY && !stream.isTTY) {
95
+ return hasNone(obj, options);
96
+ }
97
+ if (!options.ignoreDumb && term === "dumb" && !env.COLORTERM) {
98
+ return hasNone(obj, options);
99
+ }
100
+ if (platform === "win32") {
101
+ return hasBasic(obj);
102
+ }
103
+ if (env.TMUX) {
104
+ return has256(obj);
105
+ }
106
+ if (!options.ignoreCI && (env.CI || env.TEAMCITY_VERSION)) {
107
+ if (env.TRAVIS) {
108
+ return has256(obj);
109
+ } else {
110
+ return hasNone(obj, options);
111
+ }
112
+ }
113
+ switch (env.TERM_PROGRAM) {
114
+ case "iTerm.app":
115
+ var ver = env.TERM_PROGRAM_VERSION || "0.";
116
+ if (/^[0-2]\./.test(ver)) {
117
+ return has256(obj);
118
+ } else {
119
+ return has16m(obj);
120
+ }
121
+ case "HyperTerm":
122
+ case "Hyper":
123
+ return has16m(obj);
124
+ case "MacTerm":
125
+ return has16m(obj);
126
+ case "Apple_Terminal":
127
+ return has256(obj);
128
+ }
129
+ if (/^xterm-256/.test(term)) {
130
+ return has256(obj);
131
+ }
132
+ if (/^screen|^xterm|^vt100|color|ansi|cygwin|linux/i.test(term)) {
133
+ return hasBasic(obj);
134
+ }
135
+ if (env.COLORTERM) {
136
+ return hasBasic(obj);
137
+ }
138
+ return hasNone(obj, options);
139
+ }
140
+ }
141
+ });
142
+
143
+ // node_modules/fancy-log/index.js
144
+ var require_fancy_log = __commonJS({
145
+ "node_modules/fancy-log/index.js"(exports, module) {
146
+ "use strict";
147
+ var util = __require("util");
148
+ var Console = __require("console").Console;
149
+ var supportsColor = require_color_support();
150
+ var console = new Console({
151
+ stdout: process.stdout,
152
+ stderr: process.stderr,
153
+ colorMode: false
154
+ });
155
+ function hasFlag(flag) {
156
+ return process.argv.indexOf("--" + flag) !== -1;
157
+ }
158
+ function hasColors() {
159
+ if (hasFlag("no-color")) {
160
+ return false;
161
+ }
162
+ if (hasFlag("color")) {
163
+ return true;
164
+ }
165
+ if (supportsColor()) {
166
+ return true;
167
+ }
168
+ return false;
169
+ }
170
+ function Timestamp() {
171
+ this.now = /* @__PURE__ */ new Date();
172
+ }
173
+ Timestamp.prototype[util.inspect.custom] = function(depth, opts) {
174
+ var timestamp = this.now.toLocaleTimeString("en", { hour12: false });
175
+ return "[" + opts.stylize(timestamp, "date") + "]";
176
+ };
177
+ function getTimestamp() {
178
+ return util.inspect(new Timestamp(), { colors: hasColors() });
179
+ }
180
+ function log3() {
181
+ var time = getTimestamp();
182
+ process.stdout.write(time + " ");
183
+ console.log.apply(console, arguments);
184
+ return this;
185
+ }
186
+ function info() {
187
+ var time = getTimestamp();
188
+ process.stdout.write(time + " ");
189
+ console.info.apply(console, arguments);
190
+ return this;
191
+ }
192
+ function dir() {
193
+ var time = getTimestamp();
194
+ process.stdout.write(time + " ");
195
+ console.dir.apply(console, arguments);
196
+ return this;
197
+ }
198
+ function warn() {
199
+ var time = getTimestamp();
200
+ process.stderr.write(time + " ");
201
+ console.warn.apply(console, arguments);
202
+ return this;
203
+ }
204
+ function error() {
205
+ var time = getTimestamp();
206
+ process.stderr.write(time + " ");
207
+ console.error.apply(console, arguments);
208
+ return this;
209
+ }
210
+ module.exports = log3;
211
+ module.exports.info = info;
212
+ module.exports.dir = dir;
213
+ module.exports.warn = warn;
214
+ module.exports.error = error;
215
+ }
216
+ });
217
+
218
+ // index.ts
219
+ var import_fancy_log2 = __toESM(require_fancy_log());
220
+
221
+ // core.ts
222
+ var import_fancy_log = __toESM(require_fancy_log());
223
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
224
+ import { join, dirname, resolve as resolvePath } from "node:path";
225
+ import { fileURLToPath } from "node:url";
226
+ import { spawnSync } from "node:child_process";
227
+
228
+ // c-type-parser.ts
229
+ var CTypeParser = class {
230
+ tokens = [];
231
+ cursor = 0;
232
+ lex(str) {
233
+ this.tokens = [];
234
+ let current = "";
235
+ const BREAK_TOKENS = [" ", "(", ")", ",", "<", ">"];
236
+ for (let i = 0; i < str.length; i++) {
237
+ const c = str[i];
238
+ if (BREAK_TOKENS.includes(c)) {
239
+ if (current.length > 0) {
240
+ this.tokens.push(current);
241
+ current = "";
242
+ }
243
+ if (c !== " ") {
244
+ this.tokens.push(c);
245
+ }
246
+ } else {
247
+ current += c;
248
+ }
249
+ }
250
+ if (current.length > 0) {
251
+ this.tokens.push(current);
252
+ }
253
+ }
254
+ parse(str = null, typeTransformer = (orig) => orig) {
255
+ if (str) {
256
+ this.lex(str);
257
+ this.cursor = 0;
258
+ }
259
+ const type = {
260
+ argsFunc: [],
261
+ argsTemplate: [],
262
+ function: false,
263
+ template: false,
264
+ type: ""
265
+ };
266
+ do {
267
+ const parseCommaList = (arr) => {
268
+ do {
269
+ const res = this.parse(null, typeTransformer);
270
+ if (res)
271
+ arr.push(res);
272
+ } while (this.eat(","));
273
+ };
274
+ if (this.eat("(")) {
275
+ type.function = true;
276
+ if (!this.next(")"))
277
+ parseCommaList(type.argsFunc);
278
+ this.eat(")", true);
279
+ } else if (this.eat("<")) {
280
+ type.template = true;
281
+ if (!this.next(">"))
282
+ parseCommaList(type.argsTemplate);
283
+ this.eat(">", true);
284
+ } else {
285
+ type.type = typeTransformer(this.tokens[this.cursor]);
286
+ this.cursor++;
287
+ }
288
+ if (this.next("(") || this.next("<")) {
289
+ continue;
290
+ }
291
+ break;
292
+ } while (true);
293
+ return type;
294
+ }
295
+ eat(token, force = false) {
296
+ if (this.next(token)) {
297
+ this.cursor++;
298
+ return true;
299
+ } else {
300
+ if (force) throw new Error(`Excepted: ${token}, found ${this.next()} in ${this.tokens.join(" ")}`);
301
+ }
302
+ return false;
303
+ }
304
+ next(token = null) {
305
+ if (this.tokens[this.cursor] === token || !token) {
306
+ return this.tokens[this.cursor];
307
+ }
308
+ return false;
309
+ }
310
+ formatToC(node) {
311
+ let str = node.type;
312
+ if (node.template) {
313
+ str += "<" + node.argsTemplate.map((a) => this.formatToC(a)).join(", ") + ">";
314
+ }
315
+ if (node.function) {
316
+ str += "(" + node.argsFunc.map((a) => this.formatToC(a)).join(", ") + ")";
317
+ }
318
+ return str;
319
+ }
320
+ formatToTypeScript(node, namespace = "") {
321
+ if (node.type.startsWith(namespace))
322
+ node.type = node.type.slice(namespace.length);
323
+ node.type = node.type.split("::").filter(Boolean).join(".");
324
+ const typeMap = {
325
+ "int": "number",
326
+ "float": "number",
327
+ "double": "number",
328
+ "std.string": "string",
329
+ "std.vector": "Array",
330
+ "bool": "boolean"
331
+ };
332
+ let tsBasicType = (typeMap[node.type] ?? node.type) + (node.template ? "<" + node.argsTemplate.map((a) => this.formatToTypeScript(a, namespace)).join(", ") + ">" : "");
333
+ const ignoreTypes = ["std.variant", "std.shared_ptr", "std.function"];
334
+ if (ignoreTypes.includes(node.type)) {
335
+ tsBasicType = node.argsTemplate.map((a) => this.formatToTypeScript(a, namespace)).join(" | ");
336
+ } else if (node.type === "std.optional") {
337
+ tsBasicType = `${this.formatToTypeScript(node.argsTemplate[0], namespace)} | undefined`;
338
+ } else if (node.type === "std.pair" || node.type === "std.tuple") {
339
+ tsBasicType = node.argsTemplate.map((a) => this.formatToTypeScript(a, namespace)).join(", ");
340
+ tsBasicType = `[${tsBasicType}]`;
341
+ }
342
+ if (node.function) {
343
+ return `((${node.argsFunc.map((a) => this.formatToTypeScript(a, namespace)).map((v, i) => `arg${i + 1}: ${v}`).join(", ")}) => ${tsBasicType})`;
344
+ }
345
+ return tsBasicType;
346
+ }
347
+ };
348
+ var cTypeToTypeScript = (str, namespace) => {
349
+ const parser = new CTypeParser();
350
+ parser.lex(str);
351
+ const res = parser.parse();
352
+ return parser.formatToTypeScript(res, namespace);
353
+ };
354
+
355
+ // core.ts
356
+ var DEFAULT_CPP_BINDING_OUTPUT_FILE = "binding_qjs.h";
357
+ var DEFAULT_TS_DEFINITION_OUTPUT_FILE = "binding_types.d.ts";
358
+ var DEFAULT_QUICKJS_TYPES_PATH = "quickjs-types.txt";
359
+ var DEFAULT_NAME_FILTER = "breeze::js::";
360
+ function parseFunctionQualType(type) {
361
+ let State;
362
+ ((State2) => {
363
+ State2[State2["ReturnType"] = 0] = "ReturnType";
364
+ State2[State2["Args"] = 1] = "Args";
365
+ State2[State2["Done"] = 2] = "Done";
366
+ })(State || (State = {}));
367
+ let state = 0 /* ReturnType */;
368
+ let returnType = "";
369
+ let currentArg = "";
370
+ let args = [];
371
+ let depth = 0;
372
+ let angleBracketDepth = 0;
373
+ for (let i = 0; i < type.length; i++) {
374
+ const char = type[i];
375
+ if (char === "<") angleBracketDepth++;
376
+ else if (char === ">") angleBracketDepth--;
377
+ switch (state) {
378
+ case 0 /* ReturnType */:
379
+ if (char === "(" && angleBracketDepth === 0) {
380
+ state = 1 /* Args */;
381
+ returnType = returnType.trim();
382
+ } else {
383
+ returnType += char;
384
+ }
385
+ break;
386
+ case 1 /* Args */:
387
+ if (char === "(") depth++;
388
+ if (char === ")") {
389
+ if (depth === 0 && angleBracketDepth === 0) {
390
+ if (currentArg.trim()) args.push(currentArg.trim());
391
+ state = 2 /* Done */;
392
+ break;
393
+ }
394
+ depth--;
395
+ }
396
+ if (char === "," && depth === 0 && angleBracketDepth === 0) {
397
+ args.push(currentArg.trim());
398
+ currentArg = "";
399
+ } else {
400
+ currentArg += char;
401
+ }
402
+ break;
403
+ }
404
+ }
405
+ if (state !== 2 /* Done */) throw new Error("Invalid function type");
406
+ return { returnType, args };
407
+ }
408
+ function processAstAndGenerateCode(astArr, originalCppFilePath, bindgenDir, nameFilter, quickjsTypesPath) {
409
+ const origFileContent = readFileSync(originalCppFilePath, "utf-8").split("\n").map((v) => v.trim());
410
+ const structNames = [];
411
+ const resolveUnderPath = (path, resolveName) => {
412
+ const ns = path.join("::");
413
+ const fullName = `${ns}::${resolveName}`;
414
+ if (structNames.includes(fullName)) return fullName;
415
+ if (path.length > 1) {
416
+ const parentPath = path.slice(0, -1);
417
+ const parentFullName = resolveUnderPath(parentPath, resolveName);
418
+ if (parentFullName) return parentFullName;
419
+ }
420
+ return resolveName;
421
+ };
422
+ const ctypeToQualified = (type, path) => {
423
+ const parser = new CTypeParser();
424
+ const parsed = parser.parse(type, (name) => resolveUnderPath(path, name));
425
+ return parser.formatToC(parsed);
426
+ };
427
+ let binding = `// This file is generated by bindgen
428
+ // Do not modify this file manually!
429
+
430
+ #pragma once
431
+ #include "binding_types.h" // Assuming this will be in the same output directory
432
+ #include "quickjs.h"
433
+ #include "quickjspp.hpp"
434
+
435
+ template <typename T>
436
+ struct js_bind {
437
+ static void bind(qjs::Context::Module &mod) {}
438
+ };
439
+ `;
440
+ let typescriptDef = `// This file is generated by bindgen
441
+ // Do not modify this file manually!
442
+
443
+ declare module 'mshell' { // TODO: Make module name configurable or derive
444
+ `;
445
+ const generateForRecordDecl = (node_struct, path) => {
446
+ if (node_struct.kind !== "CXXRecordDecl") throw new Error("Node is not a RecordDecl");
447
+ const structName = node_struct.name;
448
+ const fields = [];
449
+ const methods = [];
450
+ const bases = node_struct.bases?.filter((base) => !base.type.qualType.includes("std::")).map((base) => ({
451
+ access: base.access,
452
+ type: ctypeToQualified(base.type.qualType, path)
453
+ })) || [];
454
+ if (!node_struct.inner) return;
455
+ for (const node of node_struct.inner) {
456
+ if (node.name?.startsWith("$")) continue;
457
+ const lineNum = node.loc?.line;
458
+ let comment = "";
459
+ if (lineNum) {
460
+ let rangeCommentCnt = 0;
461
+ for (let i = lineNum - 2; i >= 0; i--) {
462
+ const line = origFileContent[i];
463
+ if (!line) continue;
464
+ if (line.startsWith("//")) {
465
+ comment = line.substring(2) + "\n" + comment;
466
+ continue;
467
+ }
468
+ if (line.startsWith("/*")) rangeCommentCnt++;
469
+ if (line.endsWith("*/")) rangeCommentCnt--;
470
+ if (rangeCommentCnt === 0 && (line.startsWith("/*") || line.endsWith("*/"))) {
471
+ if (line.startsWith("/*") && line.endsWith("*/")) {
472
+ comment = line.substring(2, line.length - 2) + "\n" + comment;
473
+ } else if (line.startsWith("/*")) {
474
+ } else if (line.endsWith("*/")) {
475
+ comment = line.substring(0, line.length - 2) + "\n" + comment;
476
+ }
477
+ break;
478
+ } else if (rangeCommentCnt > 0 || line.endsWith("*/")) {
479
+ comment = line.replaceAll("/*", "").replaceAll("*/", "*") + "\n" + comment;
480
+ } else if (rangeCommentCnt === 0 && !line.startsWith("//") && !line.startsWith("/*") && !line.endsWith("*/")) {
481
+ break;
482
+ }
483
+ }
484
+ }
485
+ comment = comment.trim();
486
+ if (node.kind === "FieldDecl") {
487
+ fields.push({
488
+ name: node.name,
489
+ type: ctypeToQualified(node.type.qualType, path),
490
+ comment: comment.length > 0 ? comment : void 0
491
+ });
492
+ }
493
+ if (node.kind === "CXXMethodDecl") {
494
+ const parsed = parseFunctionQualType(node.type.qualType);
495
+ if (["operator="].includes(node.name)) continue;
496
+ const argNames = [];
497
+ if (node.inner) {
498
+ for (const arg of node.inner) {
499
+ if (arg.kind === "ParmVarDecl") argNames.push(arg.name);
500
+ }
501
+ }
502
+ methods.push({
503
+ name: node.name,
504
+ returnType: ctypeToQualified(parsed.returnType, path),
505
+ args: parsed.args.map((arg) => ctypeToQualified(arg, path)),
506
+ static: node.storageClass === "static",
507
+ comment: comment.length > 0 ? comment : void 0,
508
+ argNames
509
+ });
510
+ }
511
+ }
512
+ const fullName = path.join("::") + "::" + structName;
513
+ if (bases.length === 0) {
514
+ binding += `
515
+ template <> struct qjs::js_traits<${fullName}> {
516
+ static ${fullName} unwrap(JSContext *ctx, JSValueConst v) {
517
+ ${fullName} obj;
518
+ `;
519
+ for (const field of fields) {
520
+ binding += `
521
+ obj.${field.name} = js_traits<${field.type}>::unwrap(ctx, JS_GetPropertyStr(ctx, v, "${field.name}"));
522
+ `;
523
+ }
524
+ binding += `
525
+ return obj;
526
+ }
527
+
528
+ static JSValue wrap(JSContext *ctx, const ${fullName} &val) noexcept {
529
+ JSValue obj = JS_NewObject(ctx);
530
+ `;
531
+ for (const field of fields) {
532
+ binding += `
533
+ JS_SetPropertyStr(ctx, obj, "${field.name}", js_traits<${field.type}>::wrap(ctx, val.${field.name}));
534
+ `;
535
+ }
536
+ binding += `
537
+ return obj;
538
+ }
539
+ };`;
540
+ }
541
+ const jsNamespaceName = fullName.replace(nameFilter, "");
542
+ binding += `
543
+ template<> struct js_bind<${fullName}> {
544
+ static void bind(qjs::Context::Module &mod) {
545
+ mod.class_<${fullName}>("${jsNamespaceName}")
546
+ .constructor<>()`;
547
+ if (bases.length > 0) {
548
+ binding += `
549
+ .base<${bases[0].type}>()`;
550
+ }
551
+ for (const method of methods) {
552
+ binding += `
553
+ .${method.static ? "static_" : ""}fun<&${fullName}::${method.name}>("${method.name}")`;
554
+ }
555
+ for (const field of fields) {
556
+ binding += `
557
+ .property<&${fullName}::${field.name}>("${field.name}")`;
558
+ }
559
+ binding += `
560
+ ;
561
+ }
562
+ };
563
+ `;
564
+ const tsNamespaceParts = jsNamespaceName.split("::");
565
+ const tsClassName = tsNamespaceParts.pop() || structName;
566
+ const tsNamespace = tsNamespaceParts.join(".");
567
+ if (tsNamespace) typescriptDef += `
568
+ namespace ${tsNamespace} {`;
569
+ typescriptDef += `
570
+ export class ${tsClassName}${bases.length > 0 ? ` extends ${bases.map((base) => base.type.split("::").pop() ?? base.type).join(", ")}` : ""} {`;
571
+ fields.forEach((field) => {
572
+ let fieldDef = `${field.name}${field.type.startsWith("std::optional") ? "?" : ""}: ${cTypeToTypeScript(field.type, nameFilter)}`;
573
+ if (field.comment) {
574
+ fieldDef = `
575
+ /**
576
+ * ${field.comment.split("\n").join("\n * ")}
577
+ */
578
+ ${fieldDef}`;
579
+ }
580
+ typescriptDef += `
581
+ ${fieldDef.trim()}`;
582
+ });
583
+ methods.forEach((method) => {
584
+ let methodDef = `${method.static ? "static " : ""}${method.name}(${method.argNames && method.argNames.length > 0 ? method.args.map((arg, i) => `${method.argNames[i] || `arg${i}`}: ${cTypeToTypeScript(arg, nameFilter)}`).join(", ") : ""}): ${cTypeToTypeScript(method.returnType, nameFilter)}`;
585
+ let comments = "";
586
+ if (method.comment) comments += method.comment;
587
+ if (comments || method.argNames && method.argNames.length > 0) {
588
+ methodDef = `
589
+ /**
590
+ * ${comments.split("\n").join("\n * ")}
591
+ ${method.argNames && method.argNames.length > 0 ? `* @param ${method.args.map((arg, i) => `${method.argNames[i] || `arg${i}`}${cTypeToTypeScript(arg, nameFilter) === "any" ? "" : `: ${cTypeToTypeScript(arg, nameFilter)}`}`).join("\n * @param ")}
592
+ *` : ""} @returns ${cTypeToTypeScript(method.returnType, nameFilter)}
593
+ */
594
+ ${methodDef}`;
595
+ }
596
+ typescriptDef += `
597
+ ${methodDef.trim()}`;
598
+ });
599
+ typescriptDef += `
600
+ }`;
601
+ if (tsNamespace) typescriptDef += `
602
+ }`;
603
+ };
604
+ const enumerateStructDecls = (node, callback, path = ["breeze"]) => {
605
+ if (node.kind === "CXXRecordDecl" && node.name && node.inner) {
606
+ callback(node, path);
607
+ }
608
+ if (node.inner) {
609
+ for (const child of node.inner) {
610
+ enumerateStructDecls(child, callback, [...path, node.name || ""]);
611
+ }
612
+ }
613
+ };
614
+ for (const ast of astArr) {
615
+ enumerateStructDecls(ast, (node, path) => {
616
+ if (node.name) structNames.push(path.join("::") + "::" + node.name);
617
+ });
618
+ }
619
+ for (const ast of astArr) {
620
+ enumerateStructDecls(ast, (node, path) => {
621
+ if (node.kind === "CXXRecordDecl" && node.name) generateForRecordDecl(node, path);
622
+ });
623
+ }
624
+ binding += `
625
+ inline void bindAll(qjs::Context::Module &mod) {
626
+ `;
627
+ for (const structName of structNames) {
628
+ binding += `
629
+ js_bind<${structName}>::bind(mod);
630
+ `;
631
+ }
632
+ binding += `
633
+ }
634
+ `;
635
+ typescriptDef += `
636
+ }
637
+ `;
638
+ const quickjsTypesContent = readFileSync(join(bindgenDir, quickjsTypesPath), "utf-8");
639
+ typescriptDef += "\n" + quickjsTypesContent;
640
+ return { cppBinding: binding, tsDefinitions: typescriptDef };
641
+ }
642
+ function generateBindingsAndDefinitions(config) {
643
+ const {
644
+ cppFilePath,
645
+ outputDir,
646
+ clangPath = "clang++",
647
+ cppBindingOutputFile = DEFAULT_CPP_BINDING_OUTPUT_FILE,
648
+ tsDefinitionOutputFile = DEFAULT_TS_DEFINITION_OUTPUT_FILE,
649
+ quickjsTypesPath = DEFAULT_QUICKJS_TYPES_PATH,
650
+ nameFilter = DEFAULT_NAME_FILTER
651
+ } = config;
652
+ const absoluteCppFilePath = resolvePath(cppFilePath);
653
+ const absoluteOutputDir = resolvePath(outputDir);
654
+ const currentFilePath = fileURLToPath(import.meta.url);
655
+ const bindgenDir = dirname(currentFilePath);
656
+ const clangArgs = [
657
+ "-Xclang",
658
+ "-ast-dump=json",
659
+ "-fsyntax-only",
660
+ "-Xclang",
661
+ `-ast-dump-filter=${nameFilter.slice(0, -2)}`,
662
+ // Use parameter
663
+ "-std=c++2c",
664
+ // or c++20, c++17 as appropriate
665
+ // Add any include paths if necessary, e.g. -I../../include
666
+ absoluteCppFilePath
667
+ ];
668
+ (0, import_fancy_log.default)(`Executing: ${clangPath} ${clangArgs.join(" ")}`);
669
+ const clangProcess = spawnSync(clangPath, clangArgs, { encoding: "utf-8", shell: true });
670
+ if (clangProcess.error) {
671
+ import_fancy_log.default.error(`Failed to start clang++: ${clangProcess.error.message}`);
672
+ if (clangProcess.error.code === "ENOENT") {
673
+ throw new Error(`clang++ not found at path "${clangPath}". Please ensure it's installed and in your PATH, or provide a correct path.`);
674
+ }
675
+ throw clangProcess.error;
676
+ }
677
+ if (clangProcess.stderr && clangProcess.stderr.length > 0) {
678
+ import_fancy_log.default.warn(`clang++ stderr:
679
+ ${clangProcess.stderr}`);
680
+ }
681
+ if (!clangProcess.stdout || clangProcess.stdout.trim().length === 0) {
682
+ throw new Error(`clang++ produced no output (stdout). AST generation failed. Error: ${clangProcess.stderr}`);
683
+ }
684
+ let astText = clangProcess.stdout;
685
+ if (!astText.trim().startsWith("[")) {
686
+ astText = "[" + astText.trim().replace(/}\s*{/g, "},{") + "]";
687
+ }
688
+ let astArr;
689
+ try {
690
+ astArr = JSON.parse(astText);
691
+ } catch (e) {
692
+ import_fancy_log.default.error("Failed to parse AST JSON:", e);
693
+ import_fancy_log.default.error("Problematic AST JSON content (first 1000 chars):", astText.substring(0, 1e3));
694
+ throw new Error(`Failed to parse AST JSON from clang++. Check for errors in C++ code or clang++ execution.`);
695
+ }
696
+ if (!astArr || astArr.length === 0) {
697
+ import_fancy_log.default.warn(`No AST data was parsed. This might mean the ast-dump-filter ("${nameFilter.slice(0, -2)}") didn't match anything, or the input file is empty or has no relevant declarations.`);
698
+ }
699
+ const { cppBinding, tsDefinitions } = processAstAndGenerateCode(astArr, absoluteCppFilePath, bindgenDir, nameFilter, quickjsTypesPath);
700
+ if (!existsSync(absoluteOutputDir)) {
701
+ try {
702
+ mkdirSync(absoluteOutputDir, { recursive: true });
703
+ } catch (e) {
704
+ throw new Error(`Failed to create output directory ${absoluteOutputDir}: ${e.message}`);
705
+ }
706
+ }
707
+ writeFileSync(join(absoluteOutputDir, cppBindingOutputFile), cppBinding);
708
+ writeFileSync(join(absoluteOutputDir, tsDefinitionOutputFile), tsDefinitions);
709
+ (0, import_fancy_log.default)(`Bindings generated successfully in ${absoluteOutputDir}`);
710
+ }
711
+
712
+ // index.ts
713
+ import { join as joinPath, dirname as pathDirname } from "node:path";
714
+ import { fileURLToPath as fileURLToPath2 } from "node:url";
715
+ async function runDefaultGeneration() {
716
+ try {
717
+ const currentFilePath = fileURLToPath2(import.meta.url);
718
+ const bindgenDir = pathDirname(currentFilePath);
719
+ const defaultInputFile = joinPath(bindgenDir, "../src/breeze-js/binding_types.h");
720
+ const defaultOutputDir = joinPath(bindgenDir, "../src/breeze-js/");
721
+ (0, import_fancy_log2.default)(`Running default binding generation...`);
722
+ (0, import_fancy_log2.default)(`Input C++ file: ${defaultInputFile}`);
723
+ (0, import_fancy_log2.default)(`Output directory: ${defaultOutputDir}`);
724
+ generateBindingsAndDefinitions({
725
+ cppFilePath: defaultInputFile,
726
+ outputDir: defaultOutputDir
727
+ });
728
+ (0, import_fancy_log2.default)("Default binding generation finished successfully.");
729
+ } catch (error) {
730
+ import_fancy_log2.default.error("Error during default binding generation:", error.message);
731
+ if (error.stack && process.env.DEBUG) {
732
+ import_fancy_log2.default.error(error.stack);
733
+ }
734
+ process.exit(1);
735
+ }
736
+ }
737
+ runDefaultGeneration();