@xnoxs/flux-lang 4.0.3 → 4.0.5

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/flux.cjs.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * flux-lang v4.0.3
2
+ * flux-lang v4.0.5
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
package/index.js CHANGED
@@ -3,17 +3,17 @@
3
3
  /**
4
4
  * Flux Lang — Public API
5
5
  *
6
- * const { transpile } = require('flux-lang');
7
- * import { transpile, format, buildStdlib } from 'flux-lang';
6
+ * const { transpile } = require('@xnoxs/flux-lang');
7
+ * import { transpile, format, buildStdlib } from '@xnoxs/flux-lang';
8
8
  */
9
9
 
10
- const { transpile } = require('./src/transpiler');
11
- const { format } = require('./src/formatter');
12
- const { buildStdlib, detectUsedSymbols, STDLIB_SYMBOLS } = require('./src/stdlib');
13
- const { Lexer } = require('./src/lexer');
14
- const { Parser } = require('./src/parser');
15
- const { bundle } = require('./src/bundler');
16
- const { loadConfig, mergeConfig, defineConfig } = require('./src/config');
10
+ const { transpile } = require('./src/self/transpiler');
11
+ const { format } = require('./src/self/formatter');
12
+ const { buildStdlib, detectUsedSymbols, STDLIB_SYMBOLS } = require('./src/self/stdlib');
13
+ const { Lexer } = require('./src/self/lexer');
14
+ const { Parser } = require('./src/self/parser');
15
+ const { bundle } = require('./src/self/bundler');
16
+ const { loadConfig, mergeConfig } = require('./src/self/config');
17
17
 
18
18
  module.exports = {
19
19
  transpile,
@@ -26,5 +26,4 @@ module.exports = {
26
26
  bundle,
27
27
  loadConfig,
28
28
  mergeConfig,
29
- defineConfig,
30
29
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xnoxs/flux-lang",
3
- "version": "4.0.3",
3
+ "version": "4.0.5",
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",
@@ -9,9 +9,8 @@
9
9
  "flux": "./bin/flux.js"
10
10
  },
11
11
  "scripts": {
12
- "build": "node scripts/build.js",
13
- "prepublishOnly": "npm test && npm run build",
14
- "test": "node src/cli.js test tests/",
12
+ "build": "node -e \"console.log(\"build skipped\")\"",
13
+ "test": "node src/self/cli.js test tests/",
15
14
  "test:file": "node src/cli.js test",
16
15
  "check": "node src/cli.js check tests/01_basics.test.flux",
17
16
  "bench": "node benchmarks/bench.js",
@@ -84,4 +83,4 @@
84
83
  "devDependencies": {
85
84
  "esbuild": "^0.28.1"
86
85
  }
87
- }
86
+ }
@@ -3,6 +3,8 @@
3
3
  // src/self/bundler.flux — written in Flux, compiled by stage-0
4
4
  //
5
5
  // Bundles multiple Flux modules into a single JS file.
6
+ // Resolves all inter-file .flux imports recursively.
7
+ // npm packages (non-relative imports) remain as require() calls.
6
8
  // ============================================================
7
9
 
8
10
  import Fs from "fs"
@@ -16,17 +18,25 @@ fn toModuleId(absPath):
16
18
  return '_flux_' + base.replace(/[^a-zA-Z0-9]/g, '_')
17
19
 
18
20
  fn extractModuleInfo(ast, fromFile):
19
- val imports = []
20
- val exports = []
21
- val body = []
22
- val dir = Path.dirname(fromFile)
21
+ val imports = []
22
+ val npmImports = []
23
+ val exports = []
24
+ val body = []
25
+ val dir = Path.dirname(fromFile)
23
26
 
24
27
  for node in ast.body:
25
28
  if node.type == 'ImportDecl':
26
- var src = node.source
27
- if not src.endsWith('.flux'): src = src + '.flux'
28
- val absPath = Path.resolve(dir, src)
29
- imports.push({ names: node.names, source: node.source, absPath })
29
+ val src = node.source
30
+ // Relative import resolve as .flux file
31
+ if src.startsWith('./') or src.startsWith('../'):
32
+ var resolved = src
33
+ if not resolved.endsWith('.flux'): resolved = resolved + '.flux'
34
+ val absPath = Path.resolve(dir, resolved)
35
+ imports.push({ names: node.names, source: node.source, absPath })
36
+ else:
37
+ // npm package import — keep as-is (require in output)
38
+ npmImports.push({ names: node.names, source: src })
39
+ body.push(node)
30
40
 
31
41
  else if node.type == 'ExportDecl':
32
42
  val inner = node.decl
@@ -38,7 +48,7 @@ fn extractModuleInfo(ast, fromFile):
38
48
  else:
