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.
Files changed (53) hide show
  1. package/README.md +5 -5
  2. package/package.json +7 -4
  3. package/src/cli-core.js +65 -0
  4. package/src/codegen/expressions.js +523 -1717
  5. package/src/codegen/index.js +576 -0
  6. package/src/codegen/runtime.js +151 -0
  7. package/src/codegen/statements.js +308 -296
  8. package/src/codegen/stdlib/builder.js +39 -0
  9. package/src/codegen/stdlib/bytes.js +65 -0
  10. package/src/codegen/stdlib/errors.js +20 -0
  11. package/src/codegen/stdlib/fmt.js +104 -0
  12. package/src/codegen/stdlib/gom.js +155 -0
  13. package/src/codegen/stdlib/html.js +20 -0
  14. package/src/codegen/stdlib/index.js +98 -0
  15. package/src/codegen/stdlib/io.js +36 -0
  16. package/src/codegen/stdlib/maps.js +45 -0
  17. package/src/codegen/stdlib/math.js +56 -0
  18. package/src/codegen/stdlib/os.js +13 -0
  19. package/src/codegen/stdlib/path.js +34 -0
  20. package/src/codegen/stdlib/rand.js +27 -0
  21. package/src/codegen/stdlib/regexp.js +54 -0
  22. package/src/codegen/stdlib/slices.js +51 -0
  23. package/src/codegen/stdlib/sort.js +31 -0
  24. package/src/codegen/stdlib/strconv.js +33 -0
  25. package/src/codegen/stdlib/strings.js +86 -0
  26. package/src/codegen/stdlib/time.js +57 -0
  27. package/src/codegen/stdlib/unicode.js +25 -0
  28. package/src/codegen/stdlib/utf8.js +26 -0
  29. package/src/codegen/templ.js +284 -0
  30. package/src/compiler.js +142 -77
  31. package/src/dts-parser.js +355 -371
  32. package/src/index.js +32 -162
  33. package/src/lexer.js +186 -272
  34. package/src/minifier.js +305 -318
  35. package/src/{parser.js → parser/declarations.js} +18 -175
  36. package/src/parser/expressions.js +51 -34
  37. package/src/parser/index.js +161 -0
  38. package/src/parser/statements.js +24 -34
  39. package/src/parser/types.js +31 -29
  40. package/src/templ-parser.js +2 -2
  41. package/src/tokens.js +109 -0
  42. package/src/typechecker/assignability.js +261 -0
  43. package/src/typechecker/expressions.js +568 -549
  44. package/src/typechecker/index.js +556 -0
  45. package/src/typechecker/resolve.js +428 -0
  46. package/src/typechecker/statements.js +270 -280
  47. package/src/typechecker/stdlib/core.js +592 -0
  48. package/src/typechecker/stdlib/extended.js +332 -0
  49. package/src/typechecker/stdlib.js +9 -1060
  50. package/src/typechecker/termination.js +86 -0
  51. package/src/typechecker/types.js +1 -0
  52. package/src/codegen.js +0 -882
  53. 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 { basename, dirname, join, relative, resolve } from "node:path";
30
- import { CodeGen } from "./codegen.js";
31
- import { compileDir } from "./compiler.js";
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
- writeFileSync(mainPath, template);
66
+ ({ mainPath } = handleInit(targetDir));
107
67
  } catch (e) {
108
- console.error(`gofront: cannot write '${mainPath}': ${e.message}`);
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=");