@xnoxs/flux-lang 3.5.3 → 4.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xnoxs/flux-lang",
3
- "version": "3.5.3",
3
+ "version": "4.0.1",
4
4
  "description": "Flux — A modern language that transpiles to JavaScript. Python-clean syntax, TypeScript-level safety, Rust-inspired pattern matching.",
5
5
  "main": "dist/flux.cjs.js",
6
6
  "module": "dist/flux.esm.js",
package/scripts/build.js CHANGED
File without changes
package/src/config.js CHANGED
File without changes
File without changes
File without changes
package/src/self/cli.flux CHANGED
File without changes
@@ -54,6 +54,7 @@ export class CodeGenerator:
54
54
  smBuilder: any
55
55
  _needsFmt: bool
56
56
  _loopDepth: int
57
+ _version: string
57
58
 
58
59
  fn i():
59
60
  var s = ''
@@ -83,7 +84,7 @@ export class CodeGenerator:
83
84
  self.lines = []
84
85
  self.level = 0
85
86
  self._needsFmt = false
86
- self.emit('// Generated by Flux Transpiler v3.1.0 (self-hosted)')
87
+ self.emit('// Generated by Flux Transpiler v' + (self._version ?? "3.5.3") + ' (self-hosted)')
87
88
  self.emit('"use strict";')
88
89
  self.blank()
89
90
  for node in ast.body: self.genStmt(node)
@@ -111,6 +112,7 @@ export class CodeGenerator:
111
112
  else if node.type == 'TypeDecl': self.genTypeDecl(node)
112
113
  else if node.type == 'InterfaceDecl': self.genInterfaceDecl(node)
113
114
  else if node.type == 'EnumDecl': self.genEnumDecl(node)
115
+ else if node.type == 'DeclareDecl': return
114
116
  else if node.type == 'ExprStmt': self.emit(self.genExpr(node.expr) + ';')
115
117
  else:
116
118
  throw new Error("Unknown statement: {node.type}")
@@ -552,4 +554,5 @@ export class CodeGenerator:
552
554
  export fn makeCodeGen(opts):
553
555
  val ind = opts?.indent ?? ' '
554
556
  val smb = opts?.smBuilder ?? null
555
- return new CodeGenerator(ind, 0, [], {}, smb, false, 0)
557
+ val ver = opts?.version ?? "3.5.3"
558
+ return new CodeGenerator(ind, 0, [], {}, smb, false, 0, ver)
@@ -52,7 +52,7 @@ function getAllFields(name, reg, visited) {
52
52
  return [...parent, ...reg[name].fields];
53
53
  }
