@xnoxs/flux-lang 3.5.2 → 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 +219 -15
- package/dist/flux.cjs.js +86 -3
- package/dist/flux.esm.js +86 -3
- package/dist/flux.min.js +20 -20
- package/package.json +1 -1
- package/src/self/cli.js +1 -1
- package/src/self/codegen.flux +5 -2
- package/src/self/codegen.js +1 -794
- package/src/self/css-preprocessor.js +1 -1
- 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 +107 -10
- package/src/self/pkg.js +108 -2
- package/src/self/test-runner.js +1 -1
- 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
|
@@ -24,16 +24,17 @@ val FLUX_PKG_DIR = "flux_modules"
|
|
|
24
24
|
val PKG_FILE = "flux.json"
|
|
25
25
|
|
|
26
26
|
// ── ANSI colors ───────────────────────────────────────────────
|
|
27
|
+
val ESC = "\u001b"
|
|
27
28
|
val C = {
|
|
28
|
-
reset: "
|
|
29
|
-
bold: "
|
|
30
|
-
dim: "
|
|
31
|
-
red: "
|
|
32
|
-
green: "
|
|
33
|
-
yellow: "
|
|
34
|
-
blue: "
|
|
35
|
-
cyan: "
|
|
36
|
-
gray: "
|
|
29
|
+
reset: ESC + "[0m",
|
|
30
|
+
bold: ESC + "[1m",
|
|
31
|
+
dim: ESC + "[2m",
|
|
32
|
+
red: ESC + "[31m",
|
|
33
|
+
green: ESC + "[32m",
|
|
34
|
+
yellow: ESC + "[33m",
|
|
35
|
+
blue: ESC + "[34m",
|
|
36
|
+
cyan: ESC + "[36m",
|
|
37
|
+
gray: ESC + "[90m",
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
fn clr(c, s): return c + s + C.reset
|
|
@@ -41,6 +42,24 @@ fn ok(msg): console.log(clr(C.green, "✓ ") + msg)
|
|
|
41
42
|
fn err(msg): console.error(clr(C.red, "✗ ") + msg)
|
|
42
43
|
fn info(msg): console.log(clr(C.cyan, " ") + msg)
|
|
43
44
|
|
|
45
|
+
// ── Spinner ───────────────────────────────────────────────────
|
|
46
|
+
val SPIN_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"]
|
|
47
|
+
val stdout = process.stdout
|
|
48
|
+
|
|
49
|
+
fn startSpinner(label):
|
|
50
|
+
if not stdout.isTTY: return null
|
|
51
|
+
var frame = 0
|
|
52
|
+
fn tick():
|
|
53
|
+
stdout.write("\r" + clr(C.cyan, SPIN_FRAMES[frame % SPIN_FRAMES.length]) + " " + label + " ")
|
|
54
|
+
frame = frame + 1
|
|
55
|
+
val timer = setInterval(tick, 80)
|
|
56
|
+
return timer
|
|
57
|
+
|
|
58
|
+
fn stopSpinner(timer):
|
|
59
|
+
if not timer: return
|
|
60
|
+
clearInterval(timer)
|
|
61
|
+
stdout.write("\r" + ESC + "[2K")
|
|
62
|
+
|
|
44
63
|
// ── HTTP fetch (Node built-in, no dependencies) ───────────────
|
|
45
64
|
async fn fetchJson(url):
|
|
46
65
|
val mod = url.startsWith("https") ? Https : Http
|
|
@@ -103,13 +122,14 @@ export async fn cmdAdd(specs, opts):
|
|
|
103
122
|
|
|
104
123
|
for spec in specs:
|
|
105
124
|
val { name, version } = parsePackageSpec(spec)
|
|
106
|
-
|
|
125
|
+
val spinner = startSpinner("Fetching " + clr(C.bold, name) + clr(C.gray, "@" + version) + " ...")
|
|
107
126
|
|
|
108
127
|
try:
|
|
109
128
|
val info_ = await fetchJson(REGISTRY_URL + "/" + name)
|
|
110
129
|
val resolvedVersion = version == "latest" ? (info_["dist-tags"]?.latest ?? "1.0.0") : version
|
|
111
130
|
|
|
112
131
|
val versionInfo = info_.versions?.[resolvedVersion]
|
|
132
|
+
stopSpinner(spinner)
|
|
113
133
|
if not versionInfo:
|
|
114
134
|
err("Version " + resolvedVersion + " not found for " + name)
|
|
115
135
|
continue
|
|
@@ -125,6 +145,7 @@ export async fn cmdAdd(specs, opts):
|
|
|
125
145
|
info("Added to " + (isDev ? "devDependencies" : "dependencies"))
|
|
126
146
|
|
|
127
147
|
catch(e):
|
|
148
|
+
stopSpinner(spinner)
|
|
128
149
|
err("Failed to fetch " + name + ": " + e.message)
|
|
129
150
|
|
|
130
151
|
console.log()
|
|
@@ -302,6 +323,82 @@ export async fn cmdInfo(name, opts):
|
|
|
302
323
|
catch(e):
|
|
303
324
|
err("Could not fetch info for " + name + ": " + e.message)
|
|
304
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
|
+
|
|
305
402
|
// ── flux publish ──────────────────────────────────────────────
|
|
306
403
|
export fn cmdPublish(opts):
|
|
307
404
|
val cwd = process.cwd()
|
package/src/self/pkg.js
CHANGED
|
@@ -21,7 +21,8 @@ const { readPackage, writeConfig, loadConfig } = require("./config");
|
|
|
21
21
|
const REGISTRY_URL = "https://registry.npmjs.org";
|
|
22
22
|
const FLUX_PKG_DIR = "flux_modules";
|
|
23
23
|
const PKG_FILE = "flux.json";
|
|
24
|
-
const
|
|
24
|
+
const ESC = "\u001b";
|
|
25
|
+
const C = { reset: (ESC + "[0m"), bold: (ESC + "[1m"), dim: (ESC + "[2m"), red: (ESC + "[31m"), green: (ESC + "[32m"), yellow: (ESC + "[33m"), blue: (ESC + "[34m"), cyan: (ESC + "[36m"), gray: (ESC + "[90m") };
|
|
25
26
|
function clr(c, s) {
|
|
26
27
|
return ((c + s) + C.reset);
|
|
27
28
|
}
|
|
@@ -34,6 +35,27 @@ function err(msg) {
|
|
|
34
35
|
function info(msg) {
|
|
35
36
|
console.log((clr(C.cyan, " ") + msg));
|
|
36
37
|
}
|
|
38
|
+
const SPIN_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
39
|
+
const stdout = process.stdout;
|
|
40
|
+
function startSpinner(label) {
|
|
41
|
+
if (!stdout.isTTY) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
let frame = 0;
|
|
45
|
+
function tick() {
|
|
46
|
+
stdout.write((((("\r" + clr(C.cyan, SPIN_FRAMES[(frame % SPIN_FRAMES.length)])) + " ") + label) + " "));
|
|
47
|
+
frame = (frame + 1);
|
|
48
|
+
}
|
|
49
|
+
const timer = setInterval(tick, 80);
|
|
50
|
+
return timer;
|
|
51
|
+
}
|
|
52
|
+
function stopSpinner(timer) {
|
|
53
|
+
if (!timer) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
clearInterval(timer);
|
|
57
|
+
stdout.write((("\r" + ESC) + "[2K"));
|
|
58
|
+
}
|
|
37
59
|
async function fetchJson(url) {
|
|
38
60
|
const mod = (url.startsWith("https") ? Https : Http);
|
|
39
61
|
function doRequest(resolve, reject) {
|
|
@@ -85,11 +107,12 @@ async function cmdAdd(specs, opts) {
|
|
|
85
107
|
const pkg = ensureFluxJson(cwd);
|
|
86
108
|
for (const spec of specs) {
|
|
87
109
|
const { name, version } = parsePackageSpec(spec);
|
|
88
|
-
|
|
110
|
+
const spinner = startSpinner(((("Fetching " + clr(C.bold, name)) + clr(C.gray, ("@" + version))) + " ..."));
|
|
89
111
|
try {
|
|
90
112
|
const info_ = await fetchJson(((REGISTRY_URL + "/") + name));
|
|
91
113
|
const resolvedVersion = ((version == "latest") ? (info_["dist-tags"]?.latest ?? "1.0.0") : version);
|
|
92
114
|
const versionInfo = info_.versions?.[resolvedVersion];
|
|
115
|
+
stopSpinner(spinner);
|
|
93
116
|
if (!versionInfo) {
|
|
94
117
|
err(((("Version " + resolvedVersion) + " not found for ") + name));
|
|
95
118
|
continue;
|
|
@@ -105,6 +128,7 @@ async function cmdAdd(specs, opts) {
|
|
|
105
128
|
info(("Added to " + (isDev ? "devDependencies" : "dependencies")));
|
|
106
129
|
}
|
|
107
130
|
catch (e) {
|
|
131
|
+
stopSpinner(spinner);
|
|
108
132
|
err(((("Failed to fetch " + name) + ": ") + e.message));
|
|
109
133
|
}
|
|
110
134
|
}
|
|
@@ -286,6 +310,88 @@ async function cmdInfo(name, opts) {
|
|
|
286
310
|
}
|
|
287
311
|
}
|
|
288
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;
|
|
289
395
|
function cmdPublish(opts) {
|
|
290
396
|
const cwd = process.cwd();
|
|
291
397
|
const pkg = readPackage(cwd);
|
package/src/self/test-runner.js
CHANGED
|
@@ -21,7 +21,7 @@ function repeat(s, n) { return String(s).repeat(n); }
|
|
|
21
21
|
const Fs = require("fs");
|
|
22
22
|
const Path = require("path");
|
|
23
23
|
const Os = require("os");
|
|
24
|
-
const C = { reset: "
|
|
24
|
+
const C = { reset: "\u001b[0m", bold: "\u001b[1m", red: "\u001b[31m", green: "\u001b[32m", yellow: "\u001b[33m", cyan: "\u001b[36m", gray: "\u001b[90m", dim: "\u001b[2m" };
|
|
25
25
|
function clr(c, s) {
|
|
26
26
|
return (process.env.NO_COLOR ? s : ((c + s) + C.reset));
|
|
27
27
|
}
|
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:
|