@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/checker.js
CHANGED
package/src/self/cli.flux
CHANGED
|
@@ -73,14 +73,13 @@ fn showHelp():
|
|
|
73
73
|
console.log(bold("COMPILER:"))
|
|
74
74
|
val compilerCmds = [
|
|
75
75
|
["compile <file.flux>", "Compile .flux → .js"],
|
|
76
|
-
["bundle <entry.flux>", "Bundle
|
|
77
|
-
["run <file.flux>", "Compile and run
|
|
76
|
+
["bundle <entry.flux>", "Bundle multiple files into one .js"],
|
|
77
|
+
["run <file.flux>", "Compile and run immediately"],
|
|
78
78
|
["watch <file.flux>", "Watch for changes, auto-compile"],
|
|
79
79
|
["check <file.flux>", "Type-check and static analysis"],
|
|
80
80
|
]
|
|
81
|
-
compilerCmds
|
|
82
|
-
console.log(" " + green(("flux " +
|
|
83
|
-
)
|
|
81
|
+
for [cmd, desc] in compilerCmds:
|
|
82
|
+
console.log(" " + green(("flux " + cmd).padEnd(36)) + " " + gray(desc))
|
|
84
83
|
|
|
85
84
|
console.log()
|
|
86
85
|
console.log(bold("TOOLING:"))
|
|
@@ -92,25 +91,23 @@ fn showHelp():
|
|
|
92
91
|
["tokens <file.flux>", "Show lexer token list"],
|
|
93
92
|
["ast <file.flux>", "Show Abstract Syntax Tree (JSON)"],
|
|
94
93
|
]
|
|
95
|
-
toolCmds
|
|
96
|
-
console.log(" " + green(("flux " +
|
|
97
|
-
)
|
|
94
|
+
for [cmd, desc] in toolCmds:
|
|
95
|
+
console.log(" " + green(("flux " + cmd).padEnd(36)) + " " + gray(desc))
|
|
98
96
|
|
|
99
97
|
console.log()
|
|
100
98
|
console.log(bold("PACKAGE MANAGER:"))
|
|
101
99
|
val pkgCmds = [
|
|
102
|
-
["init [name]
|
|
103
|
-
["add <pkg[@version]>", "Add a dependency
|
|
104
|
-
["remove <pkg>", "Remove a dependency
|
|
105
|
-
["install", "Install all dependencies
|
|
100
|
+
["init [name]", "Scaffold a new Flux project"],
|
|
101
|
+
["add <pkg[@version]>", "Add a dependency"],
|
|
102
|
+
["remove <pkg>", "Remove a dependency"],
|
|
103
|
+
["install", "Install all dependencies"],
|
|
106
104
|
["list", "List installed packages"],
|
|
107
|
-
["search <query>", "Search the
|
|
105
|
+
["search <query>", "Search the package registry"],
|
|
108
106
|
["info <pkg>", "Show package details"],
|
|
109
|
-
["publish", "Publish package to
|
|
107
|
+
["publish", "Publish package to registry"],
|
|
110
108
|
]
|
|
111
|
-
pkgCmds
|
|
112
|
-
console.log(" " + cyan(("flux " +
|
|
113
|
-
)
|
|
109
|
+
for [cmd, desc] in pkgCmds:
|
|
110
|
+
console.log(" " + cyan(("flux " + cmd).padEnd(36)) + " " + gray(desc))
|
|
114
111
|
|
|
115
112
|
console.log()
|
|
116
113
|
console.log(bold("SELF-HOSTED:"))
|
|
@@ -119,9 +116,8 @@ fn showHelp():
|
|
|
119
116
|
["self-hosted build", "Bootstrap: compile compiler with itself"],
|
|
120
117
|
["self-hosted verify", "Verify self-hosted output matches stage-0"],
|
|
121
118
|
]
|
|
122
|
-
selfCmds
|
|
123
|
-
console.log(" " + yellow(("flux " +
|
|
124
|
-
)
|
|
119
|
+
for [cmd, desc] in selfCmds:
|
|
120
|
+
console.log(" " + yellow(("flux " + cmd).padEnd(36)) + " " + gray(desc))
|
|
125
121
|
|
|
126
122
|
console.log()
|
|
127
123
|
console.log(bold("OPTIONS:"))
|
|
@@ -132,7 +128,6 @@ fn showHelp():
|
|
|
132
128
|
console.log(" " + yellow("--typecheck ") + " Enable type checking")
|
|
133
129
|
console.log(" " + yellow("--stdout ") + " Print to terminal")
|
|
134
130
|
console.log(" " + yellow("--no-color ") + " Disable colors")
|
|
135
|
-
console.log(" " + yellow("--template ") + " Init template: script, server, webapp")
|
|
136
131
|
console.log()
|
|
137
132
|
|
|
138
133
|
// ── Parse CLI args ────────────────────────────────────────────
|
|
@@ -150,7 +145,6 @@ fn parseArgs(argv):
|
|
|
150
145
|
verbose: false,
|
|
151
146
|
jsx: false,
|
|
152
147
|
jsxTarget: "browser",
|
|
153
|
-
template: null,
|
|
154
148
|
}
|
|
155
149
|
val positional = []
|
|
156
150
|
var i = 0
|
|
@@ -180,9 +174,6 @@ fn parseArgs(argv):
|
|
|
180
174
|
else if a == "--jsx-target":
|
|
181
175
|
i = i + 1
|
|
182
176
|
opts.jsxTarget = args[i]
|
|
183
|
-
else if a == "--template" or a == "-t":
|
|
184
|
-
i = i + 1
|
|
185
|
-
opts.template = args[i]
|
|
186
177
|
else if not a.startsWith("--"):
|
|
187
178
|
positional.push(a)
|
|
188
179
|
i = i + 1
|
|
@@ -245,22 +236,6 @@ fn printErrors(errors, source, filePath):
|
|
|
245
236
|
console.error(cyan(" Hint: ") + gray(err.hint))
|
|
246
237
|
console.error()
|
|
247
238
|
|
|
248
|
-
// ── Detect inter-file .flux imports in source ─────────────────
|
|
249
|
-
fn findFluxImports(source):
|
|
250
|
-
val found = []
|
|
251
|
-
val lines = source.split("\n")
|
|
252
|
-
for line in lines:
|
|
253
|
-
val trimmed = line.trim()
|
|
254
|
-
// Match: import ... from "./something" or import ... from "../something"
|
|
255
|
-
// where the path is relative (starts with ./ or ../)
|
|
256
|
-
val m = trimmed.match(/^import\s+.+\s+from\s+["'](\.[^"']+)["']/)
|
|
257
|
-
if m:
|
|
258
|
-
val src = m[1]
|
|
259
|
-
// Relative import to a .flux file (explicit or implicit extension)
|
|
260
|
-
if not src.endsWith(".js") and not src.endsWith(".json") and not src.endsWith(".node"):
|
|
261
|
-
found.push(src)
|
|
262
|
-
return found
|
|
263
|
-
|
|
264
239
|
// ══════════════════════════════════════════════════════════════
|
|
265
240
|
// Commands
|
|
266
241
|
// ══════════════════════════════════════════════════════════════
|
|
@@ -315,23 +290,6 @@ fn cmdCompile(filePath, opts):
|
|
|
315
290
|
// ── flux run ──────────────────────────────────────────────────
|
|
316
291
|
fn cmdRun(filePath, opts):
|
|
317
292
|
val { source, abs } = readFluxFile(filePath)
|
|
318
|
-
|
|
319
|
-
// Detect inter-file .flux imports — flux run cannot handle them
|
|
320
|
-
val fluxImports = findFluxImports(source)
|
|
321
|
-
if fluxImports.length > 0:
|
|
322
|
-
val example = fluxImports[0]
|
|
323
|
-
val entryRel = Path.relative(process.cwd(), abs)
|
|
324
|
-
val outFile = Path.basename(abs, ".flux") + ".js"
|
|
325
|
-
console.error(red("\n✗ Cannot run a multi-file Flux project with `flux run`.\n"))
|
|
326
|
-
console.error(" Found: " + yellow("import ... from \"" + example + "\""))
|
|
327
|
-
console.error()
|
|
328
|
-
console.error(" Use " + cyan("flux bundle") + " to compile all files into one, then run it:\n")
|
|
329
|
-
console.error(" " + yellow("flux bundle " + entryRel + " -o dist/" + outFile))
|
|
330
|
-
console.error(" " + yellow("node dist/" + outFile))
|
|
331
|
-
console.error()
|
|
332
|
-
console.error(" Or use " + cyan("flux run") + " only for single-file scripts (no inter-file .flux imports).\n")
|
|
333
|
-
process.exit(1)
|
|
334
|
-
|
|
335
293
|
val result = transpile(source, {
|
|
336
294
|
jsx: opts.jsx ?? false,
|
|
337
295
|
jsxTarget: opts.jsxTarget ?? "browser",
|
|
@@ -488,11 +446,6 @@ fn cmdBundle(entryPath, opts):
|
|
|
488
446
|
console.log(result.code)
|
|
489
447
|
return
|
|
490
448
|
|
|
491
|
-
// Ensure output directory exists
|
|
492
|
-
val outDir = Path.dirname(Path.resolve(outFile))
|
|
493
|
-
if not Fs.existsSync(outDir):
|
|
494
|
-
Fs.mkdirSync(outDir, { recursive: true })
|
|
495
|
-
|
|
496
449
|
Fs.writeFileSync(outFile, result.code, "utf8")
|
|
497
450
|
val kb = (result.code.length / 1024).toFixed(1)
|
|
498
451
|
console.log(
|
|
@@ -625,8 +578,7 @@ fn cmdRepl(opts):
|
|
|
625
578
|
// ── flux init ────────────────────────────────────────────────
|
|
626
579
|
fn cmdInit(name, opts):
|
|
627
580
|
val projectName = name ?? "my-flux-app"
|
|
628
|
-
val
|
|
629
|
-
val dir = Path.resolve(projectName)
|
|
581
|
+
val dir = Path.resolve(projectName)
|
|
630
582
|
|
|
631
583
|
if Fs.existsSync(dir):
|
|
632
584
|
console.error(red("✗ Directory already exists: " + projectName))
|
|
@@ -636,251 +588,246 @@ fn cmdInit(name, opts):
|
|
|
636
588
|
Fs.mkdirSync(Path.join(dir, "src"), { recursive: true })
|
|
637
589
|
Fs.mkdirSync(Path.join(dir, "tests"), { recursive: true })
|
|
638
590
|
|
|
639
|
-
val
|
|
591
|
+
val mainFlux = `// {projectName} — built with Flux Lang v{VERSION}
|
|
592
|
+
// Run: flux run src/main.flux
|
|
593
|
+
|
|
594
|
+
// ── Algebraic Data Types + Pattern Matching ───────────────────
|
|
595
|
+
type Shape = Circle(radius) | Rect(width, height) | Triangle(base, height)
|
|
596
|
+
|
|
597
|
+
fn area(shape):
|
|
598
|
+
match shape:
|
|
599
|
+
when Circle(r): return Math.PI * r * r
|
|
600
|
+
when Rect(w, h): return w * h
|
|
601
|
+
when Triangle(b, h): return 0.5 * b * h
|
|
602
|
+
|
|
603
|
+
fn describe(shape):
|
|
604
|
+
match shape:
|
|
605
|
+
when Circle(r): return "Circle(r={r:.2f})"
|
|
606
|
+
when Rect(w, h): return "Rect({w:.1f}x{h:.1f})"
|
|
607
|
+
when Triangle(b, h): return "Triangle(b={b:.1f}, h={h:.1f})"
|
|
608
|
+
|
|
609
|
+
// ── Result type ───────────────────────────────────────────────
|
|
610
|
+
type Result = Ok(value) | Err(message)
|
|
611
|
+
|
|
612
|
+
fn safeDivide(a, b):
|
|
613
|
+
if b == 0: return Err("division by zero")
|
|
614
|
+
return Ok(a / b)
|
|
615
|
+
|
|
616
|
+
// ── Utility functions ─────────────────────────────────────────
|
|
617
|
+
fn greet(name): return "Hello from Flux, {name}!"
|
|
618
|
+
|
|
619
|
+
fn formatList(items):
|
|
620
|
+
if items.length == 0: return "(empty)"
|
|
621
|
+
return "[" + items.join(", ") + "]"
|
|
622
|
+
|
|
623
|
+
fn clamp(value, lo, hi):
|
|
624
|
+
if value < lo: return lo
|
|
625
|
+
if value > hi: return hi
|
|
626
|
+
return value
|
|
627
|
+
|
|
628
|
+
// ── Pipe operator + stdlib ────────────────────────────────────
|
|
629
|
+
val numbers = [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5]
|
|
630
|
+
val processed = numbers
|
|
631
|
+
|> filter(n -> n > 3)
|
|
632
|
+
|> map(n -> n * n)
|
|
633
|
+
|> sort
|
|
634
|
+
|
|
635
|
+
// ── Main ──────────────────────────────────────────────────────
|
|
636
|
+
print(greet("{projectName}"))
|
|
637
|
+
print("Squares > 3: {formatList(processed)}")
|
|
638
|
+
print("clamp(12, 0, 10) = {clamp(12, 0, 10)}")
|
|
639
|
+
|
|
640
|
+
val shapes = [Circle(5.0), Rect(8.0, 3.0), Triangle(6.0, 4.0)]
|
|
641
|
+
for shape in shapes:
|
|
642
|
+
val a = area(shape)
|
|
643
|
+
print("{describe(shape)} area={a:.2f}")
|
|
644
|
+
|
|
645
|
+
match safeDivide(10.0, 3.0):
|
|
646
|
+
when Ok(v): print("10 / 3 = {v:.4f}")
|
|
647
|
+
when Err(e): print("Error: {e}")
|
|
648
|
+
`
|
|
649
|
+
|
|
650
|
+
val utilsFlux = `// Utility functions for {projectName}
|
|
651
|
+
// Use with: flux bundle src/main.flux (bundles imports automatically)
|
|
652
|
+
|
|
653
|
+
export fn greet(name):
|
|
654
|
+
return "Hello from Flux, {name}!"
|
|
655
|
+
|
|
656
|
+
export fn formatList(items):
|
|
657
|
+
if items.length == 0: return "(empty)"
|
|
658
|
+
return "[" + items.join(", ") + "]"
|
|
659
|
+
|
|
660
|
+
export fn clamp(value, lo, hi):
|
|
661
|
+
if value < lo: return lo
|
|
662
|
+
if value > hi: return hi
|
|
663
|
+
return value
|
|
664
|
+
|
|
665
|
+
export fn sum(nums):
|
|
666
|
+
return nums.reduce((acc, x) -> acc + x, 0)
|
|
667
|
+
|
|
668
|
+
export fn average(nums):
|
|
669
|
+
if nums.length == 0: return 0
|
|
670
|
+
return sum(nums) / nums.length
|
|
671
|
+
`
|
|
640
672
|
|
|
641
673
|
val testFlux = `// Tests for {projectName}
|
|
642
674
|
// Run: flux test tests/
|
|
643
675
|
|
|
676
|
+
// ── Functions under test ──────────────────────────────────────
|
|
644
677
|
fn add(a, b):
|
|
645
678
|
return a + b
|
|
646
679
|
|
|
680
|
+
fn mul(a, b):
|
|
681
|
+
return a * b
|
|
682
|
+
|
|
647
683
|
fn clamp(value, lo, hi):
|
|
648
684
|
if value < lo: return lo
|
|
649
685
|
if value > hi: return hi
|
|
650
686
|
return value
|
|
651
687
|
|
|
688
|
+
fn average(nums):
|
|
689
|
+
if nums.length == 0: return 0
|
|
690
|
+
return nums.reduce((s, x) -> s + x, 0) / nums.length
|
|
691
|
+
|
|
692
|
+
type Result = Ok(value) | Err(message)
|
|
693
|
+
|
|
694
|
+
fn safeDivide(a, b):
|
|
695
|
+
if b == 0: return Err("div by zero")
|
|
696
|
+
return Ok(a / b)
|
|
697
|
+
|
|
698
|
+
// ── Test functions ────────────────────────────────────────────
|
|
652
699
|
fn test_add():
|
|
653
700
|
assert(add(1, 2) == 3, "1+2=3")
|
|
654
701
|
assert(add(0, 0) == 0, "0+0=0")
|
|
655
702
|
assert(add(-1, 1) == 0, "-1+1=0")
|
|
656
703
|
|
|
704
|
+
fn test_mul():
|
|
705
|
+
assert(mul(3, 4) == 12, "3*4=12")
|
|
706
|
+
assert(mul(0, 5) == 0, "0*5=0")
|
|
707
|
+
|
|
657
708
|
fn test_clamp():
|
|
658
709
|
assert(clamp(5, 0, 10) == 5, "within range")
|
|
659
710
|
assert(clamp(-1, 0, 10) == 0, "below min")
|
|
660
711
|
assert(clamp(15, 0, 10) == 10, "above max")
|
|
661
|
-
`
|
|
662
|
-
|
|
663
|
-
// ── Template: script (default) — single file, no inter-file imports ──
|
|
664
|
-
if template == "script":
|
|
665
|
-
val mainFlux = `// {projectName} — a Flux script
|
|
666
|
-
// Run: npm run dev (or: node_modules/.bin/flux run src/main.flux)
|
|
667
|
-
|
|
668
|
-
import Fs from "fs"
|
|
669
|
-
import Path from "path"
|
|
670
712
|
|
|
671
|
-
fn
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
713
|
+
fn test_average():
|
|
714
|
+
assert(average([2, 4, 6]) == 4, "average of 2,4,6")
|
|
715
|
+
assert(average([]) == 0, "empty list")
|
|
716
|
+
|
|
717
|
+
fn test_safe_divide():
|
|
718
|
+
val ok = safeDivide(10, 2)
|
|
719
|
+
match ok:
|
|
720
|
+
when Ok(v): assert(v == 5, "10/2=5")
|
|
721
|
+
when Err(e): assert(false, "unexpected error")
|
|
722
|
+
val err = safeDivide(10, 0)
|
|
723
|
+
match err:
|
|
724
|
+
when Ok(v): assert(false, "expected error")
|
|
725
|
+
when Err(e): assert(e == "div by zero", "error message")
|
|
726
|
+
|
|
727
|
+
fn test_pipe_operator():
|
|
728
|
+
val result = [1, 2, 3, 4, 5] |> filter(n -> n > 2) |> map(n -> n * 2)
|
|
729
|
+
assert(result.length == 3, "filter length")
|
|
730
|
+
assert(result[0] == 6, "first element")
|
|
731
|
+
assert(result[2] == 10, "last element")
|
|
676
732
|
`
|
|
677
733
|
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
flux
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
Fs.writeFileSync(Path.join(dir, "src", "main.flux"), mainFlux, "utf8")
|
|
702
|
-
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8")
|
|
703
|
-
Fs.writeFileSync(Path.join(dir, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n", "utf8")
|
|
704
|
-
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8")
|
|
705
|
-
|
|
706
|
-
console.log()
|
|
707
|
-
console.log(green("✓ Project ") + bold(projectName + "/") + green(" created with template ") + cyan("script"))
|
|
708
|
-
console.log()
|
|
709
|
-
console.log(bold(" Next steps:"))
|
|
710
|
-
console.log(" " + yellow("cd " + projectName))
|
|
711
|
-
console.log(" " + yellow("npm install"))
|
|
712
|
-
console.log(" " + yellow("npm run dev"))
|
|
713
|
-
console.log()
|
|
714
|
-
console.log(gray(" Add packages:"))
|
|
715
|
-
console.log(" " + yellow("flux add <package>"))
|
|
716
|
-
console.log()
|
|
717
|
-
return
|
|
718
|
-
|
|
719
|
-
// ── Template: server — Express HTTP server, single file ──
|
|
720
|
-
if template == "server":
|
|
721
|
-
val serverFlux = `// {projectName} — Flux HTTP server
|
|
722
|
-
// Run: npm run dev
|
|
723
|
-
// Build: npm run build && npm start
|
|
734
|
+
val fluxJson = {
|
|
735
|
+
name: projectName,
|
|
736
|
+
version: "1.0.0",
|
|
737
|
+
description: "A Flux Lang v" + VERSION + " project",
|
|
738
|
+
author: "",
|
|
739
|
+
license: "MIT",
|
|
740
|
+
entry: "src/main.flux",
|
|
741
|
+
outDir: "dist",
|
|
742
|
+
sourcemap: false,
|
|
743
|
+
typecheck: true,
|
|
744
|
+
scripts: {
|
|
745
|
+
start: "flux run src/main.flux",
|
|
746
|
+
build: "flux bundle src/main.flux -o dist/bundle.js",
|
|
747
|
+
dev: "flux watch src/main.flux",
|
|
748
|
+
check: "flux check src/main.flux",
|
|
749
|
+
test: "flux test tests/",
|
|
750
|
+
fmt: "flux fmt src/",
|
|
751
|
+
lint: "flux lint src/",
|
|
752
|
+
},
|
|
753
|
+
dependencies: {},
|
|
754
|
+
devDependencies: { "@xnoxs/flux-lang": "^" + VERSION },
|
|
755
|
+
}
|
|
724
756
|
|
|
725
|
-
|
|
757
|
+
val gitignore = "node_modules/\ndist/\nflux_modules/\n*.js.map\n.DS_Store\n"
|
|
726
758
|
|
|
727
|
-
val
|
|
728
|
-
val PORT = process.env.PORT or 3000
|
|
759
|
+
val readme = `# {projectName}
|
|
729
760
|
|
|
730
|
-
|
|
761
|
+
A project built with [Flux Lang](https://flux-lang.dev) v{VERSION} — the self-hosted compiler.
|
|
731
762
|
|
|
732
|
-
|
|
733
|
-
res.json({ status: "ok", message: "Hello from Flux!", port: PORT })
|
|
734
|
-
)
|
|
763
|
+
## Quick Start
|
|
735
764
|
|
|
736
|
-
|
|
737
|
-
|
|
765
|
+
\`\`\`bash
|
|
766
|
+
flux run src/main.flux
|
|
767
|
+
\`\`\`
|
|
738
768
|
|
|
739
|
-
|
|
740
|
-
name: projectName,
|
|
741
|
-
version: "1.0.0",
|
|
742
|
-
description: "A Flux HTTP server",
|
|
743
|
-
main: "dist/server.js",
|
|
744
|
-
scripts: {
|
|
745
|
-
dev: "flux run src/server.flux",
|
|
746
|
-
build: "flux bundle src/server.flux -o dist/server.js",
|
|
747
|
-
start: "node dist/server.js",
|
|
748
|
-
test: "flux test tests/",
|
|
749
|
-
},
|
|
750
|
-
flux: {
|
|
751
|
-
entry: "src/server.flux",
|
|
752
|
-
outDir: "dist",
|
|
753
|
-
mangle: false,
|
|
754
|
-
sourcemap: false,
|
|
755
|
-
},
|
|
756
|
-
dependencies: {
|
|
757
|
-
"@xnoxs/flux-lang": "^" + VERSION,
|
|
758
|
-
"express": "^4.18.0",
|
|
759
|
-
},
|
|
760
|
-
devDependencies: {},
|
|
761
|
-
}
|
|
762
|
-
|
|
763
|
-
Fs.writeFileSync(Path.join(dir, "src", "server.flux"), serverFlux, "utf8")
|
|
764
|
-
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8")
|
|
765
|
-
Fs.writeFileSync(Path.join(dir, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n", "utf8")
|
|
766
|
-
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8")
|
|
769
|
+
## Project Structure
|
|
767
770
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
return
|
|
771
|
+
\`\`\`
|
|
772
|
+
{projectName}/
|
|
773
|
+
├── src/
|
|
774
|
+
│ ├── main.flux # Entry point
|
|
775
|
+
│ └── utils.flux # Utility functions
|
|
776
|
+
├── tests/
|
|
777
|
+
│ └── main.test.flux # Test suite
|
|
778
|
+
├── flux_modules/ # Packages installed by \`flux install\` (gitignored)
|
|
779
|
+
├── flux.json # Project config & dependencies
|
|
780
|
+
└── README.md
|
|
781
|
+
\`\`\`
|
|
780
782
|
|
|
781
|
-
|
|
782
|
-
if template == "webapp":
|
|
783
|
-
val utilsFlux = `// Utility functions
|
|
784
|
-
export fn formatDate(date):
|
|
785
|
-
val d = new Date(date)
|
|
786
|
-
return d.toISOString().split("T")[0]
|
|
783
|
+
## Commands
|
|
787
784
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
785
|
+
| Command | Description |
|
|
786
|
+
|---|---|
|
|
787
|
+
| \`flux run src/main.flux\` | Run the project |
|
|
788
|
+
| \`flux bundle src/main.flux -o dist/bundle.js\` | Bundle to single file |
|
|
789
|
+
| \`flux watch src/main.flux\` | Watch mode |
|
|
790
|
+
| \`flux check src/main.flux\` | Type check + static analysis |
|
|
791
|
+
| \`flux test tests/\` | Run all tests |
|
|
792
|
+
| \`flux fmt src/\` | Format source code |
|
|
793
|
+
| \`flux lint src/\` | Lint for issues |
|
|
794
|
+
| \`flux add <package>\` | Add a dependency |
|
|
791
795
|
`
|
|
792
796
|
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
]
|
|
801
|
-
|
|
802
|
-
export fn setupRoutes(app):
|
|
803
|
-
app.get("/items", (req, res) ->
|
|
804
|
-
val page = parseInt(req.query.page or "1")
|
|
805
|
-
val perPage = parseInt(req.query.per_page or "10")
|
|
806
|
-
val data = paginate(items, page, perPage)
|
|
807
|
-
res.json({ data, page })
|
|
808
|
-
)
|
|
809
|
-
|
|
810
|
-
app.get("/items/:id", (req, res) ->
|
|
811
|
-
val item = items.find(i -> i.id == parseInt(req.params.id))
|
|
812
|
-
if item == null:
|
|
813
|
-
res.status(404).json({ error: "Not found" })
|
|
814
|
-
else:
|
|
815
|
-
res.json({ data: item, date: formatDate(item.date) })
|
|
816
|
-
)
|
|
817
|
-
`
|
|
818
|
-
|
|
819
|
-
val serverFlux = `// Entry point — MUST be compiled with: npm run build
|
|
820
|
-
// Inter-file .flux imports only work via flux bundle, NOT flux run
|
|
821
|
-
import Express from "express"
|
|
822
|
-
import { setupRoutes } from "./routes" // inter-file .flux import
|
|
823
|
-
|
|
824
|
-
val app = Express()
|
|
825
|
-
val PORT = process.env.PORT or 3000
|
|
826
|
-
|
|
827
|
-
app.use(Express.json())
|
|
828
|
-
setupRoutes(app)
|
|
829
|
-
|
|
830
|
-
app.listen(PORT, -> print("{projectName} running at http://localhost:{PORT}"))
|
|
831
|
-
`
|
|
797
|
+
val allFiles = [
|
|
798
|
+
projectName + "/src/main.flux",
|
|
799
|
+
projectName + "/src/utils.flux",
|
|
800
|
+
projectName + "/tests/main.test.flux",
|
|
801
|
+
projectName + "/flux.json",
|
|
802
|
+
projectName + "/.gitignore",
|
|
803
|
+
projectName + "/README.md",
|
|
804
|
+
]
|
|
832
805
|
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
build: "flux bundle src/server.flux -o dist/server.js",
|
|
840
|
-
start: "node dist/server.js",
|
|
841
|
-
dev: "flux bundle src/server.flux -o dist/server.js && node dist/server.js",
|
|
842
|
-
watch: "flux watch src/server.flux",
|
|
843
|
-
test: "flux test tests/",
|
|
844
|
-
},
|
|
845
|
-
flux: {
|
|
846
|
-
entry: "src/server.flux",
|
|
847
|
-
outDir: "dist",
|
|
848
|
-
mangle: false,
|
|
849
|
-
sourcemap: true,
|
|
850
|
-
},
|
|
851
|
-
dependencies: {
|
|
852
|
-
"@xnoxs/flux-lang": "^" + VERSION,
|
|
853
|
-
"express": "^4.18.0",
|
|
854
|
-
},
|
|
855
|
-
devDependencies: {},
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
Fs.writeFileSync(Path.join(dir, "src", "utils.flux"), utilsFlux, "utf8")
|
|
859
|
-
Fs.writeFileSync(Path.join(dir, "src", "routes.flux"), routesFlux, "utf8")
|
|
860
|
-
Fs.writeFileSync(Path.join(dir, "src", "server.flux"), serverFlux, "utf8")
|
|
861
|
-
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8")
|
|
862
|
-
Fs.writeFileSync(Path.join(dir, "package.json"), JSON.stringify(pkgJson, null, 2) + "\n", "utf8")
|
|
863
|
-
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8")
|
|
806
|
+
Fs.writeFileSync(Path.join(dir, "src", "main.flux"), mainFlux, "utf8")
|
|
807
|
+
Fs.writeFileSync(Path.join(dir, "src", "utils.flux"), utilsFlux, "utf8")
|
|
808
|
+
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8")
|
|
809
|
+
Fs.writeFileSync(Path.join(dir, "flux.json"), JSON.stringify(fluxJson, null, 2) + "\n", "utf8")
|
|
810
|
+
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8")
|
|
811
|
+
Fs.writeFileSync(Path.join(dir, "README.md"), readme, "utf8")
|
|
864
812
|
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
console.log("
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
console.
|
|
882
|
-
console.
|
|
883
|
-
process.exit(1)
|
|
813
|
+
console.log()
|
|
814
|
+
console.log(green("✓ Created: ") + bold(projectName + "/"))
|
|
815
|
+
console.log()
|
|
816
|
+
console.log(gray(" Files:"))
|
|
817
|
+
for f in allFiles:
|
|
818
|
+
console.log(" " + cyan(f))
|
|
819
|
+
console.log()
|
|
820
|
+
console.log(bold(" Next steps:"))
|
|
821
|
+
console.log(" " + yellow("cd " + projectName))
|
|
822
|
+
console.log(" " + yellow("flux run src/main.flux"))
|
|
823
|
+
console.log()
|
|
824
|
+
console.log(gray(" Add packages (installed into flux_modules/):"))
|
|
825
|
+
console.log(" " + yellow("flux add <package>"))
|
|
826
|
+
console.log(" " + yellow("flux install"))
|
|
827
|
+
console.log()
|
|
828
|
+
console.log(gray(" Or run the test suite:"))
|
|
829
|
+
console.log(" " + yellow("flux test tests/"))
|
|
830
|
+
console.log()
|
|
884
831
|
|
|
885
832
|
// ── flux self-hosted ──────────────────────────────────────────
|
|
886
833
|
fn cmdSelfHosted(sub, opts):
|
|
@@ -1028,7 +975,6 @@ fn main():
|
|
|
1028
975
|
when "tokens": cmdTokens(positional[1], opts)
|
|
1029
976
|
when "ast": cmdAst(positional[1], opts)
|
|
1030
977
|
when "repl": cmdRepl(opts)
|
|
1031
|
-
when "test": runTests(positional[1] ?? 'tests/', src -> transpile(src, {}))
|
|
1032
978
|
when "init": cmdInit(positional[1], opts)
|
|
1033
979
|
when "add": cmdAdd(positional.slice(1), opts)
|
|
1034
980
|
when "remove": cmdRemove(positional.slice(1), opts)
|