@xnoxs/flux-lang 3.5.3 → 4.0.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 +31 -0
- package/README.md +3 -1
- package/dist/flux-cli.js +171 -11
- package/dist/flux.cjs.js +64 -1
- package/dist/flux.esm.js +64 -1
- package/dist/flux.min.js +20 -20
- package/package.json +1 -1
- package/src/self/codegen.flux +5 -2
- package/src/self/codegen.js +1 -794
- package/src/self/lexer.flux +1 -1
- package/src/self/lexer.js +1 -713
- package/src/self/lexer.stage2.js +700 -0
- package/src/self/parser.flux +41 -0
- package/src/self/parser.js +1 -1571
- package/src/self/pkg.flux +76 -0
- package/src/self/pkg.js +82 -0
- package/src/self/transpiler.flux +14 -4
- package/src/self/transpiler.js +1 -83
- package/src/self/type-checker.flux +12 -0
- package/src/self/type-checker.js +1 -1114
package/src/self/pkg.flux
CHANGED
|
@@ -323,6 +323,82 @@ export async fn cmdInfo(name, opts):
|
|
|
323
323
|
catch(e):
|
|
324
324
|
err("Could not fetch info for " + name + ": " + e.message)
|
|
325
325
|
|
|
326
|
+
// ── flux upgrade [--check] ────────────────────────────────────
|
|
327
|
+
export async fn cmdUpgrade(opts):
|
|
328
|
+
val isCheck = opts?.check ?? false
|
|
329
|
+
val cwd = process.cwd()
|
|
330
|
+
val pkg = readPackage(cwd)
|
|
331
|
+
|
|
332
|
+
if not pkg:
|
|
333
|
+
err("No flux.json found. Run: flux init")
|
|
334
|
+
return
|
|
335
|
+
|
|
336
|
+
val deps = pkg.dependencies ?? {}
|
|
337
|
+
val devDeps = pkg.devDependencies ?? {}
|
|
338
|
+
val all = { ...deps, ...devDeps }
|
|
339
|
+
val names = Object.keys(all)
|
|
340
|
+
|
|
341
|
+
if names.length == 0:
|
|
342
|
+
info("No dependencies to upgrade")
|
|
343
|
+
console.log()
|
|
344
|
+
return
|
|
345
|
+
|
|
346
|
+
if isCheck:
|
|
347
|
+
console.log(clr(C.cyan, "\n Checking " + names.length + " package(s) for updates...\n"))
|
|
348
|
+
else:
|
|
349
|
+
console.log(clr(C.cyan, "\n Upgrading " + names.length + " package(s) to latest...\n"))
|
|
350
|
+
|
|
351
|
+
var outdated = 0
|
|
352
|
+
var updated = 0
|
|
353
|
+
|
|
354
|
+
for name in names:
|
|
355
|
+
val current = all[name]
|
|
356
|
+
val spinner = startSpinner("Checking " + clr(C.bold, name) + " ...")
|
|
357
|
+
try:
|
|
358
|
+
val info_ = await fetchJson(REGISTRY_URL + "/" + name)
|
|
359
|
+
val latest = info_["dist-tags"]?.latest ?? null
|
|
360
|
+
stopSpinner(spinner)
|
|
361
|
+
|
|
362
|
+
if not latest:
|
|
363
|
+
console.log(" " + clr(C.gray, "? ") + clr(C.bold, name) + clr(C.gray, " — could not resolve latest"))
|
|
364
|
+
continue
|
|
365
|
+
|
|
366
|
+
val currentClean = current.replace("^", "").replace("~", "")
|
|
367
|
+
if currentClean == latest:
|
|
368
|
+
console.log(" " + clr(C.green, "✓ ") + clr(C.bold, name) + clr(C.gray, " " + current + " (up to date)"))
|
|
369
|
+
else:
|
|
370
|
+
outdated = outdated + 1
|
|
371
|
+
if isCheck:
|
|
372
|
+
console.log(" " + clr(C.yellow, "↑ ") + clr(C.bold, name) + clr(C.gray, " " + current + " → ") + clr(C.green, "^" + latest))
|
|
373
|
+
else:
|
|
374
|
+
val isDev = devDeps[name] != null
|
|
375
|
+
val depKey = isDev ? "devDependencies" : "dependencies"
|
|
376
|
+
pkg[depKey][name] = "^" + latest
|
|
377
|
+
updated = updated + 1
|
|
378
|
+
console.log(" " + clr(C.green, "✓ ") + clr(C.bold, name) + clr(C.gray, " " + current + " → ") + clr(C.green, "^" + latest))
|
|
379
|
+
|
|
380
|
+
catch(e):
|
|
381
|
+
stopSpinner(spinner)
|
|
382
|
+
console.log(" " + clr(C.red, "✗ ") + clr(C.bold, name) + clr(C.gray, " — " + e.message))
|
|
383
|
+
|
|
384
|
+
console.log()
|
|
385
|
+
|
|
386
|
+
if isCheck:
|
|
387
|
+
if outdated == 0:
|
|
388
|
+
ok("All packages are up to date")
|
|
389
|
+
else:
|
|
390
|
+
console.log(clr(C.yellow, " " + outdated + " package(s) can be upgraded"))
|
|
391
|
+
console.log(clr(C.gray, " Run ") + clr(C.yellow, "flux upgrade") + clr(C.gray, " to apply updates"))
|
|
392
|
+
else:
|
|
393
|
+
if updated == 0:
|
|
394
|
+
ok("All packages are already up to date")
|
|
395
|
+
else:
|
|
396
|
+
saveFluxJson(pkg, cwd)
|
|
397
|
+
ok(updated + " package(s) updated in flux.json")
|
|
398
|
+
console.log(clr(C.gray, " Run ") + clr(C.yellow, "flux install") + clr(C.gray, " to install updated versions"))
|
|
399
|
+
|
|
400
|
+
console.log()
|
|
401
|
+
|
|
326
402
|
// ── flux publish ──────────────────────────────────────────────
|
|
327
403
|
export fn cmdPublish(opts):
|
|
328
404
|
val cwd = process.cwd()
|
package/src/self/pkg.js
CHANGED
|
@@ -310,6 +310,88 @@ async function cmdInfo(name, opts) {
|
|
|
310
310
|
}
|
|
311
311
|
}
|
|
312
312
|
module.exports.cmdInfo = cmdInfo;
|
|
313
|
+
async function cmdUpgrade(opts) {
|
|
314
|
+
const isCheck = (opts?.check ?? false);
|
|
315
|
+
const cwd = process.cwd();
|
|
316
|
+
const pkg = readPackage(cwd);
|
|
317
|
+
if (!pkg) {
|
|
318
|
+
err("No flux.json found. Run: flux init");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const deps = (pkg.dependencies ?? { });
|
|
322
|
+
const devDeps = (pkg.devDependencies ?? { });
|
|
323
|
+
const all = { ...deps, ...devDeps };
|
|
324
|
+
const names = Object.keys(all);
|
|
325
|
+
if ((names.length == 0)) {
|
|
326
|
+
info("No dependencies to upgrade");
|
|
327
|
+
console.log();
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
if (isCheck) {
|
|
331
|
+
console.log(clr(C.cyan, (("\n Checking " + names.length) + " package(s) for updates...\n")));
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
console.log(clr(C.cyan, (("\n Upgrading " + names.length) + " package(s) to latest...\n")));
|
|
335
|
+
}
|
|
336
|
+
let outdated = 0;
|
|
337
|
+
let updated = 0;
|
|
338
|
+
for (const name of names) {
|
|
339
|
+
const current = all[name];
|
|
340
|
+
const spinner = startSpinner((("Checking " + clr(C.bold, name)) + " ..."));
|
|
341
|
+
try {
|
|
342
|
+
const info_ = await fetchJson(((REGISTRY_URL + "/") + name));
|
|
343
|
+
const latest = (info_["dist-tags"]?.latest ?? null);
|
|
344
|
+
stopSpinner(spinner);
|
|
345
|
+
if (!latest) {
|
|
346
|
+
console.log((((" " + clr(C.gray, "? ")) + clr(C.bold, name)) + clr(C.gray, " — could not resolve latest")));
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const currentClean = current.replace("^", "").replace("~", "");
|
|
350
|
+
if ((currentClean == latest)) {
|
|
351
|
+
console.log((((" " + clr(C.green, "✓ ")) + clr(C.bold, name)) + clr(C.gray, ((" " + current) + " (up to date)"))));
|
|
352
|
+
}
|
|
353
|
+
else {
|
|
354
|
+
outdated = (outdated + 1);
|
|
355
|
+
if (isCheck) {
|
|
356
|
+
console.log(((((" " + clr(C.yellow, "↑ ")) + clr(C.bold, name)) + clr(C.gray, ((" " + current) + " → "))) + clr(C.green, ("^" + latest))));
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
const isDev = (devDeps[name] != null);
|
|
360
|
+
const depKey = (isDev ? "devDependencies" : "dependencies");
|
|
361
|
+
pkg[depKey][name] = ("^" + latest);
|
|
362
|
+
updated = (updated + 1);
|
|
363
|
+
console.log(((((" " + clr(C.green, "✓ ")) + clr(C.bold, name)) + clr(C.gray, ((" " + current) + " → "))) + clr(C.green, ("^" + latest))));
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
catch (e) {
|
|
368
|
+
stopSpinner(spinner);
|
|
369
|
+
console.log((((" " + clr(C.red, "✗ ")) + clr(C.bold, name)) + clr(C.gray, (" — " + e.message))));
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
console.log();
|
|
373
|
+
if (isCheck) {
|
|
374
|
+
if ((outdated == 0)) {
|
|
375
|
+
ok("All packages are up to date");
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
console.log(clr(C.yellow, ((" " + outdated) + " package(s) can be upgraded")));
|
|
379
|
+
console.log(((clr(C.gray, " Run ") + clr(C.yellow, "flux upgrade")) + clr(C.gray, " to apply updates")));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
if ((updated == 0)) {
|
|
384
|
+
ok("All packages are already up to date");
|
|
385
|
+
}
|
|
386
|
+
else {
|
|
387
|
+
saveFluxJson(pkg, cwd);
|
|
388
|
+
ok((updated + " package(s) updated in flux.json"));
|
|
389
|
+
console.log(((clr(C.gray, " Run ") + clr(C.yellow, "flux install")) + clr(C.gray, " to install updated versions")));
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
console.log();
|
|
393
|
+
}
|
|
394
|
+
module.exports.cmdUpgrade = cmdUpgrade;
|
|
313
395
|
function cmdPublish(opts) {
|
|
314
396
|
const cwd = process.cwd();
|
|
315
397
|
const pkg = readPackage(cwd);
|
package/src/self/transpiler.flux
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ============================================================
|
|
2
|
-
// Flux Self-Hosted Transpiler — v3.
|
|
2
|
+
// Flux Self-Hosted Transpiler — v3.5 (100% Self-Hosting)
|
|
3
3
|
// src/self/transpiler.flux — written in Flux, compiled by stage-0
|
|
4
4
|
//
|
|
5
5
|
// Full pipeline:
|
|
@@ -15,8 +15,18 @@ import { transformJsx, FLUX_H_BROWSER, FLUX_H_SERVER, FLUX_CSS_BROWSER, FLUX_CSS
|
|
|
15
15
|
import { Checker } from './checker'
|
|
16
16
|
import { FluxTypeChecker } from './type-checker'
|
|
17
17
|
|
|
18
|
-
// ── Version info
|
|
19
|
-
|
|
18
|
+
// ── Version info — always in sync with package.json ──────────
|
|
19
|
+
import Fs from "fs"
|
|
20
|
+
import Path from "path"
|
|
21
|
+
|
|
22
|
+
fn _readFluxVersion():
|
|
23
|
+
try:
|
|
24
|
+
val pkgPath = Path.resolve(__dirname, "../../package.json")
|
|
25
|
+
return JSON.parse(Fs.readFileSync(pkgPath, "utf8")).version
|
|
26
|
+
catch(e):
|
|
27
|
+
return "4.0.0"
|
|
28
|
+
|
|
29
|
+
export val FLUX_VERSION = _readFluxVersion()
|
|
20
30
|
export val FLUX_STAGE = "self-hosted"
|
|
21
31
|
|
|
22
32
|
// ── Public API ────────────────────────────────────────────────
|
|
@@ -89,7 +99,7 @@ export fn transpile(source, options):
|
|
|
89
99
|
// ── Stage 5: Code generation ────────────────────────────────
|
|
90
100
|
result.stage = "codegen"
|
|
91
101
|
val indent = opts.mangle ? "" : " "
|
|
92
|
-
val cg = makeCodeGen({ indent })
|
|
102
|
+
val cg = makeCodeGen({ indent, version: FLUX_VERSION })
|
|
93
103
|
val genResult = cg.generate(ast)
|
|
94
104
|
var code = genResult.code
|
|
95
105
|
|
package/src/self/transpiler.js
CHANGED
|
@@ -1,83 +1 @@
|
|
|
1
|
-
|
|
2
|
-
"use strict";
|
|
3
|
-
|
|
4
|
-
const { Lexer, lexerize, T } = require("./lexer");
|
|
5
|
-
const { Parser, makeParser } = require("./parser");
|
|
6
|
-
const { CodeGenerator, makeCodeGen } = require("./codegen");
|
|
7
|
-
const { transformCss } = require("./css-preprocessor");
|
|
8
|
-
const { transformJsx, FLUX_H_BROWSER, FLUX_H_SERVER, FLUX_CSS_BROWSER, FLUX_CSS_SERVER } = require("./jsx");
|
|
9
|
-
const { Checker } = require("./checker");
|
|
10
|
-
const { FluxTypeChecker } = require("./type-checker");
|
|
11
|
-
const FLUX_VERSION = "3.0.0";
|
|
12
|
-
module.exports.FLUX_VERSION = FLUX_VERSION;
|
|
13
|
-
const FLUX_STAGE = "self-hosted";
|
|
14
|
-
module.exports.FLUX_STAGE = FLUX_STAGE;
|
|
15
|
-
function transpile(source, options) {
|
|
16
|
-
const opts = (options ?? { });
|
|
17
|
-
const result = { success: false, output: "", ast: null, tokens: null, errors: [], typeErrors: [], typeWarnings: [], stage: "" };
|
|
18
|
-
try {
|
|
19
|
-
let src = source;
|
|
20
|
-
result.stage = "css";
|
|
21
|
-
if ((opts.css != false)) {
|
|
22
|
-
src = transformCss(src);
|
|
23
|
-
}
|
|
24
|
-
result.stage = "jsx";
|
|
25
|
-
if (opts.jsx) {
|
|
26
|
-
const jsxTarget = (opts.jsxTarget ?? "browser");
|
|
27
|
-
const jsxResult = transformJsx(src, { target: jsxTarget });
|
|
28
|
-
src = jsxResult.source;
|
|
29
|
-
if (jsxResult.hasJsx) {
|
|
30
|
-
opts._jsxHelpers = jsxResult.runtimeHelpers;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
result.stage = "lexer";
|
|
34
|
-
const lexer = lexerize(src);
|
|
35
|
-
const tokens = lexer.tokenize();
|
|
36
|
-
result.tokens = tokens;
|
|
37
|
-
result.stage = "parser";
|
|
38
|
-
const ast = makeParser(tokens).parse();
|
|
39
|
-
result.ast = ast;
|
|
40
|
-
if ((opts.check != false)) {
|
|
41
|
-
result.stage = "checker";
|
|
42
|
-
const checker = new Checker([], []);
|
|
43
|
-
const checkResult = checker.check(ast);
|
|
44
|
-
if ((checkResult.errors.length > 0)) {
|
|
45
|
-
result.errors = checkResult.errors;
|
|
46
|
-
result.stage = null;
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (opts.typecheck) {
|
|
51
|
-
result.stage = "type-checker";
|
|
52
|
-
const tc = new FluxTypeChecker([], [], new Map(), new Map(), new Map(), new Map());
|
|
53
|
-
const tcResult = tc.check(ast);
|
|
54
|
-
result.typeErrors = tcResult.errors;
|
|
55
|
-
result.typeWarnings = tcResult.warnings;
|
|
56
|
-
if ((opts.strict && (tcResult.errors.length > 0))) {
|
|
57
|
-
result.errors = tcResult.errors;
|
|
58
|
-
result.stage = null;
|
|
59
|
-
return result;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
result.stage = "codegen";
|
|
63
|
-
const indent = (opts.mangle ? "" : " ");
|
|
64
|
-
const cg = makeCodeGen({ indent });
|
|
65
|
-
const genResult = cg.generate(ast);
|
|
66
|
-
let code = genResult.code;
|
|
67
|
-
if (opts._jsxHelpers) {
|
|
68
|
-
code = ((opts._jsxHelpers + "\n") + code);
|
|
69
|
-
}
|
|
70
|
-
result.output = code;
|
|
71
|
-
result.success = true;
|
|
72
|
-
result.stage = null;
|
|
73
|
-
}
|
|
74
|
-
catch (e) {
|
|
75
|
-
result.errors.push({ message: e.message, name: e.name, stage: result.stage });
|
|
76
|
-
}
|
|
77
|
-
return result;
|
|
78
|
-
}
|
|
79
|
-
module.exports.transpile = transpile;
|
|
80
|
-
function transpileFile(source, opts) {
|
|
81
|
-
return transpile(source, { check: true, typecheck: (opts?.typecheck ?? false), jsx: (opts?.jsx ?? false), jsxTarget: (opts?.jsxTarget ?? "browser"), mangle: (opts?.mangle ?? false), strict: (opts?.strict ?? false), ...(opts ?? { }) });
|
|
82
|
-
}
|
|
83
|
-
module.exports.transpileFile = transpileFile;
|
|
1
|
+
"use strict"; const { Lexer, lexerize, T } = require("./lexer"); const { Parser, makeParser } = require("./parser"); const { CodeGenerator, makeCodeGen } = require("./codegen"); const { transformCss } = require("./css-preprocessor"); const { transformJsx, FLUX_H_BROWSER, FLUX_H_SERVER, FLUX_CSS_BROWSER, FLUX_CSS_SERVER } = require("./jsx"); const { Checker } = require("./checker"); const { FluxTypeChecker } = require("./type-checker"); const Fs = require("fs"); const Path = require("path"); function _a() { try { const pkgPath = Path.resolve(__dirname, "../../package.json"); return JSON.parse(Fs.readFileSync(pkgPath, "utf8")).version; } catch (_b) { return "4.0.0"; } } const FLUX_VERSION = _a(); module.exports.FLUX_VERSION = FLUX_VERSION; const FLUX_STAGE = "self-hosted"; module.exports.FLUX_STAGE = FLUX_STAGE; function transpile(_c, _d) { const opts = (_d ?? { }); const result = { success: false, output: "", ast: null, tokens: null, errors: [], typeErrors: [], typeWarnings: [], stage: "" }; try { let src = _c; result.stage = "css"; if ((opts.css != false)) { src = transformCss(src); } result.stage = "jsx"; if (opts.jsx) { const jsxTarget = (opts.jsxTarget ?? "browser"); const jsxResult = transformJsx(src, { target: jsxTarget }); src = jsxResult.source; if (jsxResult.hasJsx) { opts._jsxHelpers = jsxResult.runtimeHelpers; } } result.stage = "lexer"; const lexer = lexerize(src); const tokens = lexer.tokenize(); result.tokens = tokens; result.stage = "parser"; const ast = makeParser(tokens).parse(); result.ast = ast; if ((opts.check != false)) { result.stage = "checker"; const checker = new Checker([], []); const checkResult = checker.check(ast); if ((checkResult.errors.length > 0)) { result.errors = checkResult.errors; result.stage = null; return result; } } if (opts.typecheck) { result.stage = "type-checker"; const tc = new FluxTypeChecker([], [], new Map(), new Map(), new Map(), new Map()); const tcResult = tc.check(ast); result.typeErrors = tcResult.errors; result.typeWarnings = tcResult.warnings; if ((opts.strict && (tcResult.errors.length > 0))) { result.errors = tcResult.errors; result.stage = null; return result; } } result.stage = "codegen"; const indent = (opts.mangle ? "" : " "); const cg = makeCodeGen({ indent, version: FLUX_VERSION }); const genResult = cg.generate(ast); let code = genResult.code; if (opts._jsxHelpers) { code = ((opts._jsxHelpers + "\n") + code); } result.output = code; result.success = true; result.stage = null; } catch (_b) { result.errors.push({ message: _b.message, name: _b.name, stage: result.stage }); } return result; } module.exports.transpile = transpile; function transpileFile(_c, _e) { return transpile(_c, { check: true, typecheck: (_e?.typecheck ?? false), jsx: (_e?.jsx ?? false), jsxTarget: (_e?.jsxTarget ?? "browser"), mangle: (_e?.mangle ?? false), strict: (_e?.strict ?? false), ...(_e ?? { }) }); } module.exports.transpileFile = transpileFile;
|
|
@@ -734,6 +734,18 @@ export class FluxTypeChecker:
|
|
|
734
734
|
clsEnv.set("self", T_OBJECT(shape))
|
|
735
735
|
for m in node.methods: self._checkStmt(m, clsEnv)
|
|
736
736
|
|
|
737
|
+
else if node.type == "DeclareDecl":
|
|
738
|
+
val d = node.decl
|
|
739
|
+
if d.type == "FnDecl":
|
|
740
|
+
val retType = d.retType ? parseAnnotation(d.retType) : null
|
|
741
|
+
val paramTypes = d.params.map(p -> p.typeAnn ? parseAnnotation(p.typeAnn) : T_UNKNOWN)
|
|
742
|
+
if d.name: env.set(d.name, T_FN(paramTypes, retType ?? T_UNKNOWN))
|
|
743
|
+
else if d.type == "VarDecl":
|
|
744
|
+
val t = d.typeAnn ? parseAnnotation(d.typeAnn) : T_UNKNOWN
|
|
745
|
+
env.set(d.name, t)
|
|
746
|
+
else if d.type == "ClassDecl":
|
|
747
|
+
env.set(d.name, T_NAMED(d.name))
|
|
748
|
+
|
|
737
749
|
else if node.type == "TypeDecl":
|
|
738
750
|
for v in node.variants:
|
|
739
751
|
if v.fields.length == 0:
|