@xnoxs/flux-lang 4.0.7 → 4.0.9
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 +0 -12
- package/dist/flux-cli.js +558 -550
- package/dist/flux.cjs.js +3689 -5548
- package/dist/flux.esm.js +3691 -5545
- package/dist/flux.min.js +95 -356
- package/index.js +10 -9
- package/package.json +5 -4
- package/src/config.js +86 -101
- package/src/formatter.js +100 -105
- package/src/self/bundler.flux +16 -21
- package/src/self/bundler.js +28 -16
- package/src/self/checker.js +2 -0
- package/src/self/cli.flux +220 -274
- package/src/self/cli.js +59 -123
- package/src/self/codegen.js +811 -1
- package/src/self/config.flux +28 -36
- package/src/self/config.js +32 -33
- package/src/self/css-preprocessor.js +3 -1
- package/src/self/formatter.js +2 -0
- package/src/self/index.flux +87 -0
- package/src/self/jsx.js +4 -2
- package/src/self/lexer.js +8 -6
- package/src/self/linter.js +2 -0
- package/src/self/mangler.js +2 -0
- package/src/self/parser.js +2 -0
- package/src/self/pkg.flux +136 -39
- package/src/self/pkg.js +125 -36
- package/src/self/sourcemap.js +2 -0
- package/src/self/stdlib.js +2 -0
- package/src/self/test-runner.js +2 -0
- package/src/self/transpiler.js +2 -0
- package/src/self/type-checker.js +2 -0
- package/src/stdlib.js +218 -731
- package/dist/transpiler.js +0 -4
package/src/self/cli.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
/* compiled from src/self/cli.flux */
|
|
1
|
+
/* compiled from src/self/cli.flux by Flux Lang */
|
|
2
2
|
'use strict';
|
|
3
3
|
// ── Flux stdlib ──
|
|
4
4
|
|
|
5
|
-
function
|
|
5
|
+
function map(arr, fn) { return arr.map(fn); }
|
|
6
6
|
|
|
7
|
-
function
|
|
7
|
+
function filter(arr, fn) { return arr.filter(fn); }
|
|
8
|
+
|
|
9
|
+
function reduce(arr, fn, init) { return arguments.length >= 3 ? arr.reduce(fn, init) : arr.reduce(fn); }
|
|
8
10
|
|
|
9
11
|
function some(arr, fn) { return arr.some(fn); }
|
|
10
12
|
|
|
@@ -14,6 +16,10 @@ function clamp(val, min, max) {
|
|
|
14
16
|
return Math.min(Math.max(val, min), max);
|
|
15
17
|
}
|
|
16
18
|
|
|
19
|
+
function sum(arr) {
|
|
20
|
+
return arr.reduce(function(a, b) { return a + b; }, 0);
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
function max(arr) {
|
|
18
24
|
if (arguments.length > 1) return Math.max.apply(null, arguments);
|
|
19
25
|
return Math.max.apply(null, arr);
|
|
@@ -92,20 +98,32 @@ function showHelp() {
|
|
|
92
98
|
console.log(bold("USAGE:"));
|
|
93
99
|
console.log(" flux <command> [options]\n");
|
|
94
100
|
console.log(bold("COMPILER:"));
|
|
95
|
-
const compilerCmds = [["compile <file.flux>", "Compile .flux → .js"], ["bundle <entry.flux>", "Bundle
|
|
96
|
-
|
|
101
|
+
const compilerCmds = [["compile <file.flux>", "Compile .flux → .js"], ["bundle <entry.flux>", "Bundle multiple files into one .js"], ["run <file.flux>", "Compile and run immediately"], ["watch <file.flux>", "Watch for changes, auto-compile"], ["check <file.flux>", "Type-check and static analysis"]];
|
|
102
|
+
for (const __item__ of compilerCmds) {
|
|
103
|
+
const [cmd, desc] = __item__;
|
|
104
|
+
console.log((((" " + green(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
105
|
+
}
|
|
97
106
|
console.log();
|
|
98
107
|
console.log(bold("TOOLING:"));
|
|
99
108
|
const toolCmds = [["lint <file.flux>", "Full lint: types + style + immutability"], ["fmt <file.flux>", "Format source code in-place"], ["test [dir]", "Run *.test.flux files"], ["repl", "Interactive REPL mode"], ["tokens <file.flux>", "Show lexer token list"], ["ast <file.flux>", "Show Abstract Syntax Tree (JSON)"]];
|
|
100
|
-
|
|
109
|
+
for (const __item__ of toolCmds) {
|
|
110
|
+
const [cmd, desc] = __item__;
|
|
111
|
+
console.log((((" " + green(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
112
|
+
}
|
|
101
113
|
console.log();
|
|
102
114
|
console.log(bold("PACKAGE MANAGER:"));
|
|
103
|
-
const pkgCmds = [["init [name]
|
|
104
|
-
|
|
115
|
+
const pkgCmds = [["init [name]", "Scaffold a new Flux project"], ["add <pkg[@version]>", "Add a dependency"], ["remove <pkg>", "Remove a dependency"], ["install", "Install all dependencies"], ["list", "List installed packages"], ["search <query>", "Search the package registry"], ["info <pkg>", "Show package details"], ["publish", "Publish package to registry"]];
|
|
116
|
+
for (const __item__ of pkgCmds) {
|
|
117
|
+
const [cmd, desc] = __item__;
|
|
118
|
+
console.log((((" " + cyan(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
119
|
+
}
|
|
105
120
|
console.log();
|
|
106
121
|
console.log(bold("SELF-HOSTED:"));
|
|
107
122
|
const selfCmds = [["self-hosted", "Show self-hosted compiler status"], ["self-hosted build", "Bootstrap: compile compiler with itself"], ["self-hosted verify", "Verify self-hosted output matches stage-0"]];
|
|
108
|
-
|
|
123
|
+
for (const __item__ of selfCmds) {
|
|
124
|
+
const [cmd, desc] = __item__;
|
|
125
|
+
console.log((((" " + yellow(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
126
|
+
}
|
|
109
127
|
console.log();
|
|
110
128
|
console.log(bold("OPTIONS:"));
|
|
111
129
|
console.log(((" " + yellow("--out, -o <file> ")) + " Output file"));
|
|
@@ -115,12 +133,11 @@ function showHelp() {
|
|
|
115
133
|
console.log(((" " + yellow("--typecheck ")) + " Enable type checking"));
|
|
116
134
|
console.log(((" " + yellow("--stdout ")) + " Print to terminal"));
|
|
117
135
|
console.log(((" " + yellow("--no-color ")) + " Disable colors"));
|
|
118
|
-
console.log(((" " + yellow("--template ")) + " Init template: script, server, webapp"));
|
|
119
136
|
console.log();
|
|
120
137
|
}
|
|
121
138
|
function parseArgs(argv) {
|
|
122
139
|
const args = argv.slice(2);
|
|
123
|
-
const opts = { out: null, sourcemap: false, mangle: false, typecheck: false, strict: false, stdout: false, watch: false, dev: false, verbose: false, jsx: false, jsxTarget: "browser"
|
|
140
|
+
const opts = { out: null, sourcemap: false, mangle: false, typecheck: false, strict: false, stdout: false, watch: false, dev: false, verbose: false, jsx: false, jsxTarget: "browser" };
|
|
124
141
|
const positional = [];
|
|
125
142
|
let i = 0;
|
|
126
143
|
while ((i < args.length)) {
|
|
@@ -160,10 +177,6 @@ function parseArgs(argv) {
|
|
|
160
177
|
i = (i + 1);
|
|
161
178
|
opts.jsxTarget = args[i];
|
|
162
179
|
}
|
|
163
|
-
else if (((a == "--template") || (a == "-t"))) {
|
|
164
|
-
i = (i + 1);
|
|
165
|
-
opts.template = args[i];
|
|
166
|
-
}
|
|
167
180
|
else if (!a.startsWith("--")) {
|
|
168
181
|
positional.push(a);
|
|
169
182
|
}
|
|
@@ -232,21 +245,6 @@ function printErrors(errors, source, filePath) {
|
|
|
232
245
|
}
|
|
233
246
|
console.error();
|
|
234
247
|
}
|
|
235
|
-
function findFluxImports(source) {
|
|
236
|
-
const found = [];
|
|
237
|
-
const lines = source.split("\n");
|
|
238
|
-
for (const line of lines) {
|
|
239
|
-
const trimmed = line.trim();
|
|
240
|
-
const m = trimmed.match(/^import\s+.+\s+from\s+["'](\.[^"']+)["']/);
|
|
241
|
-
if (m) {
|
|
242
|
-
const src = m[1];
|
|
243
|
-
if (((!src.endsWith(".js") && !src.endsWith(".json")) && !src.endsWith(".node"))) {
|
|
244
|
-
found.push(src);
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
return found;
|
|
249
|
-
}
|
|
250
248
|
function cmdCompile(filePath, opts) {
|
|
251
249
|
const { source, abs } = readFluxFile(filePath);
|
|
252
250
|
const cfg = loadConfig(Path.dirname(abs));
|
|
@@ -280,21 +278,6 @@ function cmdCompile(filePath, opts) {
|
|
|
280
278
|
}
|
|
281
279
|
function cmdRun(filePath, opts) {
|
|
282
280
|
const { source, abs } = readFluxFile(filePath);
|
|
283
|
-
const fluxImports = findFluxImports(source);
|
|
284
|
-
if ((fluxImports.length > 0)) {
|
|
285
|
-
const example = fluxImports[0];
|
|
286
|
-
const entryRel = Path.relative(process.cwd(), abs);
|
|
287
|
-
const outFile = (Path.basename(abs, ".flux") + ".js");
|
|
288
|
-
console.error(red("\n✗ Cannot run a multi-file Flux project with `flux run`.\n"));
|
|
289
|
-
console.error((" Found: " + yellow((("import ... from \"" + example) + "\""))));
|
|
290
|
-
console.error();
|
|
291
|
-
console.error(((" Use " + cyan("flux bundle")) + " to compile all files into one, then run it:\n"));
|
|
292
|
-
console.error((" " + yellow(((("flux bundle " + entryRel) + " -o dist/") + outFile))));
|
|
293
|
-
console.error((" " + yellow(("node dist/" + outFile))));
|
|
294
|
-
console.error();
|
|
295
|
-
console.error(((" Or use " + cyan("flux run")) + " only for single-file scripts (no inter-file .flux imports).\n"));
|
|
296
|
-
process.exit(1);
|
|
297
|
-
}
|
|
298
281
|
const result = transpile(source, { jsx: (opts.jsx ?? false), jsxTarget: (opts.jsxTarget ?? "browser"), mangle: false });
|
|
299
282
|
if (!result.success) {
|
|
300
283
|
console.error(red("\n✗ Compile error"));
|
|
@@ -462,10 +445,6 @@ function cmdBundle(entryPath, opts) {
|
|
|
462
445
|
console.log(result.code);
|
|
463
446
|
return;
|
|
464
447
|
}
|
|
465
|
-
const outDir = Path.dirname(Path.resolve(outFile));
|
|
466
|
-
if (!Fs.existsSync(outDir)) {
|
|
467
|
-
Fs.mkdirSync(outDir, { recursive: true });
|
|
468
|
-
}
|
|
469
448
|
Fs.writeFileSync(outFile, result.code, "utf8");
|
|
470
449
|
const kb = (result.code.length / 1024).toFixed(1);
|
|
471
450
|
console.log((((((green("✓ Bundle done") + gray(((" (" + elapsed) + "ms) "))) + Path.basename(abs)) + gray(((" + " + (result.modules - 1)) + " module(s) → "))) + cyan(Path.relative(process.cwd(), outFile))) + gray(((" [" + kb) + " KB]"))));
|
|
@@ -596,7 +575,6 @@ function cmdRepl(opts) {
|
|
|
596
575
|
}
|
|
597
576
|
function cmdInit(name, opts) {
|
|
598
577
|
const projectName = (name ?? "my-flux-app");
|
|
599
|
-
const template = (opts.template ?? "script");
|
|
600
578
|
const dir = Path.resolve(projectName);
|
|
601
579
|
if (Fs.existsSync(dir)) {
|
|
602
580
|
console.error(red(("✗ Directory already exists: " + projectName)));
|
|
@@ -605,77 +583,38 @@ function cmdInit(name, opts) {
|
|
|
605
583
|
Fs.mkdirSync(dir, { recursive: true });
|
|
606
584
|
Fs.mkdirSync(Path.join(dir, "src"), { recursive: true });
|
|
607
585
|
Fs.mkdirSync(Path.join(dir, "tests"), { recursive: true });
|
|
608
|
-
const
|
|
609
|
-
const
|
|
610
|
-
if ((
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
console.log(("
|
|
627
|
-
console.log();
|
|
628
|
-
return;
|
|
629
|
-
}
|
|
630
|
-
if ((template == "server")) {
|
|
631
|
-
const serverFlux = "// {projectName} — Flux HTTP server\n// Run: npm run dev\n// Build: npm run build && npm start\n\nimport Express from \"express\"\n\nval app = Express()\nval PORT = process.env.PORT or 3000\n\napp.use(Express.json())\n\napp.get(\"/\", (req, res) ->\n res.json({ status: \"ok\", message: \"Hello from Flux!\", port: PORT })\n)\n\napp.listen(PORT, -> print(\"Server running at http://localhost:{PORT}\"))";
|
|
632
|
-
const pkgJson = { name: projectName, version: "1.0.0", description: "A Flux HTTP server", main: "dist/server.js", scripts: { dev: "flux run src/server.flux", build: "flux bundle src/server.flux -o dist/server.js", start: "node dist/server.js", test: "flux test tests/" }, flux: { entry: "src/server.flux", outDir: "dist", mangle: false, sourcemap: false }, dependencies: { "@xnoxs/flux-lang": ("^" + VERSION), express: "^4.18.0" }, devDependencies: { } };
|
|
633
|
-
Fs.writeFileSync(Path.join(dir, "src", "server.flux"), serverFlux, "utf8");
|
|
634
|
-
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8");
|
|
635
|
-
Fs.writeFileSync(Path.join(dir, "package.json"), (JSON.stringify(pkgJson, null, 2) + "\n"), "utf8");
|
|
636
|
-
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8");
|
|
637
|
-
console.log();
|
|
638
|
-
console.log((((green("✓ Project ") + bold((projectName + "/"))) + green(" created with template ")) + cyan("server")));
|
|
639
|
-
console.log();
|
|
640
|
-
console.log(bold(" Next steps:"));
|
|
641
|
-
console.log((" " + yellow(("cd " + projectName))));
|
|
642
|
-
console.log((" " + yellow("npm install")));
|
|
643
|
-
console.log((" " + yellow("npm run dev")));
|
|
644
|
-
console.log();
|
|
645
|
-
console.log(gray(" Build for production:"));
|
|
646
|
-
console.log((" " + yellow("npm run build && npm start")));
|
|
647
|
-
console.log();
|
|
648
|
-
return;
|
|
649
|
-
}
|
|
650
|
-
if ((template == "webapp")) {
|
|
651
|
-
const utilsFlux = "// Utility functions\nexport fn formatDate(date):\n val d = new Date(date)\n return d.toISOString().split(\"T\")[0]\n\nexport fn paginate(items, page, perPage):\n val start = (page - 1) * perPage\n return items.slice(start, start + perPage)";
|
|
652
|
-
const routesFlux = "// Route handlers\nimport { formatDate, paginate } from \"./utils\" // inter-file .flux import\n\nval items = [\n { id: 1, name: \"Item A\", date: \"2024-01-01\" },\n { id: 2, name: \"Item B\", date: \"2024-02-01\" },\n { id: 3, name: \"Item C\", date: \"2024-03-01\" },\n]\n\nexport fn setupRoutes(app):\n app.get(\"/items\", (req, res) ->\n val page = parseInt(req.query.page or \"1\")\n val perPage = parseInt(req.query.per_page or \"10\")\n val data = paginate(items, page, perPage)\n res.json({ data, page })\n )\n\n app.get(\"/items/:id\", (req, res) ->\n val item = items.find(i -> i.id == parseInt(req.params.id))\n if item == null:\n res.status(404).json({ error: \"Not found\" })\n else:\n res.json({ data: item, date: formatDate(item.date) })\n )";
|
|
653
|
-
const serverFlux = "// Entry point — MUST be compiled with: npm run build\n// Inter-file .flux imports only work via flux bundle, NOT flux run\nimport Express from \"express\"\nimport { setupRoutes } from \"./routes\" // inter-file .flux import\n\nval app = Express()\nval PORT = process.env.PORT or 3000\n\napp.use(Express.json())\nsetupRoutes(app)\n\napp.listen(PORT, -> print(\"{projectName} running at http://localhost:{PORT}\"))";
|
|
654
|
-
const pkgJson = { name: projectName, version: "1.0.0", description: "A Flux web app", main: "dist/server.js", scripts: { build: "flux bundle src/server.flux -o dist/server.js", start: "node dist/server.js", dev: "flux bundle src/server.flux -o dist/server.js && node dist/server.js", watch: "flux watch src/server.flux", test: "flux test tests/" }, flux: { entry: "src/server.flux", outDir: "dist", mangle: false, sourcemap: true }, dependencies: { "@xnoxs/flux-lang": ("^" + VERSION), express: "^4.18.0" }, devDependencies: { } };
|
|
655
|
-
Fs.writeFileSync(Path.join(dir, "src", "utils.flux"), utilsFlux, "utf8");
|
|
656
|
-
Fs.writeFileSync(Path.join(dir, "src", "routes.flux"), routesFlux, "utf8");
|
|
657
|
-
Fs.writeFileSync(Path.join(dir, "src", "server.flux"), serverFlux, "utf8");
|
|
658
|
-
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8");
|
|
659
|
-
Fs.writeFileSync(Path.join(dir, "package.json"), (JSON.stringify(pkgJson, null, 2) + "\n"), "utf8");
|
|
660
|
-
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8");
|
|
661
|
-
console.log();
|
|
662
|
-
console.log((((green("✓ Project ") + bold((projectName + "/"))) + green(" created with template ")) + cyan("webapp")));
|
|
663
|
-
console.log();
|
|
664
|
-
console.log(bold(" Next steps:"));
|
|
665
|
-
console.log((" " + yellow(("cd " + projectName))));
|
|
666
|
-
console.log(((" " + yellow("npm install")) + gray(" # install dependencies")));
|
|
667
|
-
console.log(((" " + yellow("npm run build")) + gray(" # compile all .flux → dist/server.js")));
|
|
668
|
-
console.log(((" " + yellow("npm start")) + gray(" # run the server")));
|
|
669
|
-
console.log();
|
|
670
|
-
console.log((yellow(" Note: ") + gray("This project uses multiple .flux files.")));
|
|
671
|
-
console.log(((gray(" Always build with ") + yellow("npm run build")) + gray(" (flux bundle) before running.")));
|
|
672
|
-
console.log(((gray(" Do NOT use ") + red("flux run")) + gray(" on files that import other .flux files.")));
|
|
673
|
-
console.log();
|
|
674
|
-
return;
|
|
586
|
+
const mainFlux = "// {projectName} — built with Flux Lang v{VERSION}\n// Run: flux run src/main.flux\n\n// ── Algebraic Data Types + Pattern Matching ───────────────────\ntype Shape = Circle(radius) | Rect(width, height) | Triangle(base, height)\n\nfn area(shape):\n match shape:\n when Circle(r): return Math.PI * r * r\n when Rect(w, h): return w * h\n when Triangle(b, h): return 0.5 * b * h\n\nfn describe(shape):\n match shape:\n when Circle(r): return \"Circle(r={r:.2f})\"\n when Rect(w, h): return \"Rect({w:.1f}x{h:.1f})\"\n when Triangle(b, h): return \"Triangle(b={b:.1f}, h={h:.1f})\"\n\n// ── Result type ───────────────────────────────────────────────\ntype Result = Ok(value) | Err(message)\n\nfn safeDivide(a, b):\n if b == 0: return Err(\"division by zero\")\n return Ok(a / b)\n\n// ── Utility functions ─────────────────────────────────────────\nfn greet(name): return \"Hello from Flux, {name}!\"\n\nfn formatList(items):\n if items.length == 0: return \"(empty)\"\n return \"[\" + items.join(\", \") + \"]\"\n\nfn clamp(value, lo, hi):\n if value < lo: return lo\n if value > hi: return hi\n return value\n\n// ── Pipe operator + stdlib ────────────────────────────────────\nval numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]\nval processed = numbers\n |> filter(n -> n > 3)\n |> map(n -> n * n)\n |> sort\n\n// ── Main ──────────────────────────────────────────────────────\nprint(greet(\"{projectName}\"))\nprint(\"Squares > 3: {formatList(processed)}\")\nprint(\"clamp(12, 0, 10) = {clamp(12, 0, 10)}\")\n\nval shapes = [Circle(5.0), Rect(8.0, 3.0), Triangle(6.0, 4.0)]\nfor shape in shapes:\n val a = area(shape)\n print(\"{describe(shape)} area={a:.2f}\")\n\nmatch safeDivide(10.0, 3.0):\n when Ok(v): print(\"10 / 3 = {v:.4f}\")\n when Err(e): print(\"Error: {e}\")";
|
|
587
|
+
const utilsFlux = "// Utility functions for {projectName}\n// Use with: flux bundle src/main.flux (bundles imports automatically)\n\nexport fn greet(name):\n return \"Hello from Flux, {name}!\"\n\nexport fn formatList(items):\n if items.length == 0: return \"(empty)\"\n return \"[\" + items.join(\", \") + \"]\"\n\nexport fn clamp(value, lo, hi):\n if value < lo: return lo\n if value > hi: return hi\n return value\n\nexport fn sum(nums):\n return nums.reduce((acc, x) -> acc + x, 0)\n\nexport fn average(nums):\n if nums.length == 0: return 0\n return sum(nums) / nums.length";
|
|
588
|
+
const testFlux = "// Tests for {projectName}\n// Run: flux test tests/\n\n// ── Functions under test ──────────────────────────────────────\nfn add(a, b):\n return a + b\n\nfn mul(a, b):\n return a * b\n\nfn clamp(value, lo, hi):\n if value < lo: return lo\n if value > hi: return hi\n return value\n\nfn average(nums):\n if nums.length == 0: return 0\n return nums.reduce((s, x) -> s + x, 0) / nums.length\n\ntype Result = Ok(value) | Err(message)\n\nfn safeDivide(a, b):\n if b == 0: return Err(\"div by zero\")\n return Ok(a / b)\n\n// ── Test functions ────────────────────────────────────────────\nfn test_add():\n assert(add(1, 2) == 3, \"1+2=3\")\n assert(add(0, 0) == 0, \"0+0=0\")\n assert(add(-1, 1) == 0, \"-1+1=0\")\n\nfn test_mul():\n assert(mul(3, 4) == 12, \"3*4=12\")\n assert(mul(0, 5) == 0, \"0*5=0\")\n\nfn test_clamp():\n assert(clamp(5, 0, 10) == 5, \"within range\")\n assert(clamp(-1, 0, 10) == 0, \"below min\")\n assert(clamp(15, 0, 10) == 10, \"above max\")\n\nfn test_average():\n assert(average([2, 4, 6]) == 4, \"average of 2,4,6\")\n assert(average([]) == 0, \"empty list\")\n\nfn test_safe_divide():\n val ok = safeDivide(10, 2)\n match ok:\n when Ok(v): assert(v == 5, \"10/2=5\")\n when Err(e): assert(false, \"unexpected error\")\n val err = safeDivide(10, 0)\n match err:\n when Ok(v): assert(false, \"expected error\")\n when Err(e): assert(e == \"div by zero\", \"error message\")\n\nfn test_pipe_operator():\n val result = [1, 2, 3, 4, 5] |> filter(n -> n > 2) |> map(n -> n * 2)\n assert(result.length == 3, \"filter length\")\n assert(result[0] == 6, \"first element\")\n assert(result[2] == 10, \"last element\")";
|
|
589
|
+
const fluxJson = { name: projectName, version: "1.0.0", description: (("A Flux Lang v" + VERSION) + " project"), author: "", license: "MIT", entry: "src/main.flux", outDir: "dist", sourcemap: false, typecheck: true, scripts: { start: "flux run src/main.flux", build: "flux bundle src/main.flux -o dist/bundle.js", dev: "flux watch src/main.flux", check: "flux check src/main.flux", test: "flux test tests/", fmt: "flux fmt src/", lint: "flux lint src/" }, dependencies: { }, devDependencies: { "@xnoxs/flux-lang": ("^" + VERSION) } };
|
|
590
|
+
const gitignore = "node_modules/\ndist/\nflux_modules/\n*.js.map\n.DS_Store\n";
|
|
591
|
+
const readme = "# {projectName}\n\nA project built with [Flux Lang](https://flux-lang.dev) v{VERSION} — the self-hosted compiler.\n\n## Quick Start\n\n```bash\nflux run src/main.flux\n```\n\n## Project Structure\n\n```\n{projectName}/\n├── src/\n│ ├── main.flux # Entry point\n│ └── utils.flux # Utility functions\n├── tests/\n│ └── main.test.flux # Test suite\n├── flux_modules/ # Packages installed by `flux install` (gitignored)\n├── flux.json # Project config & dependencies\n└── README.md\n```\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `flux run src/main.flux` | Run the project |\n| `flux bundle src/main.flux -o dist/bundle.js` | Bundle to single file |\n| `flux watch src/main.flux` | Watch mode |\n| `flux check src/main.flux` | Type check + static analysis |\n| `flux test tests/` | Run all tests |\n| `flux fmt src/` | Format source code |\n| `flux lint src/` | Lint for issues |\n| `flux add <package>` | Add a dependency |";
|
|
592
|
+
const allFiles = [(projectName + "/src/main.flux"), (projectName + "/src/utils.flux"), (projectName + "/tests/main.test.flux"), (projectName + "/flux.json"), (projectName + "/.gitignore"), (projectName + "/README.md")];
|
|
593
|
+
Fs.writeFileSync(Path.join(dir, "src", "main.flux"), mainFlux, "utf8");
|
|
594
|
+
Fs.writeFileSync(Path.join(dir, "src", "utils.flux"), utilsFlux, "utf8");
|
|
595
|
+
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8");
|
|
596
|
+
Fs.writeFileSync(Path.join(dir, "flux.json"), (JSON.stringify(fluxJson, null, 2) + "\n"), "utf8");
|
|
597
|
+
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8");
|
|
598
|
+
Fs.writeFileSync(Path.join(dir, "README.md"), readme, "utf8");
|
|
599
|
+
console.log();
|
|
600
|
+
console.log((green("✓ Created: ") + bold((projectName + "/"))));
|
|
601
|
+
console.log();
|
|
602
|
+
console.log(gray(" Files:"));
|
|
603
|
+
for (const f of allFiles) {
|
|
604
|
+
console.log((" " + cyan(f)));
|
|
675
605
|
}
|
|
676
|
-
console.
|
|
677
|
-
console.
|
|
678
|
-
|
|
606
|
+
console.log();
|
|
607
|
+
console.log(bold(" Next steps:"));
|
|
608
|
+
console.log((" " + yellow(("cd " + projectName))));
|
|
609
|
+
console.log((" " + yellow("flux run src/main.flux")));
|
|
610
|
+
console.log();
|
|
611
|
+
console.log(gray(" Add packages (installed into flux_modules/):"));
|
|
612
|
+
console.log((" " + yellow("flux add <package>")));
|
|
613
|
+
console.log((" " + yellow("flux install")));
|
|
614
|
+
console.log();
|
|
615
|
+
console.log(gray(" Or run the test suite:"));
|
|
616
|
+
console.log((" " + yellow("flux test tests/")));
|
|
617
|
+
console.log();
|
|
679
618
|
}
|
|
680
619
|
function cmdSelfHosted(sub, opts) {
|
|
681
620
|
const SELF = Path.join(__dirname, ".");
|
|
@@ -840,9 +779,6 @@ function main() {
|
|
|
840
779
|
else if (cmd === "repl") {
|
|
841
780
|
return cmdRepl(opts);
|
|
842
781
|
}
|
|
843
|
-
else if (cmd === "test") {
|
|
844
|
-
return runTests((positional[1] ?? "tests/"), (src) => transpile(src, { }));
|
|
845
|
-
}
|
|
846
782
|
else if (cmd === "init") {
|
|
847
783
|
return cmdInit(positional[1], opts);
|
|
848
784
|
}
|