39
49
  body.push(node)
40
50
 
41
- return { cleanAst: { type: 'Program', body }, imports, exports }
51
+ return { cleanAst: { type: 'Program', body }, imports, npmImports, exports }
42
52
 
43
53
  fn codegenModule(ast):
44
54
  val cg = makeCodeGen({ indent: ' ' })
@@ -80,6 +90,7 @@ export class Bundler:
80
90
  val info = extractModuleInfo(ast, absPath)
81
91
  self.modules.set(absPath, { cleanAst: info.cleanAst, imports: info.imports, exports: info.exports, source, absPath })
82
92
 
93
+ // Recursively collect all .flux imports
83
94
  for imp in info.imports:
84
95
  self.collect(imp.absPath)
85
96
 
@@ -98,12 +109,6 @@ export class Bundler:
98
109
  lines.push('"use strict";')
99
110
  lines.push('')
100
111
 
101
- // flux_modules resolver: patches Module._resolveFilename so require() looks in
102
- // flux_modules/node_modules/ first (packages installed via `flux install`).
103
- lines.push('// flux_modules resolver')
104
- 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);};}})();")
105
- lines.push('')
106
-
107
112
  lines.push('(function() {')
108
113
  lines.push('')
109
114
 
@@ -125,7 +130,7 @@ export class Bundler:
125
130
  for imp in mod.imports:
126
131
  val srcId = toModuleId(imp.absPath)
127
132
  for name in imp.names:
128
- val localName = name.alias ?? name.name
133
+ val localName = name.alias ?? name.name
129
134
  val importedName = name.name
130
135
  lines.push(' var ' + localName + ' = ' + srcId + '._exports ? ' + srcId + '._exports.' + importedName + ' : ' + srcId + '.' + importedName + ';')
131
136
 
