@xnoxs/flux-lang 4.0.1 → 4.0.3

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/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ---
9
9
 
10
+ ## [4.0.2] — 2026-06-28
11
+
12
+ ### Fixed
13
+ - **CLI test runner — `dist/transpiler.js` shim**: The `flux test` command
14
+ failed with `Cannot find module 'dist/transpiler.js'` when installed from npm.
15
+ The CLI resolves its own module directory at runtime (`__dirname` inside
16
+ `dist/flux-cli.js`), expecting a sibling `transpiler.js`. Added a permanent
17
+ compatibility shim (`dist/transpiler.js`) that re-exports the main CJS bundle,
18
+ so `flux test` works correctly out of the box after `npm install`.
19
+
20
+ ---
21
+
10
22
  ## [4.0.1] — 2026-06-28
11
23
 
12
24
  ### Fixed
package/dist/flux-cli.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  /*!
3
- * flux-lang v4.0.1
3
+ * flux-lang v4.0.3
4
4
  * Flux — A modern language that transpiles to JavaScript. Python-clean syntax, TypeScript-level safety, Rust-inspired pattern matching.
5
5
  * (c) 2026 Flux Lang Contributors
6
6
  * Released under the MIT License
@@ -349,7 +349,7 @@ var require_lexer = __commonJS({
349
349
  if (this.ch() === "\\") {
350
350
  this.adv();
351
351
  const e = this.adv();
352
- s += { n: "\n", t: " ", "`": "`", "\\": "\\" }[e] || "\\" + e;
352
+ s += { n: "\n", t: " ", "`": "`", "\\": "\\" }[e] || "\\" + e;
353
353
  } else {
354
354
  s += this.adv();
355
355
  }
@@ -385,7 +385,7 @@ var require_lexer = __commonJS({
385
385
  this.pos += 2;
386
386
  text += String.fromCharCode(parseInt(hex, 16));
387
387
  } else {
388
- text += { n: "\n", t: " ", r: "\r", '"': '"', "'": "'", "\\": "\\", "{": "{", "}": "}" }[e] || "\\" + e;
388
+ text += { n: "\n", t: " ", r: "\r", '"': '"', "'": "'", "\\": "\\", "{": "{", "}": "}" }[e] || "\\" + e;
389
389
  }
390
390
  } else if (this.ch() === "{") {
391
391
  parts.push({ type: "text", value: text });
@@ -473,8 +473,8 @@ var require_lexer = __commonJS({
473
473
  if (bol) {
474
474
  bol = false;
475
475
  let indent = 0;
476
- while (this.ch() === " " || this.ch() === " ") {
477
- indent += this.ch() === " " ? 4 : 1;
476
+ while (this.ch() === " " || this.ch() === " ") {
477
+ indent += this.ch() === " " ? 4 : 1;
478
478
  this.adv();
479
479
  }
480
480
  if (this.ch() === "\n" || !this.ch()) {
@@ -515,7 +515,7 @@ var require_lexer = __commonJS({
515
515
  }
516
516
  continue;
517
517
  }
518
- if (cur === " " || cur === " ") {
518
+ if (cur === " " || cur === " ") {
519
519
  this.adv();
520
520
  continue;
521
521
  }
@@ -590,7 +590,7 @@ var require_lexer = __commonJS({
590
590
  this.pos += 2;
591
591
  s += String.fromCharCode(parseInt(hex, 16));
592
592
  } else {
593
- s += { n: "\n", t: " ", r: "\r", "'": "'", "\\": "\\" }[e] || "\\" + e;
593
+ s += { n: "\n", t: " ", r: "\r", "'": "'", "\\": "\\" }[e] || "\\" + e;
594
594
  }
595
595
  } else {
596
596
  s += this.adv();
@@ -2652,6 +2652,7 @@ function _fmt(v, s) {
2652
2652
  this.smBuilder = opts.smBuilder || null;
2653
2653
  this._needsFmt = false;
2654
2654
  this._loopDepth = 0;
2655
+ this._fnDepth = 0;
2655
2656
  }
2656
2657
  i() {
2657
2658
  return this.ind.repeat(this.level);
@@ -2789,7 +2790,9 @@ function _fmt(v, s) {
2789
2790
  } else {
2790
2791
  this.emit(`${prefix}${asyncKw}function ${name}(${params}) {`);
2791
2792
  this.in();
2793
+ this._fnDepth++;
2792
2794
  for (const s of node.body) this.genStmt(s);
2795
+ this._fnDepth--;
2793
2796
  this.out();
2794
2797
  this.emit("}");
2795
2798
  }
@@ -2981,8 +2984,10 @@ function _fmt(v, s) {
2981
2984
  const exprSrc = this.genExpr(arm.body[0].expr);
2982
2985
  if (this._loopDepth > 0) {
2983
2986
  this.emit(`${exprSrc};`);
2984
- } else {
2987
+ } else if (this._fnDepth > 0) {
2985
2988
  this.emit(`return ${exprSrc};`);
2989
+ } else {
2990
+ this.emit(`${exprSrc};`);
2986
2991
  }
2987
2992
  } else {
2988
2993
  arm.body.forEach((s) => this.genStmt(s));
@@ -3231,11 +3236,13 @@ function _fmt(v, s) {
3231
3236
  const savedLevel = this.level;
3232
3237
  const savedLoopDepth = this._loopDepth;
3233
3238
  this._loopDepth = 0;
3239
+ this._fnDepth++;
3234
3240
  this.emit("(() => {");
3235
3241
  this.in();
3236
3242
  this.genMatch(node);
3237
3243
  this.out();
3238
3244
  this.emit("})()");
3245
+ this._fnDepth--;
3239
3246
  this._loopDepth = savedLoopDepth;
3240
3247
  const block = this.lines.splice(saved).map((l) => l.trimStart()).join(" ");
3241
3248
  this.level = savedLevel;
@@ -3569,7 +3576,7 @@ var require_jsx = __commonJS({
3569
3576
  const next = this.src[this.pos + 1] || "";
3570
3577
  if (!(next === ">" || next >= "a" && next <= "z" || next >= "A" && next <= "Z")) return false;
3571
3578
  let i = this.pos - 1;
3572
- while (i >= 0 && (this.src[i] === " " || this.src[i] === " ")) i--;
3579
+ while (i >= 0 && (this.src[i] === " " || this.src[i] === " ")) i--;
3573
3580
  if (i < 0) return true;
3574
3581
  const prev = this.src[i];
3575
3582
  if ("=([{,:>\n?".includes(prev)) return true;
@@ -3798,7 +3805,7 @@ var require_jsx = __commonJS({
3798
3805
  }
3799
3806
  // ── Skip whitespace (not newlines) ────────────────────────────
3800
3807
  skipWs() {
3801
- while (this.pos < this.src.length && (this.src[this.pos] === " " || this.src[this.pos] === " ")) this.pos++;
3808
+ while (this.pos < this.src.length && (this.src[this.pos] === " " || this.src[this.pos] === " ")) this.pos++;
3802
3809
  }
3803
3810
  };
3804
3811
  var FLUX_H_BROWSER = `
@@ -4622,7 +4629,7 @@ ${innerCss}${ind}}
4622
4629
  const charAfter = this.src[this.pos + 3] || "";
4623
4630
  if (!/[a-zA-Z0-9_]/.test(charBefore) && !/[a-zA-Z0-9_]/.test(charAfter)) {
4624
4631
  let j = this.pos + 3;
4625
- while (j < this.src.length && (this.src[j] === " " || this.src[j] === " " || this.src[j] === "\n" || this.src[j] === "\r")) j++;
4632
+ while (j < this.src.length && (this.src[j] === " " || this.src[j] === " " || this.src[j] === "\n" || this.src[j] === "\r")) j++;
4626
4633
  if (this.src[j] === "{") {
4627
4634
  j++;
4628
4635
  let depth = 1;
@@ -7255,12 +7262,10 @@ var require_bundler = __commonJS({
7255
7262
  }
7256
7263
  for (const imp of imports) {
7257
7264
  const srcId = toModuleId(imp.absPath);
7258
- if (imp.names.length === 1) {
7259
- lines.push(` var ${imp.names[0]} = ${srcId};`);
7260
- } else {
7261
- for (const name of imp.names) {
7262
- lines.push(` var ${name} = ${srcId}._exports ? ${srcId}._exports.${name} : ${srcId}.${name};`);
7263
- }
7265
+ for (const name of imp.names) {
7266
+ const localName = name.alias ?? name.name;
7267
+ const importedName = name.name;
7268
+ lines.push(` var ${localName} = ${srcId}._exports ? ${srcId}._exports.${importedName} : ${srcId}.${importedName};`);
7264
7269
  }
7265
7270
  }
7266
7271
  if (imports.length > 0) lines.push("");
package/dist/flux.cjs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * flux-lang v4.0.1
2
+ * flux-lang v4.0.3
3
3
  * Flux — A modern language that transpiles to JavaScript. Python-clean syntax, TypeScript-level safety, Rust-inspired pattern matching.
4
4
  * (c) 2026 Flux Lang Contributors
5
5
  * Released under the MIT License
@@ -278,7 +278,7 @@ var require_lexer = __commonJS({
278
278
  if (this.ch() === "\\") {
279
279
  this.adv();
280
280
  const e = this.adv();
281
- s += { n: "\n", t: " ", "`": "`", "\\": "\\" }[e] || "\\" + e;
281
+ s += { n: "\n", t: " ", "`": "`", "\\": "\\" }[e] || "\\" + e;
282
282
  } else {
283
283
  s += this.adv();
284
284
  }
@@ -314,7 +314,7 @@ var require_lexer = __commonJS({
314
314
  this.pos += 2;
315
315
  text += String.fromCharCode(parseInt(hex, 16));
316
316
  } else {
317
- text += { n: "\n", t: " ", r: "\r", '"': '"', "'": "'", "\\": "\\", "{": "{", "}": "}" }[e] || "\\" + e;
317
+ text += { n: "\n", t: " ", r: "\r", '"': '"', "'": "'", "\\": "\\", "{": "{", "}": "}" }[e] || "\\" + e;
318
318
  }
319
319
  } else if (this.ch() === "{") {
320
320
  parts.push({ type: "text", value: text });
@@ -402,8 +402,8 @@ var require_lexer = __commonJS({
402
402
  if (bol) {
403
403
  bol = false;
404
404
  let indent = 0;
405
- while (this.ch() === " " || this.ch() === " ") {
406
- indent += this.ch() === " " ? 4 : 1;
405
+ while (this.ch() === " " || this.ch() === " ") {
406
+ indent += this.ch() === " " ? 4 : 1;
407
407
  this.adv();
408
408
  }
409
409
  if (this.ch() === "\n" || !this.ch()) {
@@ -444,7 +444,7 @@ var require_lexer = __commonJS({
444
444
  }
445
445
  continue;
446
446
  }
447
- if (cur === " " || cur === " ") {
447
+ if (cur === " " || cur === " ") {
448
448
  this.adv();
449
449
  continue;
450
450
  }
@@ -519,7 +519,7 @@ var require_lexer = __commonJS({
519
519
  this.pos += 2;
520
520
  s += String.fromCharCode(parseInt(hex, 16));
521
521
  } else {
522
- s += { n: "\n", t: " ", r: "\r", "'": "'", "\\": "\\" }[e] || "\\" + e;
522
+ s += { n: "\n", t: " ", r: "\r", "'": "'", "\\": "\\" }[e] || "\\" + e;
523
523
  }
524
524
  } else {
525
525
  s += this.adv();
@@ -2581,6 +2581,7 @@ function _fmt(v, s) {
2581
2581
  this.smBuilder = opts.smBuilder || null;
2582
2582
  this._needsFmt = false;
2583
2583
  this._loopDepth = 0;
2584
+ this._fnDepth = 0;
2584
2585
  }
2585
2586
  i() {
2586
2587
  return this.ind.repeat(this.level);
@@ -2718,7 +2719,9 @@ function _fmt(v, s) {
2718
2719
  } else {
2719
2720
  this.emit(`${prefix}${asyncKw}function ${name}(${params}) {`);
2720
2721
  this.in();
2722
+ this._fnDepth++;
2721
2723
  for (const s of node.body) this.genStmt(s);
2724
+ this._fnDepth--;
2722
2725
  this.out();
2723
2726
  this.emit("}");
2724
2727
  }
@@ -2910,8 +2913,10 @@ function _fmt(v, s) {
2910
2913
  const exprSrc = this.genExpr(arm.body[0].expr);
2911
2914
  if (this._loopDepth > 0) {
2912
2915
  this.emit(`${exprSrc};`);
2913
- } else {
2916
+ } else if (this._fnDepth > 0) {
2914
2917
  this.emit(`return ${exprSrc};`);
2918
+ } else {
2919
+ this.emit(`${exprSrc};`);
2915
2920
  }
2916
2921
  } else {
2917
2922
  arm.body.forEach((s) => this.genStmt(s));
@@ -3160,11 +3165,13 @@ function _fmt(v, s) {
3160
3165
  const savedLevel = this.level;
3161
3166
  const savedLoopDepth = this._loopDepth;
3162
3167
  this._loopDepth = 0;
3168
+ this._fnDepth++;
3163
3169
  this.emit("(() => {");
3164
3170
  this.in();
3165
3171
  this.genMatch(node);
3166
3172
  this.out();
3167
3173
  this.emit("})()");
3174
+ this._fnDepth--;
3168
3175
  this._loopDepth = savedLoopDepth;
3169
3176
  const block = this.lines.splice(saved).map((l) => l.trimStart()).join(" ");
3170
3177
  this.level = savedLevel;
@@ -3498,7 +3505,7 @@ var require_jsx = __commonJS({
3498
3505
  const next = this.src[this.pos + 1] || "";
3499
3506
  if (!(next === ">" || next >= "a" && next <= "z" || next >= "A" && next <= "Z")) return false;
3500
3507
  let i = this.pos - 1;
3501
- while (i >= 0 && (this.src[i] === " " || this.src[i] === " ")) i--;
3508
+ while (i >= 0 && (this.src[i] === " " || this.src[i] === " ")) i--;
3502
3509
  if (i < 0) return true;
3503
3510
  const prev = this.src[i];
3504
3511
  if ("=([{,:>\n?".includes(prev)) return true;
@@ -3727,7 +3734,7 @@ var require_jsx = __commonJS({
3727
3734
  }
3728
3735
  // ── Skip whitespace (not newlines) ────────────────────────────
3729
3736
  skipWs() {
3730
- while (this.pos < this.src.length && (this.src[this.pos] === " " || this.src[this.pos] === " ")) this.pos++;
3737
+ while (this.pos < this.src.length && (this.src[this.pos] === " " || this.src[this.pos] === " ")) this.pos++;
3731
3738
  }
3732
3739
  };
3733
3740
  var FLUX_H_BROWSER = `
@@ -4551,7 +4558,7 @@ ${innerCss}${ind}}
4551
4558
  const charAfter = this.src[this.pos + 3] || "";
4552
4559
  if (!/[a-zA-Z0-9_]/.test(charBefore) && !/[a-zA-Z0-9_]/.test(charAfter)) {
4553
4560
  let j = this.pos + 3;
4554
- while (j < this.src.length && (this.src[j] === " " || this.src[j] === " " || this.src[j] === "\n" || this.src[j] === "\r")) j++;
4561
+ while (j < this.src.length && (this.src[j] === " " || this.src[j] === " " || this.src[j] === "\n" || this.src[j] === "\r")) j++;
4555
4562
  if (this.src[j] === "{") {
4556
4563
  j++;
4557
4564
  let depth = 1;
@@ -7276,12 +7283,10 @@ var require_bundler = __commonJS({
7276
7283
  }
7277
7284
  for (const imp of imports) {
7278
7285
  const srcId = toModuleId(imp.absPath);
7279
- if (imp.names.length === 1) {
7280
- lines.push(` var ${imp.names[0]} = ${srcId};`);
7281
- } else {
7282
- for (const name of imp.names) {
7283
- lines.push(` var ${name} = ${srcId}._exports ? ${srcId}._exports.${name} : ${srcId}.${name};`);
7284
- }
7286
+ for (const name of imp.names) {
7287
+ const localName = name.alias ?? name.name;
7288
+ const importedName = name.name;
7289
+ lines.push(` var ${localName} = ${srcId}._exports ? ${srcId}._exports.${importedName} : ${srcId}.${importedName};`);
7285
7290
  }
7286
7291
  }
7287
7292
  if (imports.length > 0) lines.push("");
@@ -0,0 +1,4 @@
1
+ 'use strict';
2
+ // Compatibility shim — redirects require('./transpiler') to the main CJS bundle.
3
+ // Required by the CLI test-runner which resolves module paths from __dirname.
4
+ module.exports = require('./flux.cjs.js');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xnoxs/flux-lang",
3
- "version": "4.0.1",
3
+ "version": "4.0.3",
4
4
  "description": "Flux — A modern language that transpiles to JavaScript. Python-clean syntax, TypeScript-level safety, Rust-inspired pattern matching.",
5
5
  "main": "dist/flux.cjs.js",
6
6
  "module": "dist/flux.esm.js",
@@ -84,4 +84,4 @@
84
84
  "devDependencies": {
85
85
  "esbuild": "^0.28.1"
86
86
  }
87
- }
87
+ }
@@ -124,11 +124,10 @@ export class Bundler:
124
124
 
125
125
  for imp in mod.imports:
126
126
  val srcId = toModuleId(imp.absPath)
127
- if imp.names.length == 1:
128
- lines.push(' var ' + imp.names[0] + ' = ' + srcId + ';')
129
- else:
130
- for name in imp.names:
131
- lines.push(' var ' + name + ' = ' + srcId + '._exports ? ' + srcId + '._exports.' + name + ' : ' + srcId + '.' + name + ';')
127
+ for name in imp.names:
128
+ val localName = name.alias ?? name.name
129
+ val importedName = name.name
130
+ lines.push(' var ' + localName + ' = ' + srcId + '._exports ? ' + srcId + '._exports.' + importedName + ' : ' + srcId + '.' + importedName + ';')
132
131
 
133
132
  if mod.imports.length > 0: lines.push('')
134
133
 
@@ -1,198 +1 @@
1
- // ── Flux stdlib ──
2
-
3
- function findIndex(arr, fn) { return arr.findIndex(fn); }
4
-
5
- function join(arr, sep) { return arr.join(sep != null ? sep : ','); }
6
-
7
- function includes(arr, val) { return arr.includes(val); }
8
-
9
- function trim(s) { return String(s).trim(); }
10
-
11
- function startsWith(s, prefix) { return String(s).startsWith(prefix); }
12
-
13
- function endsWith(s, suffix) { return String(s).endsWith(suffix); }
14
-
15
- function repeat(s, n) { return String(s).repeat(n); }
16
- // ── end stdlib ──
17
-
18
- // Generated by Flux Transpiler v3.2.0
19
- "use strict";
20
-
21
- const Fs = require("fs");
22
- const Path = require("path");
23
- const { lexerize } = require("./lexer");
24
- const { makeParser } = require("./parser");
25
- const { makeCodeGen } = require("./codegen");
26
- function toModuleId(absPath) {
27
- const base = Path.basename(absPath, ".flux");
28
- return ("_flux_" + base.replace(/[^a-zA-Z0-9]/g, "_"));
29
- }
30
- function extractModuleInfo(ast, fromFile) {
31
- const imports = [];
32
- const exports = [];
33
- const body = [];
34
- const dir = Path.dirname(fromFile);
35
- for (const node of ast.body) {
36
- if ((node.type == "ImportDecl")) {
37
- let src = node.source;
38
- if (!src.endsWith(".flux")) {
39
- src = (src + ".flux");
40
- }
41
- const absPath = Path.resolve(dir, src);
42
- imports.push({ names: node.names, source: node.source, absPath });
43
- }
44
- else if ((node.type == "ExportDecl")) {
45
- const inner = node.decl;
46
- if ((inner.type == "FnDecl")) {
47
- exports.push(inner.name);
48
- }
49
- if ((inner.type == "ClassDecl")) {
50
- exports.push(inner.name);
51
- }
52
- if ((inner.type == "VarDecl")) {
53
- exports.push(inner.name);
54
- }
55
- body.push(inner);
56
- }
57
- else {
58
- body.push(node);
59
- }
60
- }
61
- return { cleanAst: { type: "Program", body }, imports, exports };
62
- }
63
- function codegenModule(ast) {
64
- const cg = makeCodeGen({ indent: " " });
65
- const result = cg.generate(ast);
66
- const lines = result.code.split("\n");
67
- const start = lines.findIndex((l) => (((l.trim() != "") && !l.includes("Generated by Flux")) && !l.includes("\"use strict\"")));
68
- return lines.slice(start).join("\n");
69
- }
70
- class Bundler {
71
- constructor(entryFile, options, modules, order, visited, inStack) {
72
- this.entryFile = entryFile;
73
- this.options = options;
74
- this.modules = modules;
75
- this.order = order;
76
- this.visited = visited;
77
- this.inStack = inStack;
78
- }
79
-
80
- bundle() {
81
- this.collect(this.entryFile);
82
- return this.link();
83
- }
84
-
85
- collect(absPath) {
86
- if (this.visited.has(absPath)) {
87
- return;
88
- }
89
- if (this.inStack.has(absPath)) {
90
- throw new Error(((("[" + Path.basename(absPath)) + "] Circular dependency detected: ") + absPath));
91
- }
92
- if (!Fs.existsSync(absPath)) {
93
- throw new Error(((("[" + Path.basename(absPath)) + "] File not found: ") + absPath));
94
- }
95
- this.inStack.add(absPath);
96
- const source = Fs.readFileSync(absPath, "utf8");
97
- let ast = null;
98
- try {
99
- const tokens = lexerize(source).tokenize();
100
- ast = makeParser(tokens).parse();
101
- }
102
- catch (e) {
103
- throw new Error(((("[" + Path.basename(absPath)) + "] Parse error: ") + e.message));
104
- }
105
- const info = extractModuleInfo(ast, absPath);
106
- this.modules.set(absPath, { cleanAst: info.cleanAst, imports: info.imports, exports: info.exports, source, absPath });
107
- for (const imp of info.imports) {
108
- this.collect(imp.absPath);
109
- }
110
- this.inStack.delete(absPath);
111
- this.visited.add(absPath);
112
- this.order.push(absPath);
113
- }
114
-
115
- link() {
116
- const lines = [];
117
- const banner = (this.options.banner != false);
118
- if (banner) {
119
- lines.push("// Generated by Flux Bundler (self-hosted)");
120
- lines.push(("// Entry: " + Path.basename(this.entryFile)));
121
- lines.push(("// Modules: " + this.order.length));
122
- lines.push("\"use strict\";");
123
- lines.push("");
124
- }
125
- lines.push("// flux_modules resolver");
126
- lines.push(`(function()${var _p=require('path'),_fs=require('fs'),_M=require('module'),_d=_p.join(process.cwd(),'flux_modules','node_modules');if(_fs.existsSync(_d)){var _o=_M._resolveFilename.bind(_M);_M._resolveFilename=function(r,p,m,op){if(!r.startsWith('.')&&!r.startsWith('/')&&!r.startsWith('node:')){var _fp=_p.join(_d,r.split('/')[0]);if(_fs.existsSync(_fp)){try{return _o(_p.join(_d,r),p,m,op);}catch(_e){}}}return _o(r,p,m,op);};}})();`);
127
- lines.push("");
128
- lines.push("(function() {");
129
- lines.push("");
130
- for (const absPath of this.order) {
131
- const mod = this.modules.get(absPath);
132
- const isEntry = (absPath == this.entryFile);
133
- const modId = toModuleId(absPath);
134
- const relName = Path.relative(process.cwd(), absPath);
135
- lines.push((" // " + "─".repeat(60)));
136
- lines.push((" // Module: " + relName));
137
- lines.push((" // " + "─".repeat(60)));
138
- if (!isEntry) {
139
- lines.push(((" var " + modId) + " = (function() {"));
140
- lines.push(" var _exports = {};");
141
- lines.push("");
142
- }
143
- for (const imp of mod.imports) {
144
- const srcId = toModuleId(imp.absPath);
145
- if ((imp.names.length == 1)) {
146
- lines.push(((((" var " + imp.names[0]) + " = ") + srcId) + ";"));
147
- }
148
- else {
149
- for (const name of imp.names) {
150
- lines.push(((((((((((((" var " + name) + " = ") + srcId) + "._exports ? ") + srcId) + "._exports.") + name) + " : ") + srcId) + ".") + name) + ";"));
151
- }
152
- }
153
- }
154
- if ((mod.imports.length > 0)) {
155
- lines.push("");
156
- }
157
- const moduleCode = codegenModule(mod.cleanAst);
158
- lines.push(moduleCode);
159
- if (!isEntry) {
160
- if ((mod.exports.length > 0)) {
161
- lines.push("");
162
- for (const expName of mod.exports) {
163
- lines.push(((((" _exports." + expName) + " = ") + expName) + ";"));
164
- }
165
- }
166
- lines.push("");
167
- lines.push(" return _exports;");
168
- lines.push(" })()");
169
- lines.push(((((" " + modId) + "._exports = ") + modId) + ";"));
170
- }
171
- lines.push("");
172
- }
173
- lines.push("})();");
174
- return { code: lines.join("\n"), modules: this.order.length };
175
- }
176
-
177
- }
178
-
179
- module.exports.Bundler = Bundler;
180
- function makeBundler(entryFile, options) {
181
- return new Bundler(Path.resolve(entryFile), (options ?? { }), new Map(), [], new Set(), new Set());
182
- }
183
- module.exports.makeBundler = makeBundler;
184
- function bundle(entryFile, options) {
185
- const result = { success: false, code: "", modules: 0, errors: [] };
186
- try {
187
- const b = makeBundler(entryFile, options);
188
- const out = b.bundle();
189
- result.code = out.code;
190
- result.modules = out.modules;
191
- result.success = true;
192
- }
193
- catch (e) {
194
- result.errors.push({ message: e.message, name: e.name, file: null });
195
- }
196
- return result;
197
- }
198
- module.exports.bundle = bundle;
1
+ function findIndex(arr, fn) { return arr.findIndex(fn); } function join(arr, sep) { return arr.join(sep != null ? sep : ','); } function includes(arr, val) { return arr.includes(val); } function trim(s) { return String(s).trim(); } function startsWith(s, prefix) { return String(s).startsWith(prefix); } function endsWith(s, suffix) { return String(s).endsWith(suffix); } function repeat(s, n) { return String(s).repeat(n); } "use strict"; const Fs = require("fs"); const Path = require("path"); const { lexerize } = require("./lexer"); const { makeParser } = require("./parser"); const { makeCodeGen } = require("./codegen"); function _a(_d) { const base = Path.basename(_d, ".flux"); return ("_flux_" + base.replace(/[^a-zA-Z0-9]/g, "_")); } function _b(_e, _f) { const imports = []; const exports = []; const body = []; const dir = Path.dirname(_f); for (const _g of _e.body) { if ((_g.type == "ImportDecl")) { let src = _g.source; if (!src.endsWith(".flux")) { src = (src + ".flux"); } const _d = Path.resolve(dir, src); imports.push({ names: _g.names, source: _g.source, absPath: _d }); } else if ((_g.type == "ExportDecl")) { const inner = _g.decl; if ((inner.type == "FnDecl")) { exports.push(inner.name); } if ((inner.type == "ClassDecl")) { exports.push(inner.name); } if ((inner.type == "VarDecl")) { exports.push(inner.name); } body.push(inner); } else { body.push(_g); } } return { cleanAst: { type: "Program", body }, imports, exports }; } function _c(_e) { const cg = makeCodeGen({ indent: " " }); const result = cg.generate(_e); const lines = result.code.split("\n"); const start = lines.findIndex((_h) => (((_h.trim() != "") && !_h.includes("Generated by Flux")) && !_h.includes("\"use strict\""))); return lines.slice(start).join("\n"); } class Bundler { constructor(entryFile, options, modules, order, visited, inStack) { this.entryFile = entryFile; this.options = options; this.modules = modules; this.order = order; this.visited = visited; this.inStack = inStack; } bundle() { this.collect(this.entryFile); return this.link(); } collect(_d) { if (this.visited.has(_d)) { return; } if (this.inStack.has(_d)) { throw new Error(((("[" + Path.basename(_d)) + "] Circular dependency detected: ") + _d)); } if (!Fs.existsSync(_d)) { throw new Error(((("[" + Path.basename(_d)) + "] File not found: ") + _d)); } this.inStack.add(_d); const source = Fs.readFileSync(_d, "utf8"); let _e = null; try { const tokens = lexerize(source).tokenize(); _e = makeParser(tokens).parse(); } catch (_i) { throw new Error(((("[" + Path.basename(_d)) + "] Parse error: ") + _i.message)); } const info = _b(_e, _d); this.modules.set(_d, { cleanAst: info.cleanAst, imports: info.imports, exports: info.exports, source, absPath: _d }); for (const _j of info.imports) { this.collect(_j.absPath); } this.inStack.delete(_d); this.visited.add(_d); this.order.push(_d); } link() { const lines = []; const banner = (this.options.banner != false); if (banner) { lines.push("// Generated by Flux Bundler (self-hosted)"); lines.push(("// Entry: " + Path.basename(this.entryFile))); lines.push(("// Modules: " + this.order.length)); lines.push("\"use strict\";"); lines.push(""); } lines.push("// flux_modules resolver"); lines.push(`(function()${var _p=require('path'),_fs=require('fs'),_M=require('module'),_d=_p.join(process.cwd(),'flux_modules','node_modules');if(_fs.existsSync(_d)){var _o=_M._resolveFilename.bind(_M);_M._resolveFilename=function(r,p,m,op){if(!r.startsWith('.')&&!r.startsWith('/')&&!r.startsWith('_g:')){var _fp=_p.join(_d,r.split('/')[0]);if(_fs.existsSync(_fp)){try{return _o(_p.join(_d,r),p,m,op);}catch(_e){}}}return _o(r,p,m,op);};}})();`); lines.push(""); lines.push("(function() {"); lines.push(""); for (const _d of this.order) { const mod = this.modules.get(_d); const isEntry = (_d == this.entryFile); const modId = _a(_d); const relName = Path.relative(process.cwd(), _d); lines.push((" // " + "─".repeat(60))); lines.push((" // Module: " + relName)); lines.push((" // " + "─".repeat(60))); if (!isEntry) { lines.push(((" var " + modId) + " = (function() {")); lines.push(" var _exports = {};"); lines.push(""); } for (const _j of mod.imports) { const srcId = _a(_j.absPath); for (const _k of _j.names) { const localName = (_k.alias ?? _k.name); const importedName = _k.name; lines.push(((((((((((((" var " + localName) + " = ") + srcId) + "._exports ? ") + srcId) + "._exports.") + importedName) + " : ") + srcId) + ".") + importedName) + ";")); } } if ((mod.imports.length > 0)) { lines.push(""); } const moduleCode = _c(mod.cleanAst); lines.push(moduleCode); if (!isEntry) { if ((mod.exports.length > 0)) { lines.push(""); for (const _l of mod.exports) { lines.push(((((" _exports." + _l) + " = ") + _l) + ";")); } } lines.push(""); lines.push(" return _exports;"); lines.push(" })()"); lines.push(((((" " + modId) + "._exports = ") + modId) + ";")); } lines.push(""); } lines.push("})();"); return { code: lines.join("\n"), modules: this.order.length }; } } module.exports.Bundler = Bundler; function makeBundler(_m, _n) { return new Bundler(Path.resolve(_m), (_n ?? { }), new Map(), [], new Set(), new Set()); } module.exports.makeBundler = makeBundler; function bundle(_m, _n) { const result = { success: false, code: "", modules: 0, errors: [] }; try { const b = makeBundler(_m, _n); const out = b.bundle(); result.code = out.code; result.modules = out.modules; result.success = true; } catch (_i) { result.errors.push({ message: _i.message, name: _i.name, file: null }); } return result; } module.exports.bundle = bundle;
@@ -54,6 +54,7 @@ export class CodeGenerator:
54
54
  smBuilder: any
55
55
  _needsFmt: bool
56
56
  _loopDepth: int
57
+ _fnDepth: int
57
58
  _version: string
58
59
 
59
60
  fn i():
@@ -166,7 +167,9 @@ export class CodeGenerator:
166
167
  else:
167
168
  self.emit(prefix + asyncKw + 'function ' + name + '(' + params + ') {')
168
169
  self.indIn()
170
+ self._fnDepth = self._fnDepth + 1
169
171
  for s in node.body: self.genStmt(s)
172
+ self._fnDepth = self._fnDepth - 1
170
173
  self.indOut()
171
174
  self.emit('}')
172
175
 
@@ -200,7 +203,9 @@ export class CodeGenerator:
200
203
  else:
201
204
  self.emit(staticKw + asyncKw + m.name + '(' + params + ') {')
202
205
  self.indIn()
206
+ self._fnDepth = self._fnDepth + 1
203
207
  for s in m.body: self.genStmt(s)
208
+ self._fnDepth = self._fnDepth - 1
204
209
  self.indOut()
205
210
  self.emit('}')
206
211
  self.blank()
@@ -304,8 +309,10 @@ export class CodeGenerator:
304
309
  val exprSrc = self.genExpr(arm.body[0].expr)
305
310
  if self._loopDepth > 0:
306
311
  self.emit(exprSrc + ';')
307
- else:
312
+ else if self._fnDepth > 0:
308
313
  self.emit('return ' + exprSrc + ';')
314
+ else:
315
+ self.emit(exprSrc + ';')
309
316
  else:
310
317
  for s in arm.body: self.genStmt(s)
311
318
  self.indOut()
@@ -492,11 +499,13 @@ export class CodeGenerator:
492
499
  val savedLevel = self.level
493
500
  val savedLoop = self._loopDepth
494
501
  self._loopDepth = 0
502
+ self._fnDepth = self._fnDepth + 1
495
503
  self.emit('(() => {')
496
504
  self.indIn()
497
505
  self.genMatch(node)
498
506
  self.indOut()
499
507
  self.emit('})()')
508
+ self._fnDepth = self._fnDepth - 1
500
509
  self._loopDepth = savedLoop
501
510
  val block = self.lines.splice(saved).map(l -> l.trimStart()).join(' ')
502
511
  self.level = savedLevel