gofront 0.0.9 → 1.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/README.md +5 -5
- package/package.json +7 -4
- package/src/cli-core.js +65 -0
- package/src/codegen/expressions.js +523 -1717
- package/src/codegen/index.js +576 -0
- package/src/codegen/runtime.js +151 -0
- package/src/codegen/statements.js +308 -296
- package/src/codegen/stdlib/builder.js +39 -0
- package/src/codegen/stdlib/bytes.js +65 -0
- package/src/codegen/stdlib/errors.js +20 -0
- package/src/codegen/stdlib/fmt.js +104 -0
- package/src/codegen/stdlib/gom.js +155 -0
- package/src/codegen/stdlib/html.js +20 -0
- package/src/codegen/stdlib/index.js +98 -0
- package/src/codegen/stdlib/io.js +36 -0
- package/src/codegen/stdlib/maps.js +45 -0
- package/src/codegen/stdlib/math.js +56 -0
- package/src/codegen/stdlib/os.js +13 -0
- package/src/codegen/stdlib/path.js +34 -0
- package/src/codegen/stdlib/rand.js +27 -0
- package/src/codegen/stdlib/regexp.js +54 -0
- package/src/codegen/stdlib/slices.js +51 -0
- package/src/codegen/stdlib/sort.js +31 -0
- package/src/codegen/stdlib/strconv.js +33 -0
- package/src/codegen/stdlib/strings.js +86 -0
- package/src/codegen/stdlib/time.js +57 -0
- package/src/codegen/stdlib/unicode.js +25 -0
- package/src/codegen/stdlib/utf8.js +26 -0
- package/src/codegen/templ.js +284 -0
- package/src/compiler.js +142 -77
- package/src/dts-parser.js +355 -371
- package/src/index.js +32 -162
- package/src/lexer.js +186 -272
- package/src/minifier.js +305 -318
- package/src/{parser.js → parser/declarations.js} +18 -175
- package/src/parser/expressions.js +51 -34
- package/src/parser/index.js +161 -0
- package/src/parser/statements.js +24 -34
- package/src/parser/types.js +31 -29
- package/src/templ-parser.js +2 -2
- package/src/tokens.js +109 -0
- package/src/typechecker/assignability.js +261 -0
- package/src/typechecker/expressions.js +568 -549
- package/src/typechecker/index.js +556 -0
- package/src/typechecker/resolve.js +428 -0
- package/src/typechecker/statements.js +270 -280
- package/src/typechecker/stdlib/core.js +592 -0
- package/src/typechecker/stdlib/extended.js +332 -0
- package/src/typechecker/stdlib.js +9 -1060
- package/src/typechecker/termination.js +86 -0
- package/src/typechecker/types.js +1 -0
- package/src/codegen.js +0 -882
- package/src/typechecker.js +0 -1299
package/src/index.js
CHANGED
|
@@ -13,29 +13,15 @@
|
|
|
13
13
|
// gofront <file.go> --tokens — dump tokens of first file (debug)
|
|
14
14
|
// gofront init [dir] — scaffold a new GoFront project
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
existsSync,
|
|
18
|
-
mkdirSync,
|
|
19
|
-
readFileSync,
|
|
20
|
-
statSync,
|
|
21
|
-
watch,
|
|
22
|
-
writeFileSync,
|
|
23
|
-
} from "node:fs";
|
|
24
16
|
import { createRequire } from "node:module";
|
|
25
17
|
|
|
26
18
|
const _require = createRequire(import.meta.url);
|
|
27
19
|
const { version } = _require("../package.json");
|
|
28
20
|
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
21
|
+
import { statSync, watch, writeFileSync } from "node:fs";
|
|
22
|
+
import { dirname, resolve } from "node:path";
|
|
23
|
+
import { handleInit, maybeMinify, runCompile } from "./cli-core.js";
|
|
32
24
|
import { createDevServer, liveReloadClient } from "./dev-server.js";
|
|
33
|
-
import { parseDts } from "./dts-parser.js";
|
|
34
|
-
import { Lexer } from "./lexer.js";
|
|
35
|
-
import { minify } from "./minifier.js";
|
|
36
|
-
import { Parser } from "./parser.js";
|
|
37
|
-
import { isLocalPath, resolveAll, resolveGwDir } from "./resolver.js";
|
|
38
|
-
import { TypeChecker } from "./typechecker.js";
|
|
39
25
|
|
|
40
26
|
// ── Parse CLI args ───────────────────────────────────────────
|
|
41
27
|
|
|
@@ -75,40 +61,13 @@ Usage:
|
|
|
75
61
|
if (args[0] === "init") {
|
|
76
62
|
const targetArg = args[1] ?? ".";
|
|
77
63
|
const targetDir = resolve(targetArg);
|
|
78
|
-
|
|
79
|
-
if (targetArg !== ".") {
|
|
80
|
-
try {
|
|
81
|
-
mkdirSync(targetDir, { recursive: true });
|
|
82
|
-
} catch (e) {
|
|
83
|
-
console.error(`gofront: cannot create '${targetArg}': ${e.message}`);
|
|
84
|
-
process.exit(1);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
const mainPath = join(targetDir, "main.go");
|
|
89
|
-
if (existsSync(mainPath)) {
|
|
90
|
-
console.error(`gofront: ${mainPath} already exists — nothing written`);
|
|
91
|
-
process.exit(1);
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const pkgName =
|
|
95
|
-
targetArg === "." ? basename(resolve(".")) : basename(targetDir);
|
|
96
|
-
// package names must be valid identifiers
|
|
97
|
-
const safePkg = pkgName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^[0-9]/, "_");
|
|
98
|
-
|
|
99
|
-
const template = `package ${safePkg}
|
|
100
|
-
|
|
101
|
-
func main() {
|
|
102
|
-
\tconsole.log("Hello from GoFront!")
|
|
103
|
-
}
|
|
104
|
-
`;
|
|
64
|
+
let mainPath;
|
|
105
65
|
try {
|
|
106
|
-
|
|
66
|
+
({ mainPath } = handleInit(targetDir));
|
|
107
67
|
} catch (e) {
|
|
108
|
-
console.error(`gofront:
|
|
68
|
+
console.error(`gofront: ${e.message}`);
|
|
109
69
|
process.exit(1);
|
|
110
70
|
}
|
|
111
|
-
|
|
112
71
|
console.error(`gofront: created ${mainPath}`);
|
|
113
72
|
console.error(
|
|
114
73
|
`gofront: run gofront ${targetArg === "." ? "main.go" : `${targetArg}/main.go`} to compile`,
|
|
@@ -141,129 +100,32 @@ try {
|
|
|
141
100
|
process.exit(1);
|
|
142
101
|
}
|
|
143
102
|
|
|
144
|
-
// ── Compile function (used for initial build and re-builds) ──
|
|
145
|
-
|
|
146
|
-
function runCompile() {
|
|
147
|
-
if (isDir) {
|
|
148
|
-
const outputDir = outputFile ? dirname(resolve(outputFile)) : resolve(".");
|
|
149
|
-
return compileDir(inputPath, { sourceMap, outputDir });
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Single-file mode
|
|
153
|
-
let source;
|
|
154
|
-
try {
|
|
155
|
-
source = readFileSync(inputPath, "utf8");
|
|
156
|
-
} catch (e) {
|
|
157
|
-
throw new Error(`cannot read '${inputArg}': ${e.message}`);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const tokens = new Lexer(source, basename(inputPath)).tokenize();
|
|
161
|
-
|
|
162
|
-
if (dumpTokens) {
|
|
163
|
-
for (const tok of tokens) console.log(tok.toString());
|
|
164
|
-
process.exit(0);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
const ast = new Parser(tokens, basename(inputPath), source).parse();
|
|
168
|
-
ast._source = source;
|
|
169
|
-
|
|
170
|
-
if (dumpAst) {
|
|
171
|
-
console.log(JSON.stringify(ast, null, 2));
|
|
172
|
-
process.exit(0);
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
const checker = new TypeChecker();
|
|
176
|
-
const fromDir = dirname(inputPath);
|
|
177
|
-
const jsImports = new Map();
|
|
178
|
-
|
|
179
|
-
for (const imp of ast.imports) {
|
|
180
|
-
for (const { path } of imp.imports) {
|
|
181
|
-
if (!path.startsWith("js:")) continue;
|
|
182
|
-
const dtsPath = join(fromDir, path.slice(3));
|
|
183
|
-
try {
|
|
184
|
-
const { types, values } = parseDts(readFileSync(dtsPath, "utf8"));
|
|
185
|
-
checker.addDefinitions(types, values);
|
|
186
|
-
} catch (e) {
|
|
187
|
-
throw new Error(`cannot read '${dtsPath}': ${e.message}`);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
const resolved = resolveAll(ast.imports, inputPath, parseDts);
|
|
193
|
-
for (const [path, info] of resolved) {
|
|
194
|
-
if (!info) continue;
|
|
195
|
-
checker.addDefinitions(info.types, info.values);
|
|
196
|
-
jsImports.set(path, [...info.values.keys()]);
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const bundledPackages = new Set();
|
|
200
|
-
const preambles = [];
|
|
201
|
-
|
|
202
|
-
for (const imp of ast.imports) {
|
|
203
|
-
for (const { path, alias } of imp.imports) {
|
|
204
|
-
if (!isLocalPath(path)) continue;
|
|
205
|
-
const depDir = resolveGwDir(path, inputPath);
|
|
206
|
-
if (!depDir) {
|
|
207
|
-
console.error(
|
|
208
|
-
`gofront: warning: cannot find local package '${path}' relative to ${fromDir}`,
|
|
209
|
-
);
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
const dep = compileDir(depDir);
|
|
213
|
-
preambles.push(dep.js);
|
|
214
|
-
const nameUsed = alias ?? dep.pkgName;
|
|
215
|
-
bundledPackages.add(nameUsed);
|
|
216
|
-
checker.addPackageNamespace(
|
|
217
|
-
nameUsed,
|
|
218
|
-
dep.exportedSymbols,
|
|
219
|
-
dep.exportedTypes,
|
|
220
|
-
);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
const errors = checker.check(ast);
|
|
225
|
-
if (errors.length > 0) {
|
|
226
|
-
throw new Error(errors.map((e) => e.message).join("\n"));
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const cg = new CodeGen(checker, jsImports, bundledPackages);
|
|
230
|
-
let js = cg.generate(ast);
|
|
231
|
-
|
|
232
|
-
if (sourceMap) {
|
|
233
|
-
const outputDir = outputFile ? dirname(resolve(outputFile)) : resolve(".");
|
|
234
|
-
const srcPath = relative(outputDir, inputPath);
|
|
235
|
-
const map = cg.getSourceMap(srcPath, [source]);
|
|
236
|
-
const b64 = Buffer.from(map).toString("base64");
|
|
237
|
-
js += `\n//# sourceMappingURL=data:application/json;base64,${b64}`;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
const output = preambles.length > 0 ? `${preambles.join("\n")}\n${js}` : js;
|
|
241
|
-
return { js: output };
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// ── Minify helper ────────────────────────────────────────────
|
|
245
|
-
|
|
246
|
-
function maybeMinify(js) {
|
|
247
|
-
if (!minifyOutput) return js;
|
|
248
|
-
if (sourceMap) {
|
|
249
|
-
console.error("gofront: --source-map and --minify cannot be used together");
|
|
250
|
-
process.exit(1);
|
|
251
|
-
}
|
|
252
|
-
return minify(js, { mangle: mangleOutput });
|
|
253
|
-
}
|
|
254
|
-
|
|
255
103
|
// ── Single-shot mode ─────────────────────────────────────────
|
|
256
104
|
|
|
257
105
|
if (!watchMode) {
|
|
258
106
|
let result;
|
|
259
107
|
const startMs = performance.now();
|
|
260
108
|
try {
|
|
261
|
-
result = runCompile(
|
|
109
|
+
result = runCompile(inputPath, isDir, {
|
|
110
|
+
sourceMap,
|
|
111
|
+
outputFile,
|
|
112
|
+
dumpTokens,
|
|
113
|
+
dumpAst,
|
|
114
|
+
});
|
|
262
115
|
} catch (e) {
|
|
263
116
|
console.error(`gofront: ${e.message}`);
|
|
264
117
|
process.exit(1);
|
|
265
118
|
}
|
|
266
119
|
|
|
120
|
+
if (result.tokens) {
|
|
121
|
+
for (const tok of result.tokens) console.log(tok.toString());
|
|
122
|
+
process.exit(0);
|
|
123
|
+
}
|
|
124
|
+
if (result.ast) {
|
|
125
|
+
console.log(JSON.stringify(result.ast, null, 2));
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
267
129
|
if (checkOnly) {
|
|
268
130
|
const elapsedMs = (performance.now() - startMs).toFixed(0);
|
|
269
131
|
console.error(`gofront: ${inputArg} — OK (${elapsedMs}ms)`);
|
|
@@ -272,7 +134,11 @@ if (!watchMode) {
|
|
|
272
134
|
|
|
273
135
|
let js;
|
|
274
136
|
try {
|
|
275
|
-
js = maybeMinify(result.js
|
|
137
|
+
js = maybeMinify(result.js, {
|
|
138
|
+
minify: minifyOutput,
|
|
139
|
+
mangle: mangleOutput,
|
|
140
|
+
sourceMap,
|
|
141
|
+
});
|
|
276
142
|
} catch (e) {
|
|
277
143
|
console.error(`gofront: minify failed: ${e.message}`);
|
|
278
144
|
process.exit(1);
|
|
@@ -314,8 +180,12 @@ if (serveMode) {
|
|
|
314
180
|
function buildOnce(changedFile = null) {
|
|
315
181
|
try {
|
|
316
182
|
const startMs = performance.now();
|
|
317
|
-
const result = runCompile();
|
|
318
|
-
let js = maybeMinify(result.js
|
|
183
|
+
const result = runCompile(inputPath, isDir, { sourceMap, outputFile });
|
|
184
|
+
let js = maybeMinify(result.js, {
|
|
185
|
+
minify: minifyOutput,
|
|
186
|
+
mangle: mangleOutput,
|
|
187
|
+
sourceMap,
|
|
188
|
+
});
|
|
319
189
|
if (serveMode) {
|
|
320
190
|
// Insert live reload client before the source map comment so it stays last
|
|
321
191
|
const smIdx = js.lastIndexOf("\n//# sourceMappingURL=");
|