breeze-bindgen 1.0.2 → 1.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/core.mjs ADDED
@@ -0,0 +1,705 @@
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 log2() {
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 = log2;
211
+ module.exports.info = info;
212
+ module.exports.dir = dir;
213
+ module.exports.warn = warn;
214
+ module.exports.error = error;
215
+ }
216
+ });
217
+
218
+ // core.ts
219
+ var import_fancy_log = __toESM(require_fancy_log());
220
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
221
+ import { join, dirname, resolve as resolvePath } from "node:path";
222
+ import { fileURLToPath } from "node:url";
223
+ import { spawnSync } from "node:child_process";
224
+
225
+ // c-type-parser.ts
226
+ var CTypeParser = class {
227
+ tokens = [];
228
+ cursor = 0;
229
+ lex(str) {
230
+ this.tokens = [];
231
+ let current = "";
232
+ const BREAK_TOKENS = [" ", "(", ")", ",", "<", ">"];
233
+ for (let i = 0; i < str.length; i++) {
234
+ const c = str[i];
235
+ if (BREAK_TOKENS.includes(c)) {
236
+ if (current.length > 0) {
237
+ this.tokens.push(current);
238
+ current = "";
239
+ }
240
+ if (c !== " ") {
241
+ this.tokens.push(c);
242
+ }
243
+ } else {
244
+ current += c;
245
+ }
246
+ }
247
+ if (current.length > 0) {
248
+ this.tokens.push(current);
249
+ }
250
+ }
251
+ parse(str = null, typeTransformer = (orig) => orig) {
252
+ if (str) {
253
+ this.lex(str);
254
+ this.cursor = 0;
255
+ }
256
+ const type = {
257
+ argsFunc: [],
258
+ argsTemplate: [],
259
+ function: false,
260
+ template: false,
261
+ type: ""
262
+ };
263
+ do {
264
+ const parseCommaList = (arr) => {
265
+ do {
266
+ const res = this.parse(null, typeTransformer);
267
+ if (res)
268
+ arr.push(res);
269
+ } while (this.eat(","));
270
+ };
271
+ if (this.eat("(")) {
272
+ type.function = true;
273
+ if (!this.next(")"))
274
+ parseCommaList(type.argsFunc);
275
+ this.eat(")", true);
276
+ } else if (this.eat("<")) {
277
+ type.template = true;
278
+ if (!this.next(">"))
279
+ parseCommaList(type.argsTemplate);
280
+ this.eat(">", true);
281
+ } else {
282
+ type.type = typeTransformer(this.tokens[this.cursor]);
283
+ this.cursor++;
284
+ }
285
+ if (this.next("(") || this.next("<")) {
286
+ continue;
287
+ }
288
+ break;
289
+ } while (true);
290
+ return type;
291
+ }
292
+ eat(token, force = false) {
293
+ if (this.next(token)) {
294
+ this.cursor++;
295
+ return true;
296
+ } else {
297
+ if (force) throw new Error(`Excepted: ${token}, found ${this.next()} in ${this.tokens.join(" ")}`);
298
+ }
299
+ return false;
300
+ }
301
+ next(token = null) {
302
+ if (this.tokens[this.cursor] === token || !token) {
303
+ return this.tokens[this.cursor];
304
+ }
305
+ return false;
306
+ }
307
+ formatToC(node) {
308
+ let str = node.type;
309
+ if (node.template) {
310
+ str += "<" + node.argsTemplate.map((a) => this.formatToC(a)).join(", ") + ">";
311
+ }
312
+ if (node.function) {
313
+ str += "(" + node.argsFunc.map((a) => this.formatToC(a)).join(", ") + ")";
314
+ }
315
+ return str;
316
+ }
317
+ formatToTypeScript(node, namespace = "") {
318
+ if (node.type.startsWith(namespace))
319
+ node.type = node.type.slice(namespace.length);
320
+ node.type = node.type.split("::").filter(Boolean).join(".");
321
+ const typeMap = {
322
+ "int": "number",
323
+ "float": "number",
324
+ "double": "number",
325
+ "std.string": "string",
326
+ "std.vector": "Array",
327
+ "bool": "boolean"
328
+ };
329
+ let tsBasicType = (typeMap[node.type] ?? node.type) + (node.template ? "<" + node.argsTemplate.map((a) => this.formatToTypeScript(a, namespace)).join(", ") + ">" : "");
330
+ const ignoreTypes = ["std.variant", "std.shared_ptr", "std.function"];
331
+ if (ignoreTypes.includes(node.type)) {
332
+ tsBasicType = node.argsTemplate.map((a) => this.formatToTypeScript(a, namespace)).join(" | ");
333
+ } else if (node.type === "std.optional") {
334
+ tsBasicType = `${this.formatToTypeScript(node.argsTemplate[0], namespace)} | undefined`;
335
+ } else if (node.type === "std.pair" || node.type === "std.tuple") {
336
+ tsBasicType = node.argsTemplate.map((a) => this.formatToTypeScript(a, namespace)).join(", ");
337
+ tsBasicType = `[${tsBasicType}]`;
338
+ }
339
+ if (node.function) {
340
+ return `((${node.argsFunc.map((a) => this.formatToTypeScript(a, namespace)).map((v, i) => `arg${i + 1}: ${v}`).join(", ")}) => ${tsBasicType})`;
341
+ }
342
+ return tsBasicType;
343
+ }
344
+ };
345
+ var cTypeToTypeScript = (str, namespace) => {
346
+ const parser = new CTypeParser();
347
+ parser.lex(str);
348
+ const res = parser.parse();
349
+ return parser.formatToTypeScript(res, namespace);
350
+ };
351
+
352
+ // core.ts
353
+ var DEFAULT_CPP_BINDING_OUTPUT_FILE = "binding_qjs.h";
354
+ var DEFAULT_TS_DEFINITION_OUTPUT_FILE = "binding_types.d.ts";
355
+ var DEFAULT_NAME_FILTER = "breeze::js::";
356
+ function parseFunctionQualType(type) {
357
+ let State;
358
+ ((State2) => {
359
+ State2[State2["ReturnType"] = 0] = "ReturnType";
360
+ State2[State2["Args"] = 1] = "Args";
361
+ State2[State2["Done"] = 2] = "Done";
362
+ })(State || (State = {}));
363
+ let state = 0 /* ReturnType */;
364
+ let returnType = "";
365
+ let currentArg = "";
366
+ let args = [];
367
+ let depth = 0;
368
+ let angleBracketDepth = 0;
369
+ for (let i = 0; i < type.length; i++) {
370
+ const char = type[i];
371
+ if (char === "<") angleBracketDepth++;
372
+ else if (char === ">") angleBracketDepth--;
373
+ switch (state) {
374
+ case 0 /* ReturnType */:
375
+ if (char === "(" && angleBracketDepth === 0) {
376
+ state = 1 /* Args */;
377
+ returnType = returnType.trim();
378
+ } else {
379
+ returnType += char;
380
+ }
381
+ break;
382
+ case 1 /* Args */:
383
+ if (char === "(") depth++;
384
+ if (char === ")") {
385
+ if (depth === 0 && angleBracketDepth === 0) {
386
+ if (currentArg.trim()) args.push(currentArg.trim());
387
+ state = 2 /* Done */;
388
+ break;
389
+ }
390
+ depth--;
391
+ }
392
+ if (char === "," && depth === 0 && angleBracketDepth === 0) {
393
+ args.push(currentArg.trim());
394
+ currentArg = "";
395
+ } else {
396
+ currentArg += char;
397
+ }
398
+ break;
399
+ }
400
+ }
401
+ if (state !== 2 /* Done */) throw new Error("Invalid function type");
402
+ return { returnType, args };
403
+ }
404
+ function processAstAndGenerateCode(astArr, originalCppFilePath, nameFilter, additionalTypes) {
405
+ const origFileContent = readFileSync(originalCppFilePath, "utf-8").split("\n").map((v) => v.trim());
406
+ const structNames = [];
407
+ const resolveUnderPath = (path, resolveName) => {
408
+ const ns = path.join("::");
409
+ const fullName = `${ns}::${resolveName}`;
410
+ if (structNames.includes(fullName)) return fullName;
411
+ if (path.length > 1) {
412
+ const parentPath = path.slice(0, -1);
413
+ const parentFullName = resolveUnderPath(parentPath, resolveName);
414
+ if (parentFullName) return parentFullName;
415
+ }
416
+ return resolveName;
417
+ };
418
+ const ctypeToQualified = (type, path) => {
419
+ const parser = new CTypeParser();
420
+ const parsed = parser.parse(type, (name) => resolveUnderPath(path, name));
421
+ return parser.formatToC(parsed);
422
+ };
423
+ let binding = `// This file is generated by bindgen
424
+ // Do not modify this file manually!
425
+
426
+ #pragma once
427
+ #include "binding_types.h" // Assuming this will be in the same output directory
428
+ #include "quickjs.h"
429
+ #include "quickjspp.hpp"
430
+
431
+ template <typename T>
432
+ struct js_bind {
433
+ static void bind(qjs::Context::Module &mod) {}
434
+ };
435
+ `;
436
+ let typescriptDef = `// This file is generated by bindgen
437
+ // Do not modify this file manually!
438
+
439
+ declare module 'mshell' { // TODO: Make module name configurable or derive
440
+ `;
441
+ const generateForRecordDecl = (node_struct, path) => {
442
+ if (node_struct.kind !== "CXXRecordDecl") throw new Error("Node is not a RecordDecl");
443
+ const structName = node_struct.name;
444
+ const fields = [];
445
+ const methods = [];
446
+ const bases = node_struct.bases?.filter((base) => !base.type.qualType.includes("std::")).map((base) => ({
447
+ access: base.access,
448
+ type: ctypeToQualified(base.type.qualType, path)
449
+ })) || [];
450
+ if (!node_struct.inner) return;
451
+ for (const node of node_struct.inner) {
452
+ if (node.name?.startsWith("$")) continue;
453
+ const lineNum = node.loc?.line;
454
+ let comment = "";
455
+ if (lineNum) {
456
+ let rangeCommentCnt = 0;
457
+ for (let i = lineNum - 2; i >= 0; i--) {
458
+ const line = origFileContent[i];
459
+ if (!line) continue;
460
+ if (line.startsWith("//")) {
461
+ comment = line.substring(2) + "\n" + comment;
462
+ continue;
463
+ }
464
+ if (line.startsWith("/*")) rangeCommentCnt++;
465
+ if (line.endsWith("*/")) rangeCommentCnt--;
466
+ if (rangeCommentCnt === 0 && (line.startsWith("/*") || line.endsWith("*/"))) {
467
+ if (line.startsWith("/*") && line.endsWith("*/")) {
468
+ comment = line.substring(2, line.length - 2) + "\n" + comment;
469
+ } else if (line.startsWith("/*")) {
470
+ } else if (line.endsWith("*/")) {
471
+ comment = line.substring(0, line.length - 2) + "\n" + comment;
472
+ }
473
+ break;
474
+ } else if (rangeCommentCnt > 0 || line.endsWith("*/")) {
475
+ comment = line.replaceAll("/*", "").replaceAll("*/", "*") + "\n" + comment;
476
+ } else if (rangeCommentCnt === 0 && !line.startsWith("//") && !line.startsWith("/*") && !line.endsWith("*/")) {
477
+ break;
478
+ }
479
+ }
480
+ }
481
+ comment = comment.trim();
482
+ if (node.kind === "FieldDecl") {
483
+ fields.push({
484
+ name: node.name,
485
+ type: ctypeToQualified(node.type.qualType, path),
486
+ comment: comment.length > 0 ? comment : void 0
487
+ });
488
+ }
489
+ if (node.kind === "CXXMethodDecl") {
490
+ const parsed = parseFunctionQualType(node.type.qualType);
491
+ if (["operator="].includes(node.name)) continue;
492
+ const argNames = [];
493
+ if (node.inner) {
494
+ for (const arg of node.inner) {
495
+ if (arg.kind === "ParmVarDecl") argNames.push(arg.name);
496
+ }
497
+ }
498
+ methods.push({
499
+ name: node.name,
500
+ returnType: ctypeToQualified(parsed.returnType, path),
501
+ args: parsed.args.map((arg) => ctypeToQualified(arg, path)),
502
+ static: node.storageClass === "static",
503
+ comment: comment.length > 0 ? comment : void 0,
504
+ argNames
505
+ });
506
+ }
507
+ }
508
+ const fullName = path.join("::") + "::" + structName;
509
+ if (bases.length === 0) {
510
+ binding += `
511
+ template <> struct qjs::js_traits<${fullName}> {
512
+ static ${fullName} unwrap(JSContext *ctx, JSValueConst v) {
513
+ ${fullName} obj;
514
+ `;
515
+ for (const field of fields) {
516
+ binding += `
517
+ obj.${field.name} = js_traits<${field.type}>::unwrap(ctx, JS_GetPropertyStr(ctx, v, "${field.name}"));
518
+ `;
519
+ }
520
+ binding += `
521
+ return obj;
522
+ }
523
+
524
+ static JSValue wrap(JSContext *ctx, const ${fullName} &val) noexcept {
525
+ JSValue obj = JS_NewObject(ctx);
526
+ `;
527
+ for (const field of fields) {
528
+ binding += `
529
+ JS_SetPropertyStr(ctx, obj, "${field.name}", js_traits<${field.type}>::wrap(ctx, val.${field.name}));
530
+ `;
531
+ }
532
+ binding += `
533
+ return obj;
534
+ }
535
+ };`;
536
+ }
537
+ const jsNamespaceName = fullName.replace(nameFilter, "");
538
+ binding += `
539
+ template<> struct js_bind<${fullName}> {
540
+ static void bind(qjs::Context::Module &mod) {
541
+ mod.class_<${fullName}>("${jsNamespaceName}")
542
+ .constructor<>()`;
543
+ if (bases.length > 0) {
544
+ binding += `
545
+ .base<${bases[0].type}>()`;
546
+ }
547
+ for (const method of methods) {
548
+ binding += `
549
+ .${method.static ? "static_" : ""}fun<&${fullName}::${method.name}>("${method.name}")`;
550
+ }
551
+ for (const field of fields) {
552
+ binding += `
553
+ .property<&${fullName}::${field.name}>("${field.name}")`;
554
+ }
555
+ binding += `
556
+ ;
557
+ }
558
+ };
559
+ `;
560
+ const tsNamespaceParts = jsNamespaceName.split("::");
561
+ const tsClassName = tsNamespaceParts.pop() || structName;
562
+ const tsNamespace = tsNamespaceParts.join(".");
563
+ if (tsNamespace) typescriptDef += `
564
+ namespace ${tsNamespace} {`;
565
+ typescriptDef += `
566
+ export class ${tsClassName}${bases.length > 0 ? ` extends ${bases.map((base) => base.type.split("::").pop() ?? base.type).join(", ")}` : ""} {`;
567
+ fields.forEach((field) => {
568
+ let fieldDef = `${field.name}${field.type.startsWith("std::optional") ? "?" : ""}: ${cTypeToTypeScript(field.type, nameFilter)}`;
569
+ if (field.comment) {
570
+ fieldDef = `
571
+ /**
572
+ * ${field.comment.split("\n").join("\n * ")}
573
+ */
574
+ ${fieldDef}`;
575
+ }
576
+ typescriptDef += `
577
+ ${fieldDef.trim()}`;
578
+ });
579
+ methods.forEach((method) => {
580
+ 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)}`;
581
+ let comments = "";
582
+ if (method.comment) comments += method.comment;
583
+ if (comments || method.argNames && method.argNames.length > 0) {
584
+ methodDef = `
585
+ /**
586
+ * ${comments.split("\n").join("\n * ")}
587
+ ${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 ")}
588
+ *` : ""} @returns ${cTypeToTypeScript(method.returnType, nameFilter)}
589
+ */
590
+ ${methodDef}`;
591
+ }
592
+ typescriptDef += `
593
+ ${methodDef.trim()}`;
594
+ });
595
+ typescriptDef += `
596
+ }`;
597
+ if (tsNamespace) typescriptDef += `
598
+ }`;
599
+ };
600
+ const enumerateStructDecls = (node, callback, path = ["breeze"]) => {
601
+ if (node.kind === "CXXRecordDecl" && node.name && node.inner) {
602
+ callback(node, path);
603
+ }
604
+ if (node.inner) {
605
+ for (const child of node.inner) {
606
+ enumerateStructDecls(child, callback, [...path, node.name || ""]);
607
+ }
608
+ }
609
+ };
610
+ for (const ast of astArr) {
611
+ enumerateStructDecls(ast, (node, path) => {
612
+ if (node.name) structNames.push(path.join("::") + "::" + node.name);
613
+ });
614
+ }
615
+ for (const ast of astArr) {
616
+ enumerateStructDecls(ast, (node, path) => {
617
+ if (node.kind === "CXXRecordDecl" && node.name) generateForRecordDecl(node, path);
618
+ });
619
+ }
620
+ binding += `
621
+ inline void bindAll(qjs::Context::Module &mod) {
622
+ `;
623
+ for (const structName of structNames) {
624
+ binding += `
625
+ js_bind<${structName}>::bind(mod);
626
+ `;
627
+ }
628
+ binding += `
629
+ }
630
+ `;
631
+ typescriptDef += `
632
+ }
633
+ `;
634
+ typescriptDef += "\n" + additionalTypes;
635
+ return { cppBinding: binding, tsDefinitions: typescriptDef };
636
+ }
637
+ function generateBindingsAndDefinitions(config) {
638
+ const {
639
+ cppFilePath,
640
+ outputDir,
641
+ clangPath = "clang++",
642
+ cppBindingOutputFile = DEFAULT_CPP_BINDING_OUTPUT_FILE,
643
+ tsDefinitionOutputFile = DEFAULT_TS_DEFINITION_OUTPUT_FILE,
644
+ additionalTypes = "",
645
+ nameFilter = DEFAULT_NAME_FILTER
646
+ } = config;
647
+ const absoluteCppFilePath = resolvePath(cppFilePath);
648
+ const absoluteOutputDir = resolvePath(outputDir);
649
+ const currentFilePath = fileURLToPath(import.meta.url);
650
+ const bindgenDir = dirname(currentFilePath);
651
+ const clangArgs = [
652
+ "-Xclang",
653
+ "-ast-dump=json",
654
+ "-fsyntax-only",
655
+ "-Xclang",
656
+ `-ast-dump-filter=${nameFilter.slice(0, -2)}`,
657
+ "-std=c++2c",
658
+ absoluteCppFilePath
659
+ ];
660
+ (0, import_fancy_log.default)(`Executing: ${clangPath} ${clangArgs.join(" ")}`);
661
+ const clangProcess = spawnSync(clangPath, clangArgs, { encoding: "utf-8", shell: true });
662
+ if (clangProcess.error) {
663
+ import_fancy_log.default.error(`Failed to start clang++: ${clangProcess.error.message}`);
664
+ if (clangProcess.error.code === "ENOENT") {
665
+ throw new Error(`clang++ not found at path "${clangPath}". Please ensure it's installed and in your PATH, or provide a correct path.`);
666
+ }
667
+ throw clangProcess.error;
668
+ }
669
+ if (clangProcess.stderr && clangProcess.stderr.length > 0) {
670
+ import_fancy_log.default.warn(`clang++ stderr:
671
+ ${clangProcess.stderr}`);
672
+ }
673
+ if (!clangProcess.stdout || clangProcess.stdout.trim().length === 0) {
674
+ throw new Error(`clang++ produced no output (stdout). AST generation failed. Error: ${clangProcess.stderr}`);
675
+ }
676
+ let astText = clangProcess.stdout;
677
+ if (!astText.trim().startsWith("[")) {
678
+ astText = "[" + astText.trim().replace(/}\s*{/g, "},{") + "]";
679
+ }
680
+ let astArr;
681
+ try {
682
+ astArr = JSON.parse(astText);
683
+ } catch (e) {
684
+ import_fancy_log.default.error("Failed to parse AST JSON:", e);
685
+ import_fancy_log.default.error("Problematic AST JSON content (first 1000 chars):", astText.substring(0, 1e3));
686
+ throw new Error(`Failed to parse AST JSON from clang++. Check for errors in C++ code or clang++ execution.`);
687
+ }
688
+ if (!astArr || astArr.length === 0) {
689
+ 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.`);
690
+ }
691
+ const { cppBinding, tsDefinitions } = processAstAndGenerateCode(astArr, absoluteCppFilePath, nameFilter, additionalTypes);
692
+ if (!existsSync(absoluteOutputDir)) {
693
+ try {
694
+ mkdirSync(absoluteOutputDir, { recursive: true });
695
+ } catch (e) {
696
+ throw new Error(`Failed to create output directory ${absoluteOutputDir}: ${e.message}`);
697
+ }
698
+ }
699
+ writeFileSync(join(absoluteOutputDir, cppBindingOutputFile), cppBinding);
700
+ writeFileSync(join(absoluteOutputDir, tsDefinitionOutputFile), tsDefinitions);
701
+ (0, import_fancy_log.default)(`Bindings generated successfully in ${absoluteOutputDir}`);
702
+ }
703
+ export {
704
+ generateBindingsAndDefinitions
705
+ };