@xnoxs/flux-lang 3.3.3 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -0
- package/README.md +112 -12
- package/dist/flux-cli.js +46 -26
- package/dist/flux.cjs.js +45 -25
- package/dist/flux.esm.js +45 -25
- package/dist/flux.min.js +40 -40
- package/package.json +1 -1
- package/src/self/bundler.js +7 -1
- package/src/self/checker.js +1 -1
- package/src/self/cli.flux +877 -0
- package/src/self/cli.js +818 -0
- package/src/self/codegen.js +11 -1
- package/src/self/config.flux +112 -0
- package/src/self/config.js +99 -0
- package/src/self/css-preprocessor.js +7 -1
- package/src/self/formatter.js +20 -1
- package/src/self/jsx.js +6 -0
- package/src/self/lexer.js +5 -1
- package/src/self/linter.js +5 -1
- package/src/self/mangler.js +2 -0
- package/src/self/parser.js +1 -1
- package/src/self/pkg.flux +301 -0
- package/src/self/pkg.js +288 -0
- package/src/self/sourcemap.js +1 -1
- package/src/self/stdlib.js +51 -36
- package/src/self/test-runner.js +7 -1
- package/src/self/transpiler.js +1 -1
- package/src/self/type-checker.js +9 -1
package/src/self/cli.js
ADDED
|
@@ -0,0 +1,818 @@
|
|
|
1
|
+
// ── Flux stdlib ──
|
|
2
|
+
|
|
3
|
+
function some(arr, fn) { return arr.some(fn); }
|
|
4
|
+
|
|
5
|
+
function join(arr, sep) { return arr.join(sep != null ? sep : ','); }
|
|
6
|
+
|
|
7
|
+
function max(arr) {
|
|
8
|
+
if (arguments.length > 1) return Math.max.apply(null, arguments);
|
|
9
|
+
return Math.max.apply(null, arr);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function padStart(s, len, char) {
|
|
13
|
+
return String(s).padStart(len, char || ' ');
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function padEnd(s, len, char) {
|
|
17
|
+
return String(s).padEnd(len, char || ' ');
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function trim(s) { return String(s).trim(); }
|
|
21
|
+
|
|
22
|
+
function trimEnd(s) { return String(s).trimEnd(); }
|
|
23
|
+
|
|
24
|
+
function startsWith(s, prefix) { return String(s).startsWith(prefix); }
|
|
25
|
+
|
|
26
|
+
function endsWith(s, suffix) { return String(s).endsWith(suffix); }
|
|
27
|
+
|
|
28
|
+
function repeat(s, n) { return String(s).repeat(n); }
|
|
29
|
+
// ── end stdlib ──
|
|
30
|
+
|
|
31
|
+
// Generated by Flux Transpiler v3.2.0
|
|
32
|
+
"use strict";
|
|
33
|
+
|
|
34
|
+
const Fs = require("fs");
|
|
35
|
+
const Path = require("path");
|
|
36
|
+
const Os = require("os");
|
|
37
|
+
const { transpile, FLUX_VERSION, FLUX_STAGE } = require("./transpiler");
|
|
38
|
+
const { bundle } = require("./bundler");
|
|
39
|
+
const { format } = require("./formatter");
|
|
40
|
+
const { lint } = require("./linter");
|
|
41
|
+
const { runTests } = require("./test-runner");
|
|
42
|
+
const { loadConfig } = require("./config");
|
|
43
|
+
const { cmdAdd, cmdRemove, cmdInstall, cmdList, cmdSearch, cmdInfo, cmdPublish } = require("./pkg");
|
|
44
|
+
const VERSION = (FLUX_VERSION ?? "3.0.0");
|
|
45
|
+
const STAGE = (FLUX_STAGE ?? "self-hosted");
|
|
46
|
+
const C = { reset: "\\x1b[0m", bold: "\\x1b[1m", dim: "\\x1b[2m", red: "\\x1b[31m", green: "\\x1b[32m", yellow: "\\x1b[33m", blue: "\\x1b[34m", cyan: "\\x1b[36m", white: "\\x1b[37m", gray: "\\x1b[90m", magenta: "\\x1b[35m" };
|
|
47
|
+
const noColor = (process.env.NO_COLOR || !process.stdout.isTTY);
|
|
48
|
+
function clr(c, s) {
|
|
49
|
+
return (noColor ? s : ((c + s) + C.reset));
|
|
50
|
+
}
|
|
51
|
+
function bold(s) {
|
|
52
|
+
return clr(C.bold, s);
|
|
53
|
+
}
|
|
54
|
+
function gray(s) {
|
|
55
|
+
return clr(C.gray, s);
|
|
56
|
+
}
|
|
57
|
+
function green(s) {
|
|
58
|
+
return clr(C.green, s);
|
|
59
|
+
}
|
|
60
|
+
function red(s) {
|
|
61
|
+
return clr(C.red, s);
|
|
62
|
+
}
|
|
63
|
+
function cyan(s) {
|
|
64
|
+
return clr(C.cyan, s);
|
|
65
|
+
}
|
|
66
|
+
function yellow(s) {
|
|
67
|
+
return clr(C.yellow, s);
|
|
68
|
+
}
|
|
69
|
+
function blue(s) {
|
|
70
|
+
return clr(C.blue, s);
|
|
71
|
+
}
|
|
72
|
+
function showBanner() {
|
|
73
|
+
if (noColor) {
|
|
74
|
+
console.log((((("Flux Lang " + VERSION) + " [") + STAGE) + "]"));
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
console.log(cyan(bold("███████╗██╗ ██╗ ██╗██╗ ██╗\n██╔════╝██║ ██║ ██║╚██╗██╔╝\n█████╗ ██║ ██║ ██║ ╚███╔╝\n██╔══╝ ██║ ██║ ██║ ██╔██╗\n██║ ███████╗╚██████╔╝██╔╝ ██╗\n╚═╝ ╚══════╝ ╚═════╝ ╚═╝ ╚═╝")));
|
|
78
|
+
console.log(gray(((((" Flux Lang v" + VERSION) + " [") + STAGE) + "] → JavaScript\n")));
|
|
79
|
+
}
|
|
80
|
+
function showHelp() {
|
|
81
|
+
showBanner();
|
|
82
|
+
console.log(bold("USAGE:"));
|
|
83
|
+
console.log(" flux <command> [options]\n");
|
|
84
|
+
console.log(bold("COMPILER:"));
|
|
85
|
+
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"]];
|
|
86
|
+
for (const __item__ of compilerCmds) {
|
|
87
|
+
const [cmd, desc] = __item__;
|
|
88
|
+
console.log((((" " + green(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
89
|
+
}
|
|
90
|
+
console.log();
|
|
91
|
+
console.log(bold("TOOLING:"));
|
|
92
|
+
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)"]];
|
|
93
|
+
for (const __item__ of toolCmds) {
|
|
94
|
+
const [cmd, desc] = __item__;
|
|
95
|
+
console.log((((" " + green(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
96
|
+
}
|
|
97
|
+
console.log();
|
|
98
|
+
console.log(bold("PACKAGE MANAGER:"));
|
|
99
|
+
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"]];
|
|
100
|
+
for (const __item__ of pkgCmds) {
|
|
101
|
+
const [cmd, desc] = __item__;
|
|
102
|
+
console.log((((" " + cyan(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
103
|
+
}
|
|
104
|
+
console.log();
|
|
105
|
+
console.log(bold("SELF-HOSTED:"));
|
|
106
|
+
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"]];
|
|
107
|
+
for (const __item__ of selfCmds) {
|
|
108
|
+
const [cmd, desc] = __item__;
|
|
109
|
+
console.log((((" " + yellow(("flux " + cmd).padEnd(36))) + " ") + gray(desc)));
|
|
110
|
+
}
|
|
111
|
+
console.log();
|
|
112
|
+
console.log(bold("OPTIONS:"));
|
|
113
|
+
console.log(((" " + yellow("--out, -o <file> ")) + " Output file"));
|
|
114
|
+
console.log(((" " + yellow("--sourcemap, -m ")) + " Generate .js.map"));
|
|
115
|
+
console.log(((" " + yellow("--watch, -w ")) + " Watch mode"));
|
|
116
|
+
console.log(((" " + yellow("--mangle ")) + " Minify identifiers"));
|
|
117
|
+
console.log(((" " + yellow("--typecheck ")) + " Enable type checking"));
|
|
118
|
+
console.log(((" " + yellow("--stdout ")) + " Print to terminal"));
|
|
119
|
+
console.log(((" " + yellow("--no-color ")) + " Disable colors"));
|
|
120
|
+
console.log();
|
|
121
|
+
}
|
|
122
|
+
function parseArgs(argv) {
|
|
123
|
+
const args = argv.slice(2);
|
|
124
|
+
const opts = { out: null, sourcemap: false, mangle: false, typecheck: false, strict: false, stdout: false, watch: false, dev: false, verbose: false, jsx: false, jsxTarget: "browser" };
|
|
125
|
+
const positional = [];
|
|
126
|
+
let i = 0;
|
|
127
|
+
while ((i < args.length)) {
|
|
128
|
+
const a = args[i];
|
|
129
|
+
if (((a == "--out") || (a == "-o"))) {
|
|
130
|
+
i = (i + 1);
|
|
131
|
+
opts.out = args[i];
|
|
132
|
+
}
|
|
133
|
+
else if (((a == "--sourcemap") || (a == "-m"))) {
|
|
134
|
+
opts.sourcemap = true;
|
|
135
|
+
}
|
|
136
|
+
else if ((a == "--mangle")) {
|
|
137
|
+
opts.mangle = true;
|
|
138
|
+
}
|
|
139
|
+
else if (((a == "--typecheck") || (a == "-t"))) {
|
|
140
|
+
opts.typecheck = true;
|
|
141
|
+
}
|
|
142
|
+
else if ((a == "--strict")) {
|
|
143
|
+
opts.strict = true;
|
|
144
|
+
}
|
|
145
|
+
else if ((a == "--stdout")) {
|
|
146
|
+
opts.stdout = true;
|
|
147
|
+
}
|
|
148
|
+
else if (((a == "--watch") || (a == "-w"))) {
|
|
149
|
+
opts.watch = true;
|
|
150
|
+
}
|
|
151
|
+
else if ((a == "--dev")) {
|
|
152
|
+
opts.dev = true;
|
|
153
|
+
}
|
|
154
|
+
else if (((a == "--verbose") || (a == "-v"))) {
|
|
155
|
+
opts.verbose = true;
|
|
156
|
+
}
|
|
157
|
+
else if ((a == "--jsx")) {
|
|
158
|
+
opts.jsx = true;
|
|
159
|
+
}
|
|
160
|
+
else if ((a == "--jsx-target")) {
|
|
161
|
+
i = (i + 1);
|
|
162
|
+
opts.jsxTarget = args[i];
|
|
163
|
+
}
|
|
164
|
+
else if (!a.startsWith("--")) {
|
|
165
|
+
positional.push(a);
|
|
166
|
+
}
|
|
167
|
+
i = (i + 1);
|
|
168
|
+
}
|
|
169
|
+
return { positional, opts };
|
|
170
|
+
}
|
|
171
|
+
function readFluxFile(filePath) {
|
|
172
|
+
const abs = Path.resolve(filePath);
|
|
173
|
+
if (!Fs.existsSync(abs)) {
|
|
174
|
+
console.error(red(("✗ File not found: " + abs)));
|
|
175
|
+
process.exit(1);
|
|
176
|
+
}
|
|
177
|
+
if (!filePath.endsWith(".flux")) {
|
|
178
|
+
console.warn(yellow(("⚠ Not a .flux file: " + filePath)));
|
|
179
|
+
}
|
|
180
|
+
return { source: Fs.readFileSync(abs, "utf8"), abs };
|
|
181
|
+
}
|
|
182
|
+
function deriveOutPath(inputPath, outFlag) {
|
|
183
|
+
if (outFlag) {
|
|
184
|
+
return Path.resolve(outFlag);
|
|
185
|
+
}
|
|
186
|
+
const base = Path.basename(inputPath, ".flux");
|
|
187
|
+
return Path.join(Path.dirname(Path.resolve(inputPath)), (base + ".js"));
|
|
188
|
+
}
|
|
189
|
+
const ERROR_KIND = { ParseError: "Syntax error", LexerError: "Syntax error", CheckError: "Static error", TypeCheckError: "Type error", TypeError: "Type error" };
|
|
190
|
+
function printErrors(errors, source, filePath) {
|
|
191
|
+
const lines = source.split("\n");
|
|
192
|
+
for (const err of errors) {
|
|
193
|
+
const kind = (ERROR_KIND[err.name] ?? "Error");
|
|
194
|
+
const stage = (err.stage ? gray(((" [" + err.stage) + "]")) : "");
|
|
195
|
+
console.error();
|
|
196
|
+
console.error((red(bold(kind)) + stage));
|
|
197
|
+
if (err.line) {
|
|
198
|
+
const fileLabel = (filePath ? cyan(Path.relative(process.cwd(), filePath)) : "");
|
|
199
|
+
const locLabel = yellow(((err.line + ":") + (err.col ?? 1)));
|
|
200
|
+
if (fileLabel) {
|
|
201
|
+
console.error((((" " + fileLabel) + ":") + locLabel));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
console.error((" Line " + locLabel));
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
console.error((" " + err.message));
|
|
208
|
+
if ((err.line && (err.line <= lines.length))) {
|
|
209
|
+
const errLineIdx = (err.line - 1);
|
|
210
|
+
const col = Math.max(0, ((err.col ?? 1) - 1));
|
|
211
|
+
const tokLen = Math.max(1, (err.len ?? 1));
|
|
212
|
+
if (((errLineIdx > 0) && (lines[(errLineIdx - 1)].trim() != ""))) {
|
|
213
|
+
const prev = String((err.line - 1)).padStart(4);
|
|
214
|
+
console.error(gray((((" " + prev) + " │ ") + lines[(errLineIdx - 1)])));
|
|
215
|
+
}
|
|
216
|
+
const lineNum = String(err.line).padStart(4);
|
|
217
|
+
console.error((gray(((" " + lineNum) + " │ ")) + lines[errLineIdx]));
|
|
218
|
+
const squiggle = ("^" + "~".repeat(Math.max(0, (tokLen - 1))));
|
|
219
|
+
const pointer = (" ".repeat(col) + red(squiggle));
|
|
220
|
+
console.error((gray(" │ ") + pointer));
|
|
221
|
+
if ((((errLineIdx + 1) < lines.length) && (lines[(errLineIdx + 1)].trim() != ""))) {
|
|
222
|
+
const next = String((err.line + 1)).padStart(4);
|
|
223
|
+
console.error(gray((((" " + next) + " │ ") + lines[(errLineIdx + 1)])));
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
if (err.hint) {
|
|
227
|
+
console.error((cyan(" Hint: ") + gray(err.hint)));
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
console.error();
|
|
231
|
+
}
|
|
232
|
+
function cmdCompile(filePath, opts) {
|
|
233
|
+
const { source, abs } = readFluxFile(filePath);
|
|
234
|
+
const cfg = loadConfig(Path.dirname(abs));
|
|
235
|
+
const outPath = deriveOutPath(filePath, opts.out);
|
|
236
|
+
const mapPath = (outPath + ".map");
|
|
237
|
+
const t0 = Date.now();
|
|
238
|
+
const result = transpile(source, { sourcemap: (opts.sourcemap ?? cfg.sourcemap), mangle: (opts.mangle ?? cfg.mangle), typecheck: (opts.typecheck ?? cfg.typecheck), jsx: (opts.jsx ?? cfg.jsx), jsxTarget: (opts.jsxTarget ?? cfg.jsxTarget), sourceFile: Path.relative(Path.dirname(outPath), abs), outputFile: Path.basename(outPath) });
|
|
239
|
+
if (!result.success) {
|
|
240
|
+
console.error(red((("\n✗ Compile failed — " + result.errors.length) + " error(s)")));
|
|
241
|
+
printErrors(result.errors, source, abs);
|
|
242
|
+
process.exit(1);
|
|
243
|
+
}
|
|
244
|
+
const elapsed = (Date.now() - t0);
|
|
245
|
+
if (opts.stdout) {
|
|
246
|
+
console.log(result.output);
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
Fs.writeFileSync(outPath, result.output, "utf8");
|
|
250
|
+
let extra = "";
|
|
251
|
+
if ((opts.sourcemap && result.sourceMap)) {
|
|
252
|
+
Fs.writeFileSync(mapPath, result.sourceMap, "utf8");
|
|
253
|
+
extra = gray((" + " + Path.relative(process.cwd(), mapPath)));
|
|
254
|
+
}
|
|
255
|
+
const rel = Path.relative(process.cwd(), abs);
|
|
256
|
+
const relO = Path.relative(process.cwd(), outPath);
|
|
257
|
+
console.log((((((green("✓ ") + gray((("(" + elapsed) + "ms) "))) + blue(rel)) + gray(" → ")) + cyan(relO)) + extra));
|
|
258
|
+
if ((result.typeErrors && (result.typeErrors.length > 0))) {
|
|
259
|
+
console.warn(yellow((("\n⚠ " + result.typeErrors.length) + " type warning(s)")));
|
|
260
|
+
printErrors(result.typeErrors, source, abs);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
function cmdRun(filePath, opts) {
|
|
264
|
+
const { source, abs } = readFluxFile(filePath);
|
|
265
|
+
const result = transpile(source, { jsx: (opts.jsx ?? false), jsxTarget: (opts.jsxTarget ?? "browser"), mangle: false });
|
|
266
|
+
if (!result.success) {
|
|
267
|
+
console.error(red("\n✗ Compile error"));
|
|
268
|
+
printErrors(result.errors, source, abs);
|
|
269
|
+
process.exit(1);
|
|
270
|
+
}
|
|
271
|
+
const tmpPath = Path.join(Os.tmpdir(), (("_flux_run_" + Date.now()) + ".js"));
|
|
272
|
+
Fs.writeFileSync(tmpPath, result.output, "utf8");
|
|
273
|
+
console.log(gray((("▶ Running " + Path.basename(abs)) + " ...\n")));
|
|
274
|
+
try {
|
|
275
|
+
require(tmpPath);
|
|
276
|
+
}
|
|
277
|
+
catch (e) {
|
|
278
|
+
console.error(red(("\n[Runtime Error] " + e.message)));
|
|
279
|
+
process.exitCode = 1;
|
|
280
|
+
}
|
|
281
|
+
finally {
|
|
282
|
+
try {
|
|
283
|
+
Fs.unlinkSync(tmpPath);
|
|
284
|
+
}
|
|
285
|
+
catch (e2) {
|
|
286
|
+
null;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
function runCheck(abs) {
|
|
291
|
+
const source = Fs.readFileSync(abs, "utf8");
|
|
292
|
+
const baseName = Path.basename(abs);
|
|
293
|
+
const result = transpile(source, { check: true, typecheck: true });
|
|
294
|
+
if (!result.success) {
|
|
295
|
+
const n = result.errors.length;
|
|
296
|
+
const kind = (result.errors.some((e) => (e.name == "CheckError")) ? "static" : "syntax");
|
|
297
|
+
console.error(red((((((("\n✗ " + baseName) + ": ") + n) + " ") + kind) + " error(s)")));
|
|
298
|
+
printErrors(result.errors, source, abs);
|
|
299
|
+
return { ok: false, typeErrors: 0, warnings: 0 };
|
|
300
|
+
}
|
|
301
|
+
let allOk = true;
|
|
302
|
+
const typeErrors = (result.typeErrors ?? []);
|
|
303
|
+
if ((typeErrors.length > 0)) {
|
|
304
|
+
console.error(red((((("\n✗ " + baseName) + ": ") + typeErrors.length) + " type error(s)")));
|
|
305
|
+
printErrors(typeErrors, source, abs);
|
|
306
|
+
allOk = false;
|
|
307
|
+
}
|
|
308
|
+
const warnings = (result.typeWarnings ?? []);
|
|
309
|
+
for (const w of warnings) {
|
|
310
|
+
const fileRef = (cyan(baseName) + (w.line ? yellow((":" + w.line)) : ""));
|
|
311
|
+
console.warn(((yellow(" ⚠ ") + fileRef) + gray((" " + w.message))));
|
|
312
|
+
if (w.hint) {
|
|
313
|
+
console.warn((cyan(" Hint: ") + gray(w.hint)));
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
const fnRe = /^(?:async )?function \w/gm;
|
|
317
|
+
const clsRe = /^class \w/gm;
|
|
318
|
+
const fns = (result.output.match(fnRe) ?? []).length;
|
|
319
|
+
const cls = (result.output.match(clsRe) ?? []).length;
|
|
320
|
+
if (allOk) {
|
|
321
|
+
console.log((((green("✓ ") + cyan(baseName)) + gray(" — no errors")) + gray(((((((" Functions: " + fns) + " | Classes: ") + cls) + " | JS output: ") + result.output.split("\n").length) + " lines"))));
|
|
322
|
+
}
|
|
323
|
+
return { ok: allOk, typeErrors: typeErrors.length, warnings: warnings.length };
|
|
324
|
+
}
|
|
325
|
+
function cmdCheck(filePaths, opts) {
|
|
326
|
+
if ((filePaths.length == 0)) {
|
|
327
|
+
console.error(red("✗ No files specified"));
|
|
328
|
+
process.exit(1);
|
|
329
|
+
}
|
|
330
|
+
let totalErrors = 0;
|
|
331
|
+
let totalWarnings = 0;
|
|
332
|
+
for (const filePath of filePaths) {
|
|
333
|
+
const abs = Path.resolve(filePath);
|
|
334
|
+
if (!Fs.existsSync(abs)) {
|
|
335
|
+
console.error(red(("✗ File not found: " + filePath)));
|
|
336
|
+
totalErrors = (totalErrors + 1);
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
const r = runCheck(abs);
|
|
340
|
+
if (!r.ok) {
|
|
341
|
+
totalErrors = (totalErrors + 1);
|
|
342
|
+
}
|
|
343
|
+
totalWarnings = (totalWarnings + r.warnings);
|
|
344
|
+
}
|
|
345
|
+
console.log();
|
|
346
|
+
if ((totalErrors > 0)) {
|
|
347
|
+
console.error(red((("✗ " + totalErrors) + " file(s) with errors")));
|
|
348
|
+
process.exit(1);
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
console.log((green("✓ All files OK") + ((totalWarnings > 0) ? yellow(((" (" + totalWarnings) + " warning(s))")) : "")));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function cmdFmt(filePaths, opts) {
|
|
355
|
+
let changed = 0;
|
|
356
|
+
for (const filePath of filePaths) {
|
|
357
|
+
const abs = Path.resolve(filePath);
|
|
358
|
+
if (!Fs.existsSync(abs)) {
|
|
359
|
+
console.error(red(("✗ Not found: " + filePath)));
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const source = Fs.readFileSync(abs, "utf8");
|
|
363
|
+
const formatted = format(source);
|
|
364
|
+
if ((formatted != source)) {
|
|
365
|
+
if (!opts.stdout) {
|
|
366
|
+
Fs.writeFileSync(abs, formatted, "utf8");
|
|
367
|
+
console.log(((green("✓ ") + gray("Formatted ")) + cyan(Path.relative(process.cwd(), abs))));
|
|
368
|
+
changed = (changed + 1);
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
console.log(formatted);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
console.log(((gray("○ ") + gray("No changes: ")) + Path.relative(process.cwd(), abs)));
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if ((!opts.stdout && (changed > 0))) {
|
|
379
|
+
console.log();
|
|
380
|
+
console.log(green((("✓ " + changed) + " file(s) formatted")));
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
function cmdLint(filePaths, opts) {
|
|
384
|
+
let hasErrors = false;
|
|
385
|
+
for (const filePath of filePaths) {
|
|
386
|
+
const abs = Path.resolve(filePath);
|
|
387
|
+
if (!Fs.existsSync(abs)) {
|
|
388
|
+
console.error(red(("✗ Not found: " + filePath)));
|
|
389
|
+
continue;
|
|
390
|
+
}
|
|
391
|
+
const source = Fs.readFileSync(abs, "utf8");
|
|
392
|
+
const result = lint(source);
|
|
393
|
+
const name = Path.relative(process.cwd(), abs);
|
|
394
|
+
if (((result.errors.length == 0) && (result.warnings.length == 0))) {
|
|
395
|
+
console.log(((green("✓ ") + cyan(name)) + gray(" — clean")));
|
|
396
|
+
}
|
|
397
|
+
else {
|
|
398
|
+
for (const e of result.errors) {
|
|
399
|
+
console.error((((red(" error ") + cyan(((name + ":") + (e.line ?? "?")))) + " ") + e.message));
|
|
400
|
+
hasErrors = true;
|
|
401
|
+
}
|
|
402
|
+
for (const w of result.warnings) {
|
|
403
|
+
console.warn((((yellow(" warn ") + cyan(((name + ":") + (w.line ?? "?")))) + " ") + w.message));
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
if (hasErrors) {
|
|
408
|
+
process.exit(1);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
function cmdBundle(entryPath, opts) {
|
|
412
|
+
const abs = Path.resolve(entryPath);
|
|
413
|
+
if (!Fs.existsSync(abs)) {
|
|
414
|
+
console.error(red(("✗ File not found: " + entryPath)));
|
|
415
|
+
process.exit(1);
|
|
416
|
+
}
|
|
417
|
+
const outFile = (opts.out ?? Path.join(Path.dirname(abs), (Path.basename(abs, ".flux") + ".bundle.js")));
|
|
418
|
+
const t0 = Date.now();
|
|
419
|
+
const result = bundle(abs);
|
|
420
|
+
if (!result.success) {
|
|
421
|
+
console.error(red("\n✗ Bundle failed:\n"));
|
|
422
|
+
for (const e of result.errors) {
|
|
423
|
+
console.error(red((" " + e.message)));
|
|
424
|
+
}
|
|
425
|
+
process.exit(1);
|
|
426
|
+
}
|
|
427
|
+
const elapsed = (Date.now() - t0);
|
|
428
|
+
if (opts.stdout) {
|
|
429
|
+
console.log(result.code);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
Fs.writeFileSync(outFile, result.code, "utf8");
|
|
433
|
+
const kb = (result.code.length / 1024).toFixed(1);
|
|
434
|
+
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]"))));
|
|
435
|
+
}
|
|
436
|
+
function cmdWatch(filePath, opts) {
|
|
437
|
+
const abs = Path.resolve(filePath);
|
|
438
|
+
if (!Fs.existsSync(abs)) {
|
|
439
|
+
console.error(red(("✗ File not found: " + filePath)));
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
console.log(((cyan("◉ Watching ") + Path.relative(process.cwd(), abs)) + gray(" (Ctrl+C to stop)\n")));
|
|
443
|
+
cmdCompile(filePath, opts);
|
|
444
|
+
let timer = null;
|
|
445
|
+
function onDebounce() {
|
|
446
|
+
console.log((gray((("\n" + new Date().toLocaleTimeString()) + " — ")) + blue("change detected")));
|
|
447
|
+
cmdCompile(filePath, opts);
|
|
448
|
+
}
|
|
449
|
+
function onChange() {
|
|
450
|
+
if (timer) {
|
|
451
|
+
clearTimeout(timer);
|
|
452
|
+
}
|
|
453
|
+
timer = setTimeout(onDebounce, 80);
|
|
454
|
+
}
|
|
455
|
+
Fs.watch(abs, onChange);
|
|
456
|
+
}
|
|
457
|
+
function cmdTokens(filePath, opts) {
|
|
458
|
+
const { source } = readFluxFile(filePath);
|
|
459
|
+
const { Lexer } = require(Path.join(__dirname, "lexer.js"));
|
|
460
|
+
const lexer = new Lexer(source);
|
|
461
|
+
const tokens = lexer.tokenize();
|
|
462
|
+
console.log(gray((("Tokens (" + tokens.length) + "):\n")));
|
|
463
|
+
for (const tok of tokens) {
|
|
464
|
+
const loc = (tok.line ? gray((((" " + tok.line) + ":") + (tok.col ?? 1))) : "");
|
|
465
|
+
const val_ = ((tok.value != null) ? cyan((" " + JSON.stringify(tok.value))) : "");
|
|
466
|
+
console.log((((" " + yellow(tok.type.padEnd(16))) + val_) + loc));
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function cmdAst(filePath, opts) {
|
|
470
|
+
const { source } = readFluxFile(filePath);
|
|
471
|
+
const result = transpile(source, { });
|
|
472
|
+
if (!result.success) {
|
|
473
|
+
printErrors(result.errors, source, filePath);
|
|
474
|
+
process.exit(1);
|
|
475
|
+
}
|
|
476
|
+
console.log(JSON.stringify(result.ast, null, 2));
|
|
477
|
+
}
|
|
478
|
+
function cmdRepl(opts) {
|
|
479
|
+
const readline = require("readline");
|
|
480
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout, terminal: true, prompt: (cyan("flux") + gray("> ")) });
|
|
481
|
+
console.log();
|
|
482
|
+
console.log((bold("Flux Lang Interactive REPL") + gray(((((" v" + VERSION) + " [") + STAGE) + "]"))));
|
|
483
|
+
console.log(gray("Type Flux code to compile and run it. Ctrl+C or .exit to quit.\n"));
|
|
484
|
+
rl.prompt();
|
|
485
|
+
let multiLine = "";
|
|
486
|
+
let inBlock = false;
|
|
487
|
+
function onLine(rawLine) {
|
|
488
|
+
const line = rawLine;
|
|
489
|
+
if (((line.trim() == ".exit") || (line.trim() == ".quit"))) {
|
|
490
|
+
console.log(gray("\nBye!"));
|
|
491
|
+
process.exit(0);
|
|
492
|
+
}
|
|
493
|
+
if ((line.trim() == ".help")) {
|
|
494
|
+
console.log(gray(" .exit — quit"));
|
|
495
|
+
console.log(gray(" .clear — clear screen"));
|
|
496
|
+
console.log(gray(" .help — this message"));
|
|
497
|
+
rl.prompt();
|
|
498
|
+
return;
|
|
499
|
+
}
|
|
500
|
+
if ((line.trim() == ".clear")) {
|
|
501
|
+
console.clear();
|
|
502
|
+
rl.prompt();
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
const needsContinue = (line.trimEnd().endsWith(":") || inBlock);
|
|
506
|
+
if ((needsContinue && (line.trim() != ""))) {
|
|
507
|
+
multiLine = ((multiLine + line) + "\n");
|
|
508
|
+
inBlock = true;
|
|
509
|
+
process.stdout.write(gray("... "));
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
const src = (inBlock ? multiLine : line);
|
|
513
|
+
multiLine = "";
|
|
514
|
+
inBlock = false;
|
|
515
|
+
if (!src.trim()) {
|
|
516
|
+
rl.prompt();
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
try {
|
|
520
|
+
const result = transpile(src, { check: false });
|
|
521
|
+
if (result.success) {
|
|
522
|
+
const tmpPath = Path.join(Os.tmpdir(), (("_flux_repl_" + Date.now()) + ".js"));
|
|
523
|
+
Fs.writeFileSync(tmpPath, result.output, "utf8");
|
|
524
|
+
try {
|
|
525
|
+
const out = require(tmpPath);
|
|
526
|
+
if ((out != undefined)) {
|
|
527
|
+
console.log((green("← ") + JSON.stringify(out)));
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
catch (e) {
|
|
531
|
+
console.error((red("Runtime: ") + e.message));
|
|
532
|
+
}
|
|
533
|
+
finally {
|
|
534
|
+
try {
|
|
535
|
+
Fs.unlinkSync(tmpPath);
|
|
536
|
+
}
|
|
537
|
+
catch (e2) {
|
|
538
|
+
null;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
else {
|
|
543
|
+
for (const e of result.errors) {
|
|
544
|
+
console.error((red("✗ ") + e.message));
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
catch (e3) {
|
|
549
|
+
console.error((red("Error: ") + e3.message));
|
|
550
|
+
}
|
|
551
|
+
rl.prompt();
|
|
552
|
+
}
|
|
553
|
+
function onClose() {
|
|
554
|
+
console.log(gray("\nBye!"));
|
|
555
|
+
process.exit(0);
|
|
556
|
+
}
|
|
557
|
+
rl.on("line", onLine);
|
|
558
|
+
rl.on("close", onClose);
|
|
559
|
+
}
|
|
560
|
+
function cmdInit(name, opts) {
|
|
561
|
+
const projectName = (name ?? "my-flux-app");
|
|
562
|
+
const dir = Path.resolve(projectName);
|
|
563
|
+
if (Fs.existsSync(dir)) {
|
|
564
|
+
console.error(red(("✗ Directory already exists: " + projectName)));
|
|
565
|
+
process.exit(1);
|
|
566
|
+
}
|
|
567
|
+
Fs.mkdirSync(dir, { recursive: true });
|
|
568
|
+
Fs.mkdirSync(Path.join(dir, "src"), { recursive: true });
|
|
569
|
+
Fs.mkdirSync(Path.join(dir, "tests"), { recursive: true });
|
|
570
|
+
const mainFlux = "// {projectName} — written in Flux Lang v{VERSION}\n\ntype Shape =\n | Circle(radius: Float)\n | Rect(width: Float, height: Float)\n | Triangle(base: Float, height: Float)\n\nfn area(shape: Shape) -> Float:\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 greet(name: String) -> String:\n return \"Hello from Flux, {name}!\"\n\nval shapes = [\n Circle(5.0),\n Rect(10.0, 4.0),\n Triangle(6.0, 8.0),\n]\n\nfor shape in shapes:\n val a = area(shape)\n print(\"Area: {a:.2f}\")\n\nprint(greet(\"{projectName}\"))";
|
|
571
|
+
const testFlux = "// {projectName} tests\n\nfn add(a: Int, b: Int) -> Int: return a + b\nfn mul(a: Int, b: Int) -> Int: return a * b\n\ntest \"add works\":\n assert add(1, 2) == 3\n assert add(0, 0) == 0\n assert add(-1, 1) == 0\n\ntest \"mul works\":\n assert mul(3, 4) == 12\n assert mul(0, 5) == 0";
|
|
572
|
+
const fluxJson = { name: projectName, version: "1.0.0", description: "A Flux Lang 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: { } };
|
|
573
|
+
const gitignore = "node_modules/\ndist/\nflux_modules/\n*.js.map\n.DS_Store";
|
|
574
|
+
const readme = "# {projectName}\n\nA project built with [Flux Lang](https://flux-lang.dev) v{VERSION}.\n\n## Getting Started\n\n```bash\nflux run src/main.flux\n```\n\n## Commands\n\n| Command | Description |\n|---|---|\n| `flux run src/main.flux` | Run main file |\n| `flux build` | Bundle to dist/ |\n| `flux watch src/main.flux` | Watch mode |\n| `flux check src/main.flux` | Type check |\n| `flux test tests/` | Run tests |\n| `flux fmt src/` | Format code |";
|
|
575
|
+
Fs.writeFileSync(Path.join(dir, "src", "main.flux"), mainFlux, "utf8");
|
|
576
|
+
Fs.writeFileSync(Path.join(dir, "tests", "main.test.flux"), testFlux, "utf8");
|
|
577
|
+
Fs.writeFileSync(Path.join(dir, "flux.json"), (JSON.stringify(fluxJson, null, 2) + "\n"), "utf8");
|
|
578
|
+
Fs.writeFileSync(Path.join(dir, ".gitignore"), gitignore, "utf8");
|
|
579
|
+
Fs.writeFileSync(Path.join(dir, "README.md"), readme, "utf8");
|
|
580
|
+
console.log();
|
|
581
|
+
console.log((green("✓ Created: ") + bold((projectName + "/"))));
|
|
582
|
+
console.log();
|
|
583
|
+
console.log(gray(" Files:"));
|
|
584
|
+
console.log((" " + cyan((projectName + "/src/main.flux"))));
|
|
585
|
+
console.log((" " + cyan((projectName + "/tests/main.test.flux"))));
|
|
586
|
+
console.log((" " + cyan((projectName + "/flux.json"))));
|
|
587
|
+
console.log((" " + cyan((projectName + "/.gitignore"))));
|
|
588
|
+
console.log((" " + cyan((projectName + "/README.md"))));
|
|
589
|
+
console.log();
|
|
590
|
+
console.log(bold(" Next steps:"));
|
|
591
|
+
console.log((" " + yellow(("cd " + projectName))));
|
|
592
|
+
console.log((" " + yellow("flux run src/main.flux")));
|
|
593
|
+
console.log();
|
|
594
|
+
}
|
|
595
|
+
function cmdSelfHosted(sub, opts) {
|
|
596
|
+
const SELF = Path.join(__dirname, ".");
|
|
597
|
+
const coreModules = ["css-preprocessor", "checker", "type-checker", "jsx", "lexer", "parser", "codegen", "transpiler"];
|
|
598
|
+
const extModules = ["formatter", "sourcemap", "stdlib", "mangler", "linter", "bundler", "test-runner"];
|
|
599
|
+
const newModules = ["config", "pkg", "cli"];
|
|
600
|
+
const allModules = [...coreModules, ...extModules, ...newModules];
|
|
601
|
+
if ((sub == "build")) {
|
|
602
|
+
const { execSync } = require("child_process");
|
|
603
|
+
const BIN = Path.join(__dirname, "../../bin/flux.js");
|
|
604
|
+
console.log();
|
|
605
|
+
console.log(bold("⚡ Flux Bootstrap — Stage 0"));
|
|
606
|
+
console.log(gray(" Compiling self-hosted sources with stage-0 compiler...\n"));
|
|
607
|
+
let ok = 0;
|
|
608
|
+
let failed = 0;
|
|
609
|
+
for (const name of allModules) {
|
|
610
|
+
const src = Path.join(SELF, (name + ".flux"));
|
|
611
|
+
const out = Path.join(SELF, (name + ".js"));
|
|
612
|
+
if (!Fs.existsSync(src)) {
|
|
613
|
+
console.log(gray(((" ○ " + name) + ".flux (skipped — not found)")));
|
|
614
|
+
continue;
|
|
615
|
+
}
|
|
616
|
+
try {
|
|
617
|
+
const cmd = "node \"${BIN}\" compile \"${src}\" -o \"${out}\" --no-mangle";
|
|
618
|
+
execSync(cmd, { cwd: Path.join(__dirname, "../.."), stdio: "pipe" });
|
|
619
|
+
console.log((((green(" ✓ ") + name) + ".flux → ") + gray((name + ".js"))));
|
|
620
|
+
ok = (ok + 1);
|
|
621
|
+
}
|
|
622
|
+
catch (e) {
|
|
623
|
+
console.error((((red(" ✗ ") + name) + ".flux — ") + e.message.split("\n")[0]));
|
|
624
|
+
failed = (failed + 1);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
console.log();
|
|
628
|
+
if ((failed == 0)) {
|
|
629
|
+
console.log((green("✓ Bootstrap complete! ") + gray((ok + " modules compiled"))));
|
|
630
|
+
console.log();
|
|
631
|
+
console.log(" Activate self-hosted mode:");
|
|
632
|
+
console.log((" " + yellow("FLUX_SELF_HOSTED=1 flux <command>")));
|
|
633
|
+
}
|
|
634
|
+
else {
|
|
635
|
+
console.log(red((((("✗ " + failed) + " module(s) failed, ") + ok) + " succeeded")));
|
|
636
|
+
}
|
|
637
|
+
console.log();
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
if ((sub == "verify")) {
|
|
641
|
+
console.log(cyan("\n Verifying self-hosted compiler output...\n"));
|
|
642
|
+
try {
|
|
643
|
+
const selfMod = require(Path.join(SELF, "transpiler.js"));
|
|
644
|
+
const stage0Mod = require(Path.join(__dirname, "../transpiler.js"));
|
|
645
|
+
const testSrc = "fn greet(name): return \"Hello, {name}!\"\nval msg = greet(\"Flux\")";
|
|
646
|
+
const r0 = stage0Mod.transpile(testSrc, { });
|
|
647
|
+
const r1 = selfMod.transpile(testSrc, { });
|
|
648
|
+
function norm(s) {
|
|
649
|
+
return s.replace(/\/\/.*/g, "").replace(/\s+/g, " ").trim();
|
|
650
|
+
}
|
|
651
|
+
if ((norm(r0.output) == norm(r1.output))) {
|
|
652
|
+
console.log(green("✓ Self-hosted output matches stage-0!"));
|
|
653
|
+
console.log(green("✓ Flux is fully self-hosting."));
|
|
654
|
+
}
|
|
655
|
+
else {
|
|
656
|
+
console.log(yellow("⚠ Outputs differ (minor differences are OK)"));
|
|
657
|
+
console.log((gray(" Stage-0: ") + r0.output.split("\n")[0]));
|
|
658
|
+
console.log((gray(" Self-hosted:") + r1.output.split("\n")[0]));
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
catch (e) {
|
|
662
|
+
console.error(red(("✗ Verify failed: " + e.message)));
|
|
663
|
+
}
|
|
664
|
+
console.log();
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
console.log();
|
|
668
|
+
console.log(bold(" Flux Self-Hosted Compiler Status\n"));
|
|
669
|
+
const selfActive = (process.env.FLUX_SELF_HOSTED == "1");
|
|
670
|
+
if (selfActive) {
|
|
671
|
+
console.log(((" Mode: " + green("● ACTIVE")) + gray(" (using self-hosted compiler)")));
|
|
672
|
+
}
|
|
673
|
+
else {
|
|
674
|
+
console.log((((" Mode: " + gray("○ INACTIVE")) + " ") + gray("(using stage-0 compiler)")));
|
|
675
|
+
console.log((" Toggle: " + yellow("FLUX_SELF_HOSTED=1 flux <command>")));
|
|
676
|
+
console.log((" Build: " + yellow("flux self-hosted build")));
|
|
677
|
+
}
|
|
678
|
+
console.log();
|
|
679
|
+
console.log(bold(((" Core Pipeline (" + coreModules.length) + " modules)")));
|
|
680
|
+
for (const name of coreModules) {
|
|
681
|
+
const jsPath = Path.join(SELF, (name + ".js"));
|
|
682
|
+
const flxPath = Path.join(SELF, (name + ".flux"));
|
|
683
|
+
const hasJs = Fs.existsSync(jsPath);
|
|
684
|
+
const hasFlx = Fs.existsSync(flxPath);
|
|
685
|
+
const kb = (hasJs ? (Fs.statSync(jsPath).size / 1024).toFixed(1) : "?");
|
|
686
|
+
const sym = (hasJs ? green("✓") : red("✗"));
|
|
687
|
+
const note = (!hasFlx ? gray(" (no .flux source)") : "");
|
|
688
|
+
console.log((((((" " + sym) + " ") + (name + ".flux").padEnd(26)) + gray((kb + " KB"))) + note));
|
|
689
|
+
}
|
|
690
|
+
console.log();
|
|
691
|
+
console.log(bold(((" Extended Toolchain (" + extModules.length) + " modules)")));
|
|
692
|
+
for (const name of extModules) {
|
|
693
|
+
const jsPath = Path.join(SELF, (name + ".js"));
|
|
694
|
+
const flxPath = Path.join(SELF, (name + ".flux"));
|
|
695
|
+
const hasJs = Fs.existsSync(jsPath);
|
|
696
|
+
const hasFlx = Fs.existsSync(flxPath);
|
|
697
|
+
const kb = (hasJs ? (Fs.statSync(jsPath).size / 1024).toFixed(1) : "?");
|
|
698
|
+
const sym = (hasJs ? green("✓") : red("✗"));
|
|
699
|
+
const note = (!hasFlx ? gray(" (no .flux source)") : "");
|
|
700
|
+
console.log((((((" " + sym) + " ") + (name + ".flux").padEnd(26)) + gray((kb + " KB"))) + note));
|
|
701
|
+
}
|
|
702
|
+
console.log();
|
|
703
|
+
console.log(bold(((" Ecosystem (" + newModules.length) + " modules)")));
|
|
704
|
+
for (const name of newModules) {
|
|
705
|
+
const jsPath = Path.join(SELF, (name + ".js"));
|
|
706
|
+
const flxPath = Path.join(SELF, (name + ".flux"));
|
|
707
|
+
const hasJs = Fs.existsSync(jsPath);
|
|
708
|
+
const hasFlx = Fs.existsSync(flxPath);
|
|
709
|
+
const kb = (hasJs ? (Fs.statSync(jsPath).size / 1024).toFixed(1) : "?");
|
|
710
|
+
const sym = (hasJs ? green("✓") : yellow("○"));
|
|
711
|
+
console.log(((((" " + sym) + " ") + (name + ".flux").padEnd(26)) + (hasJs ? gray((kb + " KB")) : yellow("not built"))));
|
|
712
|
+
}
|
|
713
|
+
console.log();
|
|
714
|
+
}
|
|
715
|
+
function cmdVersion(opts) {
|
|
716
|
+
if (noColor) {
|
|
717
|
+
console.log(("flux-lang v" + VERSION));
|
|
718
|
+
return;
|
|
719
|
+
}
|
|
720
|
+
console.log((cyan(bold("⚡ Flux Lang")) + gray(((((" v" + VERSION) + " [") + STAGE) + "]"))));
|
|
721
|
+
}
|
|
722
|
+
function main() {
|
|
723
|
+
const { positional, opts } = parseArgs(process.argv);
|
|
724
|
+
const cmd = (positional[0] ?? "help");
|
|
725
|
+
if (cmd === "compile") {
|
|
726
|
+
return cmdCompile(positional[1], opts);
|
|
727
|
+
}
|
|
728
|
+
else if (cmd === "run") {
|
|
729
|
+
return cmdRun(positional[1], opts);
|
|
730
|
+
}
|
|
731
|
+
else if (cmd === "check") {
|
|
732
|
+
return cmdCheck(positional.slice(1), opts);
|
|
733
|
+
}
|
|
734
|
+
else if (cmd === "fmt") {
|
|
735
|
+
return cmdFmt(positional.slice(1), opts);
|
|
736
|
+
}
|
|
737
|
+
else if (cmd === "format") {
|
|
738
|
+
return cmdFmt(positional.slice(1), opts);
|
|
739
|
+
}
|
|
740
|
+
else if (cmd === "lint") {
|
|
741
|
+
return cmdLint(positional.slice(1), opts);
|
|
742
|
+
}
|
|
743
|
+
else if (cmd === "bundle") {
|
|
744
|
+
return cmdBundle(positional[1], opts);
|
|
745
|
+
}
|
|
746
|
+
else if (cmd === "watch") {
|
|
747
|
+
return cmdWatch(positional[1], opts);
|
|
748
|
+
}
|
|
749
|
+
else if (cmd === "tokens") {
|
|
750
|
+
return cmdTokens(positional[1], opts);
|
|
751
|
+
}
|
|
752
|
+
else if (cmd === "ast") {
|
|
753
|
+
return cmdAst(positional[1], opts);
|
|
754
|
+
}
|
|
755
|
+
else if (cmd === "repl") {
|
|
756
|
+
return cmdRepl(opts);
|
|
757
|
+
}
|
|
758
|
+
else if (cmd === "init") {
|
|
759
|
+
return cmdInit(positional[1], opts);
|
|
760
|
+
}
|
|
761
|
+
else if (cmd === "add") {
|
|
762
|
+
return cmdAdd(positional.slice(1), opts);
|
|
763
|
+
}
|
|
764
|
+
else if (cmd === "remove") {
|
|
765
|
+
return cmdRemove(positional.slice(1), opts);
|
|
766
|
+
}
|
|
767
|
+
else if (cmd === "rm") {
|
|
768
|
+
return cmdRemove(positional.slice(1), opts);
|
|
769
|
+
}
|
|
770
|
+
else if (cmd === "install") {
|
|
771
|
+
return cmdInstall(opts);
|
|
772
|
+
}
|
|
773
|
+
else if (cmd === "i") {
|
|
774
|
+
return cmdInstall(opts);
|
|
775
|
+
}
|
|
776
|
+
else if (cmd === "list") {
|
|
777
|
+
return cmdList(opts);
|
|
778
|
+
}
|
|
779
|
+
else if (cmd === "ls") {
|
|
780
|
+
return cmdList(opts);
|
|
781
|
+
}
|
|
782
|
+
else if (cmd === "search") {
|
|
783
|
+
return cmdSearch(positional[1], opts);
|
|
784
|
+
}
|
|
785
|
+
else if (cmd === "info") {
|
|
786
|
+
return cmdInfo(positional[1], opts);
|
|
787
|
+
}
|
|
788
|
+
else if (cmd === "publish") {
|
|
789
|
+
return cmdPublish(opts);
|
|
790
|
+
}
|
|
791
|
+
else if (cmd === "self-hosted") {
|
|
792
|
+
return cmdSelfHosted(positional[1], opts);
|
|
793
|
+
}
|
|
794
|
+
else if (cmd === "version") {
|
|
795
|
+
return cmdVersion(opts);
|
|
796
|
+
}
|
|
797
|
+
else if (cmd === "-v") {
|
|
798
|
+
return cmdVersion(opts);
|
|
799
|
+
}
|
|
800
|
+
else if (cmd === "--version") {
|
|
801
|
+
return cmdVersion(opts);
|
|
802
|
+
}
|
|
803
|
+
else if (cmd === "help") {
|
|
804
|
+
return showHelp();
|
|
805
|
+
}
|
|
806
|
+
else if (cmd === "--help") {
|
|
807
|
+
return showHelp();
|
|
808
|
+
}
|
|
809
|
+
else if (cmd === "-h") {
|
|
810
|
+
return showHelp();
|
|
811
|
+
}
|
|
812
|
+
else {
|
|
813
|
+
console.error(red(("✗ Unknown command: " + cmd)));
|
|
814
|
+
console.error(gray(" Run: flux help"));
|
|
815
|
+
process.exit(1);
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
main();
|