54
54
  class CodeGenerator {
55
- constructor(ind, level, lines, clsReg, smBuilder, _needsFmt, _loopDepth) {
55
+ constructor(ind, level, lines, clsReg, smBuilder, _needsFmt, _loopDepth, _version) {
56
56
  this.ind = ind;
57
57
  this.level = level;
58
58
  this.lines = lines;
@@ -60,6 +60,7 @@ class CodeGenerator {
60
60
  this.smBuilder = smBuilder;
61
61
  this._needsFmt = _needsFmt;
62
62
  this._loopDepth = _loopDepth;
63
+ this._version = _version;
63
64
  }
64
65
 
65
66
  i() {
@@ -99,7 +100,7 @@ class CodeGenerator {
99
100
  this.lines = [];
100
101
  this.level = 0;
101
102
  this._needsFmt = false;
102
- this.emit("// Generated by Flux Transpiler v3.1.0 (self-hosted)");
103
+ this.emit((("// Generated by Flux Transpiler v" + (this._version ?? "3.5.3")) + " (self-hosted)"));
103
104
  this.emit("\"use strict\";");
104
105
  this.blank();
105
106
  for (const node of ast.body) {
@@ -169,6 +170,9 @@ class CodeGenerator {
169
170
  else if ((node.type == "EnumDecl")) {
170
171
  this.genEnumDecl(node);
171
172
  }
173
+ else if ((node.type == "DeclareDecl")) {
174
+ return;
175
+ }
172
176
  else if ((node.type == "ExprStmt")) {
173
177
  this.emit((this.genExpr(node.expr) + ";"));
174
178
  }
@@ -789,6 +793,7 @@ module.exports.CodeGenerator = CodeGenerator;
789
793
  function makeCodeGen(opts) {
790
794
  const ind = (opts?.indent ?? " ");
791
795
  const smb = (opts?.smBuilder ?? null);
792
- return new CodeGenerator(ind, 0, [], { }, smb, false, 0);
796
+ const ver = (opts?.version ?? "3.5.3");
797
+ return new CodeGenerator(ind, 0, [], { }, smb, false, 0, ver);
793
798
  }
794
799
  module.exports.makeCodeGen = makeCodeGen;
File without changes
File without changes
File without changes
package/src/self/jsx.flux CHANGED
File without changes
@@ -43,7 +43,7 @@ export val T = {
43
43
  export val TokenType = T
44
44
 
45
45
  val KEYWORDS = {
46
- "var": 'VAR', "val": 'VAL', "fn": 'FN', "return": 'RETURN',
46
+ "var": 'VAR', "val": 'VAL', "fn": 'FN', "return": 'RETURN', "declare": 'DECLARE',
47
47
  "if": 'IF', "else": 'ELSE', "for": 'FOR', "in": 'IN',
48
48
  "while": 'WHILE', "break": 'BREAK', "continue": 'CONTINUE', "do": 'DO',
49
49
  "class": 'CLASS', "extends": 'EXTENDS', "self": 'SELF', "new": 'NEW',
@@ -345,7 +345,7 @@ export class Lexer:
345
345
  if word == '_' and not /[a-zA-Z0-9_]/.test(self.ch()):
346
346
  self.tok(T.WILDCARD, '_', l, c)
347
347
  continue
348
- val kw = KEYWORDS[word]
348
+ val kw = Object.prototype.hasOwnProperty.call(KEYWORDS, word) ? KEYWORDS[word] : undefined
349
349
  if kw == '__TRUE__': self.tok(T.BOOL, true, l, c)
350
350
  else if kw == '__FALSE__': self.tok(T.BOOL, false, l, c)
351
351
  else if kw == '__NULL__': self.tok(T.NULL, null, l, c)
package/src/self/lexer.js CHANGED
@@ -18,7 +18,7 @@ const T = { NUMBER: "NUMBER", STRING: "STRING", BOOL: "BOOL", NULL: "NULL", IDEN
18
18
  module.exports.T = T;
19
19
  const TokenType = T;
20
20
  module.exports.TokenType = TokenType;
21
- const KEYWORDS = { var: "VAR", val: "VAL", fn: "FN", return: "RETURN", if: "IF", else: "ELSE", for: "FOR", in: "IN", while: "WHILE", break: "BREAK", continue: "CONTINUE", do: "DO", class: "CLASS", extends: "EXTENDS", self: "SELF", new: "NEW", interface: "INTERFACE", implements: "IMPLEMENTS", private: "PRIVATE", public: "PUBLIC", protected: "PROTECTED", readonly: "READONLY", static: "STATIC", abstract: "ABSTRACT", override: "OVERRIDE", match: "MATCH", when: "WHEN", import: "IMPORT", export: "EXPORT", from: "FROM", as: "AS", default: "DEFAULT", and: "AND", or: "OR", not: "NOT", async: "ASYNC", await: "AWAIT", try: "TRY", catch: "CATCH", finally: "FINALLY", throw: "THROW", typeof: "TYPEOF", instanceof: "INSTANCEOF", type: "TYPE", enum: "ENUM", satisfies: "SATISFIES", is: "IS", const: "CONST", true: "__TRUE__", false: "__FALSE__", null: "__NULL__" };
21
+ const KEYWORDS = { var: "VAR", val: "VAL", fn: "FN", return: "RETURN", declare: "DECLARE", if: "IF", else: "ELSE", for: "FOR", in: "IN", while: "WHILE", break: "BREAK", continue: "CONTINUE", do: "DO", class: "CLASS", extends: "EXTENDS", self: "SELF", new: "NEW", interface: "INTERFACE", implements: "IMPLEMENTS", private: "PRIVATE", public: "PUBLIC", protected: "PROTECTED", readonly: "READONLY", static: "STATIC", abstract: "ABSTRACT", override: "OVERRIDE", match: "MATCH", when: "WHEN", import: "IMPORT", export: "EXPORT", from: "FROM", as: "AS", default: "DEFAULT", and: "AND", or: "OR", not: "NOT", async: "ASYNC", await: "AWAIT", try: "TRY", catch: "CATCH", finally: "FINALLY", throw: "THROW", typeof: "TYPEOF", instanceof: "INSTANCEOF", type: "TYPE", enum: "ENUM", satisfies: "SATISFIES", is: "IS", const: "CONST", true: "__TRUE__", false: "__FALSE__", null: "__NULL__" };
22
22
  class Lexer {
23
23
  constructor(src, pos, line, col, tokens, indentStack, nestDepth) {
24
24
  this.src = src;
@@ -454,7 +454,7 @@ class Lexer {
454
454
  this.tok(T.WILDCARD, "_", l, c);
455
455
  continue;
456
456
  }
457
- const kw = KEYWORDS[word];
457
+ const kw = (Object.prototype.hasOwnProperty.call(KEYWORDS, word) ? KEYWORDS[word] : undefined);
458
458
  if ((kw == "__TRUE__")) {
459
459
  this.tok(T.BOOL, true, l, c);
460
460
  }
File without changes
File without changes
@@ -85,6 +85,7 @@ export class Parser:
85
85
  if tok.type == T.FN: return self.parseFnDecl(false)
86
86
  if tok.type == T.ASYNC: return self.parseAsyncFn()
87
87
  if tok.type == T.CLASS: return self.parseClassDecl()
88
+ if tok.type == T.DECLARE: return self.parseDeclareDecl()
88
89
  if tok.type == T.IF: return self.parseIf()
89
90
  if tok.type == T.FOR: return self.parseFor()
90
91
  if tok.type == T.WHILE: return self.parseWhile()
@@ -668,6 +669,46 @@ export class Parser:
668
669
  if not self.check(T.FN): self.err('Expected fn after async')
669
670
  return self.parseFnDecl(true)
670
671
 
672
+ fn parseDeclareDecl():
673
+ val loc = self.eat(T.DECLARE)
674
+ val tok = self.peek()
675
+
676
+ if tok.type == T.FN or tok.type == T.ASYNC:
677
+ val isAsync = tok.type == T.ASYNC
678
+ self.skip()
679
+ if isAsync: self.eat(T.FN)
680
+ val name = self.check(T.IDENT) ? self.skip().value : null
681
+ val params = self.parseParamList()
682
+ var retType = null
683
+ if self.check(T.ARROW):
684
+ self.pos = self.pos + 1
685
+ retType = self.parseTypeAnn()
686
+ else if self.check(T.COLON):
687
+ self.pos = self.pos + 1
688
+ retType = self.parseTypeAnn()
689
+ self.skipNewlines()
690
+ val decl = { type: 'FnDecl', name, params, retType, body: [], inline: false, async: isAsync, loc: tok }
691
+ return { type: 'DeclareDecl', decl, loc }
692
+
693
+ if tok.type == T.VAL or tok.type == T.VAR:
694
+ val kind = tok.type == T.VAR ? 'var' : 'val'
695
+ self.skip()
696
+ val name = self.eat(T.IDENT).value
697
+ var typeAnn = null
698
+ if self.maybe(T.COLON): typeAnn = self.parseTypeAnn()
699
+ self.skipNewlines()
700
+ val decl = { type: 'VarDecl', kind, name, typeAnn, init: null, loc: tok }
701
+ return { type: 'DeclareDecl', decl, loc }
702
+
703
+ if tok.type == T.CLASS:
704
+ self.skip()
705
+ val name = self.eat(T.IDENT).value
706
+ self.skipNewlines()
707
+ val decl = { type: 'ClassDecl', name, fields: [], methods: [], loc: tok }
708
+ return { type: 'DeclareDecl', decl, loc }
709
+
710
+ self.err('Expected fn, async fn, val, var, or class after declare')
711
+
671
712
  fn parseParamList():
672
713
  self.eat(T.LPAREN)
673
714
  val params = []
@@ -121,6 +121,9 @@ class Parser {
121
121
  if ((tok.type == T.CLASS)) {
122
122
  return this.parseClassDecl();
123
123
  }
124
+ if ((tok.type == T.DECLARE)) {
125
+ return this.parseDeclareDecl();
126
+ }
124
127
  if ((tok.type == T.IF)) {
125
128
  return this.parseIf();
126
129
  }
@@ -921,6 +924,52 @@ class Parser {
921
924
  return this.parseFnDecl(true);
922
925
  }
923
926
 
927
+ parseDeclareDecl() {
928
+ const loc = this.eat(T.DECLARE);
929
+ const tok = this.peek();
930
+ if (((tok.type == T.FN) || (tok.type == T.ASYNC))) {
931
+ const isAsync = (tok.type == T.ASYNC);
932
+ this.skip();
933
+ if (isAsync) {
934
+ this.eat(T.FN);
935
+ }
936
+ const name = (this.check(T.IDENT) ? this.skip().value : null);
937
+ const params = this.parseParamList();
938
+ let retType = null;
939
+ if (this.check(T.ARROW)) {
940
+ this.pos = (this.pos + 1);
941
+ retType = this.parseTypeAnn();
942
+ }
943
+ else if (this.check(T.COLON)) {
944
+ this.pos = (this.pos + 1);
945
+ retType = this.parseTypeAnn();
946
+ }
947
+ this.skipNewlines();
948
+ const decl = { type: "FnDecl", name, params, retType, body: [], inline: false, async: isAsync, loc: tok };
949
+ return { type: "DeclareDecl", decl, loc };
950
+ }
951
+ if (((tok.type == T.VAL) || (tok.type == T.VAR))) {
952
+ const kind = ((tok.type == T.VAR) ? "var" : "val");
953
+ this.skip();
954
+ const name = this.eat(T.IDENT).value;
955
+ let typeAnn = null;
956
+ if (this.maybe(T.COLON)) {
957
+ typeAnn = this.parseTypeAnn();
958
+ }
959
+ this.skipNewlines();
960
+ const decl = { type: "VarDecl", kind, name, typeAnn, init: null, loc: tok };
961
+ return { type: "DeclareDecl", decl, loc };
962
+ }
963
+ if ((tok.type == T.CLASS)) {
964
+ this.skip();
965
+ const name = this.eat(T.IDENT).value;
966
+ this.skipNewlines();
967
+ const decl = { type: "ClassDecl", name, fields: [], methods: [], loc: tok };
968
+ return { type: "DeclareDecl", decl, loc };
969
+ }
970
+ this.err("Expected fn, async fn, val, var, or class after declare");
971
+ }
972
+
924
973
  parseParamList() {
925
974
  this.eat(T.LPAREN);
926
975
  const params = [];
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);
File without changes
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  // ============================================================
2
- // Flux Self-Hosted Transpiler — v3.0 (100% Self-Hosting)
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
- export val FLUX_VERSION = "3.0.0"
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.1"
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
 
@@ -8,7 +8,18 @@ const { transformCss } = require("./css-preprocessor");
8
8
  const { transformJsx, FLUX_H_BROWSER, FLUX_H_SERVER, FLUX_CSS_BROWSER, FLUX_CSS_SERVER } = require("./jsx");
9
9
  const { Checker } = require("./checker");
10
10
  const { FluxTypeChecker } = require("./type-checker");
11
- const FLUX_VERSION = "3.0.0";
11
+ const Fs = require("fs");
12
+ const Path = require("path");
13
+ function _readFluxVersion() {
14
+ try {
15
+ const pkgPath = Path.resolve(__dirname, "../../package.json");
16
+ return JSON.parse(Fs.readFileSync(pkgPath, "utf8")).version;
17
+ }
18
+ catch (e) {
19
+ return "4.0.1";
20
+ }
21
+ }
22
+ const FLUX_VERSION = _readFluxVersion();
12
23
  module.exports.FLUX_VERSION = FLUX_VERSION;
13
24
  const FLUX_STAGE = "self-hosted";
14
25
  module.exports.FLUX_STAGE = FLUX_STAGE;
@@ -61,7 +72,7 @@ function transpile(source, options) {
61
72
  }
62
73
  result.stage = "codegen";
63
74
  const indent = (opts.mangle ? "" : " ");
64
- const cg = makeCodeGen({ indent });
75
+ const cg = makeCodeGen({ indent, version: FLUX_VERSION });
65
76
  const genResult = cg.generate(ast);
66
77
  let code = genResult.code;
67
78
  if (opts._jsxHelpers) {
@@ -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:
@@ -995,6 +995,23 @@ class FluxTypeChecker {
995
995
  this._checkStmt(m, clsEnv);
996
996
  }
997
997
  }
998
+ else if ((node.type == "DeclareDecl")) {
999
+ const d = node.decl;
1000
+ if ((d.type == "FnDecl")) {
1001
+ const retType = (d.retType ? parseAnnotation(d.retType) : null);
1002
+ const paramTypes = d.params.map((p) => (p.typeAnn ? parseAnnotation(p.typeAnn) : T_UNKNOWN));
1003
+ if (d.name) {
1004
+ env.set(d.name, T_FN(paramTypes, (retType ?? T_UNKNOWN)));
1005
+ }
1006
+ }
1007
+ else if ((d.type == "VarDecl")) {
1008
+ const t = (d.typeAnn ? parseAnnotation(d.typeAnn) : T_UNKNOWN);
1009
+ env.set(d.name, t);
1010
+ }
1011
+ else if ((d.type == "ClassDecl")) {
1012
+ env.set(d.name, T_NAMED(d.name));
1013
+ }
1014
+ }
998
1015
  else if ((node.type == "TypeDecl")) {
999
1016
  for (const v of node.variants) {
1000
1017
  if ((v.fields.length == 0)) {