@@ -1 +1,185 @@
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;
1
+ /* compiled from src/self/bundler.flux */
2
+ 'use strict';
3
+ // Generated by Flux Transpiler v3.5.3 (self-hosted)
4
+ "use strict";
5
+
6
+ const Fs = require("fs");
7
+ const Path = require("path");
8
+ const { lexerize } = require("./lexer");
9
+ const { makeParser } = require("./parser");
10
+ const { makeCodeGen } = require("./codegen");
11
+ function toModuleId(absPath) {
12
+ const base = Path.basename(absPath, ".flux");
13
+ return ("_flux_" + base.replace(/[^a-zA-Z0-9]/g, "_"));
14
+ }
15
+ function extractModuleInfo(ast, fromFile) {
16
+ const imports = [];
17
+ const npmImports = [];
18
+ const exports = [];
19
+ const body = [];
20
+ const dir = Path.dirname(fromFile);
21
+ for (const node of ast.body) {
22
+ if ((node.type == "ImportDecl")) {
23
+ const src = node.source;
24
+ if ((src.startsWith("./") || src.startsWith("../"))) {
25
+ let resolved = src;
26
+ if (!resolved.endsWith(".flux")) {
27
+ resolved = (resolved + ".flux");
28
+ }
29
+ const absPath = Path.resolve(dir, resolved);
30
+ imports.push({ names: node.names, source: node.source, absPath });
31
+ }
32
+ else {
33
+ npmImports.push({ names: node.names, source: src });
34
+ body.push(node);
35
+ }
36
+ }
37
+ else if ((node.type == "ExportDecl")) {
38
+ const inner = node.decl;
39
+ if ((inner.type == "FnDecl")) {
40
+ exports.push(inner.name);
41
+ }
42
+ if ((inner.type == "ClassDecl")) {
43
+ exports.push(inner.name);
44
+ }
45
+ if ((inner.type == "VarDecl")) {
46
+ exports.push(inner.name);
47
+ }
48
+ body.push(inner);
49
+ }
50
+ else {
51
+ body.push(node);
52
+ }
53
+ }
54
+ return { cleanAst: { type: "Program", body }, imports, npmImports, exports };
55
+ }
56
+ function codegenModule(ast) {
57
+ const cg = makeCodeGen({ indent: " " });
58
+ const result = cg.generate(ast);
59
+ const lines = result.code.split("\n");
60
+ const start = lines.findIndex((l) => (((l.trim() != "") && !l.includes("Generated by Flux")) && !l.includes("\"use strict\"")));
61
+ return lines.slice(start).join("\n");
62
+ }
63
+ class Bundler {
64
+ constructor(entryFile, options, modules, order, visited, inStack) {
65
+ this.entryFile = entryFile;
66
+ this.options = options;
67
+ this.modules = modules;
68
+ this.order = order;
69
+ this.visited = visited;
70
+ this.inStack = inStack;
71
+ }
72
+
73
+ bundle() {
74
+ this.collect(this.entryFile);
75
+ return this.link();
76
+ }
77
+
78
+ collect(absPath) {
79
+ if (this.visited.has(absPath)) {
80
+ return;
81
+ }
82
+ if (this.inStack.has(absPath)) {
83
+ throw new Error(((("[" + Path.basename(absPath)) + "] Circular dependency detected: ") + absPath));
84
+ }
85
+ if (!Fs.existsSync(absPath)) {
86
+ throw new Error(((("[" + Path.basename(absPath)) + "] File not found: ") + absPath));
87
+ }
88
+ this.inStack.add(absPath);
89
+ const source = Fs.readFileSync(absPath, "utf8");
90
+ let ast = null;
91
+ try {
92
+ const tokens = lexerize(source).tokenize();
93
+ ast = makeParser(tokens).parse();
94
+ }
95
+ catch (e) {
96
+ throw new Error(((("[" + Path.basename(absPath)) + "] Parse error: ") + e.message));
97
+ }
98
+ const info = extractModuleInfo(ast, absPath);
99
+ this.modules.set(absPath, { cleanAst: info.cleanAst, imports: info.imports, exports: info.exports, source, absPath });
100
+ for (const imp of info.imports) {
101
+ this.collect(imp.absPath);
102
+ }
103
+ this.inStack.delete(absPath);
104
+ this.visited.add(absPath);
105
+ this.order.push(absPath);
106
+ }
107
+
108
+ link() {
109
+ const lines = [];
110
+ const banner = (this.options.banner != false);
111
+ if (banner) {
112
+ lines.push("// Generated by Flux Bundler (self-hosted)");
113
+ lines.push(("// Entry: " + Path.basename(this.entryFile)));
114
+ lines.push(("// Modules: " + this.order.length));
115
+ lines.push("\"use strict\";");
116
+ lines.push("");
117
+ }
118
+ lines.push("(function() {");
119
+ lines.push("");
120
+ for (const absPath of this.order) {
121
+ const mod = this.modules.get(absPath);
122
+ const isEntry = (absPath == this.entryFile);
123
+ const modId = toModuleId(absPath);
124
+ const relName = Path.relative(process.cwd(), absPath);
125
+ lines.push((" // " + "─".repeat(60)));
126
+ lines.push((" // Module: " + relName));
127
+ lines.push((" // " + "─".repeat(60)));
128
+ if (!isEntry) {
129
+ lines.push(((" var " + modId) + " = (function() {"));
130
+ lines.push(" var _exports = {};");
131
+ lines.push("");
132
+ }
133
+ for (const imp of mod.imports) {
134
+ const srcId = toModuleId(imp.absPath);
135
+ for (const name of imp.names) {
136
+ const localName = (name.alias ?? name.name);
137
+ const importedName = name.name;
138
+ lines.push(((((((((((((" var " + localName) + " = ") + srcId) + "._exports ? ") + srcId) + "._exports.") + importedName) + " : ") + srcId) + ".") + importedName) + ";"));
139
+ }
140
+ }
141
+ if ((mod.imports.length > 0)) {
142
+ lines.push("");
143
+ }
144
+ const moduleCode = codegenModule(mod.cleanAst);
145
+ lines.push(moduleCode);
146
+ if (!isEntry) {
147
+ if ((mod.exports.length > 0)) {
148
+ lines.push("");
149
+ for (const expName of mod.exports) {
150
+ lines.push(((((" _exports." + expName) + " = ") + expName) + ";"));
151
+ }
152
+ }
153
+ lines.push("");
154
+ lines.push(" return _exports;");
155
+ lines.push(" })()");
156
+ lines.push(((((" " + modId) + "._exports = ") + modId) + ";"));
157
+ }
158
+ lines.push("");
159
+ }
160
+ lines.push("})();");
161
+ return { code: lines.join("\n"), modules: this.order.length };
162
+ }
163
+
164
+ }
165
+
166
+ module.exports.Bundler = Bundler;
167
+ function makeBundler(entryFile, options) {
168
+ return new Bundler(Path.resolve(entryFile), (options ?? { }), new Map(), [], new Set(), new Set());
169
+ }
170
+ module.exports.makeBundler = makeBundler;
171
+ function bundle(entryFile, options) {
172
+ const result = { success: false, code: "", modules: 0, errors: [] };
173
+ try {
174
+ const b = makeBundler(entryFile, options);
175
+ const out = b.bundle();
176
+ result.code = out.code;
177
+ result.modules = out.modules;
178
+ result.success = true;
179
+ }
180
+ catch (e) {
181
+ result.errors.push({ message: e.message, name: e.name, file: null });
182
+ }
183
+ return result;
184
+ }
185
+ module.exports.bundle = bundle;