gofront 1.0.0 → 1.1.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/README.md +36 -3
- package/package.json +7 -7
- package/src/asset-manager.js +125 -0
- package/src/cli-core.js +74 -0
- package/src/codegen/expressions.js +3 -0
- package/src/codegen/statements.js +3 -0
- package/src/codegen/stdlib/builder.js +3 -0
- package/src/codegen/stdlib/bytes.js +3 -0
- package/src/codegen/stdlib/errors.js +3 -0
- package/src/codegen/stdlib/fmt.js +3 -0
- package/src/codegen/stdlib/gom.js +3 -0
- package/src/codegen/stdlib/html.js +3 -0
- package/src/codegen/stdlib/index.js +3 -0
- package/src/codegen/stdlib/io.js +3 -0
- package/src/codegen/stdlib/maps.js +3 -0
- package/src/codegen/stdlib/math.js +3 -0
- package/src/codegen/stdlib/os.js +3 -0
- package/src/codegen/stdlib/path.js +3 -0
- package/src/codegen/stdlib/rand.js +3 -0
- package/src/codegen/stdlib/regexp.js +3 -0
- package/src/codegen/stdlib/slices.js +3 -0
- package/src/codegen/stdlib/sort.js +3 -0
- package/src/codegen/stdlib/strconv.js +3 -0
- package/src/codegen/stdlib/strings.js +3 -0
- package/src/codegen/stdlib/time.js +3 -0
- package/src/codegen/stdlib/unicode.js +3 -0
- package/src/codegen/stdlib/utf8.js +3 -0
- package/src/codegen/templ.js +3 -0
- package/src/compiler.js +63 -4
- package/src/dev-server.js +96 -33
- package/src/index.js +80 -123
- package/src/parser/declarations.js +347 -0
- package/src/parser/index.js +3 -346
- package/src/typechecker/assignability.js +3 -0
- package/src/typechecker/expressions.js +9 -0
- package/src/typechecker/index.js +2 -1
- package/src/typechecker/resolve.js +9 -2
- package/src/typechecker/statements.js +3 -0
- package/src/typechecker/termination.js +3 -0
- package/src/typechecker/types.js +1 -0
- package/src/vendor.js +228 -0
package/src/compiler.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
//
|
|
1
|
+
// GoFront package compiler.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
3
|
+
// compileSingleFile(path, options) — compile one .go file
|
|
4
|
+
// compileDir(dir, options) — compile all *.go in a directory as one package
|
|
5
|
+
// compileFiles(files, options) — compile an explicit list of .go files
|
|
5
6
|
//
|
|
6
|
-
//
|
|
7
|
+
// compileSingleFile returns: { js } (or { tokens } / { ast } for debug modes)
|
|
8
|
+
// compileDir / compileFiles return:
|
|
7
9
|
// {
|
|
8
10
|
// pkgName: string,
|
|
9
11
|
// js: string, // generated JS bundle (may include dep preamble)
|
|
@@ -146,6 +148,63 @@ export function resolveImports(
|
|
|
146
148
|
|
|
147
149
|
// ── Main entry points ─────────────────────────────────────────
|
|
148
150
|
|
|
151
|
+
export function compileSingleFile(inputPath, options = {}) {
|
|
152
|
+
const {
|
|
153
|
+
sourceMap = false,
|
|
154
|
+
outputFile = null,
|
|
155
|
+
dumpTokens = false,
|
|
156
|
+
dumpAst = false,
|
|
157
|
+
} = options;
|
|
158
|
+
|
|
159
|
+
let source;
|
|
160
|
+
try {
|
|
161
|
+
source = readFileSync(inputPath, "utf8");
|
|
162
|
+
} catch (e) {
|
|
163
|
+
throw new Error(`cannot read '${inputPath}': ${e.message}`);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const tokens = new Lexer(source, basename(inputPath)).tokenize();
|
|
167
|
+
if (dumpTokens) return { tokens };
|
|
168
|
+
|
|
169
|
+
const ast = new Parser(tokens, basename(inputPath), source).parse();
|
|
170
|
+
ast._source = source;
|
|
171
|
+
if (dumpAst) return { ast };
|
|
172
|
+
|
|
173
|
+
const checker = new TypeChecker();
|
|
174
|
+
const jsImports = new Map();
|
|
175
|
+
const bundledPackages = new Set();
|
|
176
|
+
const preambles = [];
|
|
177
|
+
|
|
178
|
+
resolveImports(
|
|
179
|
+
[ast],
|
|
180
|
+
inputPath,
|
|
181
|
+
checker,
|
|
182
|
+
jsImports,
|
|
183
|
+
bundledPackages,
|
|
184
|
+
preambles,
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
const errors = checker.check(ast);
|
|
188
|
+
checker.reportUnusedImports();
|
|
189
|
+
if (errors.length > 0) {
|
|
190
|
+
throw new Error(errors.map((e) => e.message).join("\n"));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const cg = new CodeGen(checker, jsImports, bundledPackages);
|
|
194
|
+
let js = cg.generate(ast);
|
|
195
|
+
|
|
196
|
+
if (sourceMap) {
|
|
197
|
+
const outputDir = outputFile ? dirname(resolve(outputFile)) : resolve(".");
|
|
198
|
+
const srcPath = relative(outputDir, inputPath);
|
|
199
|
+
const map = cg.getSourceMap(srcPath, [source]);
|
|
200
|
+
const b64 = Buffer.from(map).toString("base64");
|
|
201
|
+
js += `\n//# sourceMappingURL=data:application/json;base64,${b64}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const output = preambles.length > 0 ? `${preambles.join("\n")}\n${js}` : js;
|
|
205
|
+
return { js: output };
|
|
206
|
+
}
|
|
207
|
+
|
|
149
208
|
export function compileDir(dir, options = {}) {
|
|
150
209
|
const files = gwFilesIn(dir);
|
|
151
210
|
if (files.length === 0) throw new Error(`No .go files found in ${dir}`);
|
package/src/dev-server.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// Minimal dev server for gofront --serve watch mode.
|
|
2
2
|
// Serves static files and pushes a reload event via SSE after each build.
|
|
3
3
|
|
|
4
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
4
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
5
5
|
import { createServer } from "node:http";
|
|
6
|
-
import { extname, join } from "node:path";
|
|
6
|
+
import { extname, join, resolve } from "node:path";
|
|
7
7
|
|
|
8
|
-
const MIME = {
|
|
8
|
+
export const MIME = {
|
|
9
9
|
".html": "text/html; charset=utf-8",
|
|
10
10
|
".js": "application/javascript; charset=utf-8",
|
|
11
11
|
".css": "text/css; charset=utf-8",
|
|
@@ -22,42 +22,97 @@ const MIME = {
|
|
|
22
22
|
// Injected at the bottom of compiled JS in serve mode.
|
|
23
23
|
export const liveReloadClient = `(function(){var es=new EventSource('/_gofront/events');es.addEventListener('reload',function(){location.reload();});})();`;
|
|
24
24
|
|
|
25
|
-
export function
|
|
26
|
-
|
|
25
|
+
export function handleDevRequest(req, res, serveDir, clients = new Set()) {
|
|
26
|
+
// SSE endpoint — browser connects here to receive reload events
|
|
27
|
+
if (req.url === "/_gofront/events") {
|
|
28
|
+
res.writeHead(200, {
|
|
29
|
+
"Content-Type": "text/event-stream",
|
|
30
|
+
"Cache-Control": "no-cache",
|
|
31
|
+
Connection: "keep-alive",
|
|
32
|
+
});
|
|
33
|
+
res.write(": connected\n\n");
|
|
34
|
+
clients.add(res);
|
|
35
|
+
req.on?.("close", () => clients.delete(res));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
27
38
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
res.write(": connected\n\n");
|
|
37
|
-
clients.add(res);
|
|
38
|
-
req.on("close", () => clients.delete(res));
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
39
|
+
let urlPath = req.url.split("?")[0].split("#")[0];
|
|
40
|
+
try {
|
|
41
|
+
urlPath = decodeURIComponent(urlPath);
|
|
42
|
+
} catch {
|
|
43
|
+
// Ignore malformed URL encoding and use raw path
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (urlPath === "/" || urlPath === "") urlPath = "/index.html";
|
|
41
47
|
|
|
42
|
-
|
|
43
|
-
|
|
48
|
+
const resolvedServe = resolve(serveDir);
|
|
49
|
+
const filePath = resolve(serveDir, `.${urlPath}`);
|
|
50
|
+
if (!filePath.startsWith(resolvedServe)) {
|
|
51
|
+
res.writeHead(403, { "Content-Type": "text/plain" });
|
|
52
|
+
res.end("Forbidden");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (!existsSync(filePath)) {
|
|
57
|
+
// SPA fallback: clean paths with no file extension fall back to index.html
|
|
58
|
+
const ext = extname(urlPath);
|
|
59
|
+
if (!ext) {
|
|
60
|
+
const indexPath = join(serveDir, "index.html");
|
|
61
|
+
if (existsSync(indexPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const data = readFileSync(indexPath);
|
|
64
|
+
res.writeHead(200, { "Content-Type": MIME[".html"] });
|
|
65
|
+
res.end(data);
|
|
66
|
+
return;
|
|
67
|
+
} catch {
|
|
68
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
69
|
+
res.end("Server error");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
75
|
+
res.end("Not found");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
44
78
|
|
|
45
|
-
|
|
46
|
-
|
|
79
|
+
try {
|
|
80
|
+
const stat = statSync(filePath);
|
|
81
|
+
if (stat.isDirectory()) {
|
|
82
|
+
const dirIndex = join(filePath, "index.html");
|
|
83
|
+
if (existsSync(dirIndex)) {
|
|
84
|
+
const data = readFileSync(dirIndex);
|
|
85
|
+
res.writeHead(200, { "Content-Type": MIME[".html"] });
|
|
86
|
+
res.end(data);
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const rootIndex = join(serveDir, "index.html");
|
|
90
|
+
if (existsSync(rootIndex)) {
|
|
91
|
+
const data = readFileSync(rootIndex);
|
|
92
|
+
res.writeHead(200, { "Content-Type": MIME[".html"] });
|
|
93
|
+
res.end(data);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
47
96
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
48
97
|
res.end("Not found");
|
|
49
98
|
return;
|
|
50
99
|
}
|
|
51
100
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
101
|
+
const data = readFileSync(filePath);
|
|
102
|
+
const mime = MIME[extname(filePath)] ?? "application/octet-stream";
|
|
103
|
+
res.writeHead(200, { "Content-Type": mime });
|
|
104
|
+
res.end(data);
|
|
105
|
+
} catch {
|
|
106
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
107
|
+
res.end("Server error");
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function createDevServer(serveDir, port = 3000) {
|
|
112
|
+
const clients = new Set();
|
|
113
|
+
|
|
114
|
+
const server = createServer((req, res) => {
|
|
115
|
+
handleDevRequest(req, res, serveDir, clients);
|
|
61
116
|
});
|
|
62
117
|
|
|
63
118
|
server.on("error", (err) => {
|
|
@@ -70,8 +125,12 @@ export function createDevServer(serveDir, port) {
|
|
|
70
125
|
}
|
|
71
126
|
process.exit(1);
|
|
72
127
|
});
|
|
128
|
+
|
|
73
129
|
server.listen(port, () => {
|
|
74
|
-
|
|
130
|
+
const actualPort = server.address()?.port ?? port;
|
|
131
|
+
if (port !== 0) {
|
|
132
|
+
console.error(`gofront: dev server → http://localhost:${actualPort}`);
|
|
133
|
+
}
|
|
75
134
|
});
|
|
76
135
|
|
|
77
136
|
function notify() {
|
|
@@ -80,5 +139,9 @@ export function createDevServer(serveDir, port) {
|
|
|
80
139
|
}
|
|
81
140
|
}
|
|
82
141
|
|
|
83
|
-
return {
|
|
142
|
+
return {
|
|
143
|
+
notify,
|
|
144
|
+
server,
|
|
145
|
+
close: () => new Promise((res) => server.close(res)),
|
|
146
|
+
};
|
|
84
147
|
}
|
package/src/index.js
CHANGED
|
@@ -13,27 +13,16 @@
|
|
|
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 { mkdirSync, statSync, watch, writeFileSync } from "node:fs";
|
|
22
|
+
import { dirname, resolve } from "node:path";
|
|
23
|
+
import { copyAssets } from "./asset-manager.js";
|
|
24
|
+
import { handleInit, handlePrep, maybeMinify, runCompile } from "./cli-core.js";
|
|
32
25
|
import { createDevServer, liveReloadClient } from "./dev-server.js";
|
|
33
|
-
import { Lexer } from "./lexer.js";
|
|
34
|
-
import { minify } from "./minifier.js";
|
|
35
|
-
import { Parser } from "./parser/index.js";
|
|
36
|
-
import { TypeChecker } from "./typechecker/index.js";
|
|
37
26
|
|
|
38
27
|
// ── Parse CLI args ───────────────────────────────────────────
|
|
39
28
|
|
|
@@ -56,11 +45,13 @@ Usage:
|
|
|
56
45
|
gofront <input> --watch Watch for changes and recompile
|
|
57
46
|
gofront <input> -o out.js --serve Watch + serve with live reload (default port 3000)
|
|
58
47
|
gofront <input> -o out.js --serve --port 8080 Use a custom port
|
|
48
|
+
gofront <input> -o out.js --copy-assets Compile and synchronize static assets
|
|
59
49
|
gofront <input> --source-map Append inline source map to output
|
|
60
50
|
gofront <input> --minify Minify output
|
|
61
51
|
gofront <input> --minify --mangle Minify and mangle identifiers
|
|
62
52
|
gofront <file.go> --ast Dump AST (debug)
|
|
63
53
|
gofront <file.go> --tokens Dump tokens (debug)
|
|
54
|
+
gofront prep [dir] Copy static assets and bundle vendor dependencies
|
|
64
55
|
gofront init [dir] Scaffold a new GoFront project
|
|
65
56
|
gofront --version Print version
|
|
66
57
|
`.trim(),
|
|
@@ -68,45 +59,42 @@ Usage:
|
|
|
68
59
|
process.exit(0);
|
|
69
60
|
}
|
|
70
61
|
|
|
71
|
-
// ──
|
|
62
|
+
// ── prep / vendor subcommand ──────────────────────────────────
|
|
72
63
|
|
|
73
|
-
if (args[0] === "
|
|
64
|
+
if (args[0] === "prep" || args[0] === "vendor") {
|
|
74
65
|
const targetArg = args[1] ?? ".";
|
|
75
66
|
const targetDir = resolve(targetArg);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
process.exit(1);
|
|
67
|
+
try {
|
|
68
|
+
const { assets, vendor } = await handlePrep(targetDir);
|
|
69
|
+
if (assets.copied > 0 || assets.skipped > 0) {
|
|
70
|
+
console.error(
|
|
71
|
+
`gofront: copied ${assets.copied} assets (${assets.skipped} skipped)`,
|
|
72
|
+
);
|
|
83
73
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
74
|
+
if (vendor.bundled?.length > 0) {
|
|
75
|
+
console.error(
|
|
76
|
+
`gofront: bundled ${vendor.bundled.length} vendor dependencies → ${vendor.dest}`,
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
} catch (e) {
|
|
80
|
+
console.error(`gofront: ${e.message}`);
|
|
89
81
|
process.exit(1);
|
|
90
82
|
}
|
|
83
|
+
process.exit(0);
|
|
84
|
+
}
|
|
91
85
|
|
|
92
|
-
|
|
93
|
-
targetArg === "." ? basename(resolve(".")) : basename(targetDir);
|
|
94
|
-
// package names must be valid identifiers
|
|
95
|
-
const safePkg = pkgName.replace(/[^a-zA-Z0-9_]/g, "_").replace(/^[0-9]/, "_");
|
|
96
|
-
|
|
97
|
-
const template = `package ${safePkg}
|
|
86
|
+
// ── init subcommand ──────────────────────────────────────────
|
|
98
87
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
88
|
+
if (args[0] === "init") {
|
|
89
|
+
const targetArg = args[1] ?? ".";
|
|
90
|
+
const targetDir = resolve(targetArg);
|
|
91
|
+
let mainPath;
|
|
103
92
|
try {
|
|
104
|
-
|
|
93
|
+
({ mainPath } = handleInit(targetDir));
|
|
105
94
|
} catch (e) {
|
|
106
|
-
console.error(`gofront:
|
|
95
|
+
console.error(`gofront: ${e.message}`);
|
|
107
96
|
process.exit(1);
|
|
108
97
|
}
|
|
109
|
-
|
|
110
98
|
console.error(`gofront: created ${mainPath}`);
|
|
111
99
|
console.error(
|
|
112
100
|
`gofront: run gofront ${targetArg === "." ? "main.go" : `${targetArg}/main.go`} to compile`,
|
|
@@ -123,6 +111,7 @@ const dumpTokens = args.includes("--tokens");
|
|
|
123
111
|
const sourceMap = args.includes("--source-map");
|
|
124
112
|
const serveMode = args.includes("--serve");
|
|
125
113
|
const watchMode = args.includes("--watch") || serveMode;
|
|
114
|
+
const copyAssetsFlag = args.includes("--copy-assets");
|
|
126
115
|
const minifyOutput = args.includes("--minify");
|
|
127
116
|
const mangleOutput = args.includes("--mangle");
|
|
128
117
|
const portFlag = args.indexOf("--port");
|
|
@@ -139,95 +128,32 @@ try {
|
|
|
139
128
|
process.exit(1);
|
|
140
129
|
}
|
|
141
130
|
|
|
142
|
-
// ── Compile function (used for initial build and re-builds) ──
|
|
143
|
-
|
|
144
|
-
function runCompile() {
|
|
145
|
-
if (isDir) {
|
|
146
|
-
const outputDir = outputFile ? dirname(resolve(outputFile)) : resolve(".");
|
|
147
|
-
return compileDir(inputPath, { sourceMap, outputDir });
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Single-file mode
|
|
151
|
-
let source;
|
|
152
|
-
try {
|
|
153
|
-
source = readFileSync(inputPath, "utf8");
|
|
154
|
-
} catch (e) {
|
|
155
|
-
throw new Error(`cannot read '${inputArg}': ${e.message}`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
const tokens = new Lexer(source, basename(inputPath)).tokenize();
|
|
159
|
-
|
|
160
|
-
if (dumpTokens) {
|
|
161
|
-
for (const tok of tokens) console.log(tok.toString());
|
|
162
|
-
process.exit(0);
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const ast = new Parser(tokens, basename(inputPath), source).parse();
|
|
166
|
-
ast._source = source;
|
|
167
|
-
|
|
168
|
-
if (dumpAst) {
|
|
169
|
-
console.log(JSON.stringify(ast, null, 2));
|
|
170
|
-
process.exit(0);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const checker = new TypeChecker();
|
|
174
|
-
const jsImports = new Map();
|
|
175
|
-
const bundledPackages = new Set();
|
|
176
|
-
const preambles = [];
|
|
177
|
-
|
|
178
|
-
resolveImports(
|
|
179
|
-
[ast],
|
|
180
|
-
inputPath,
|
|
181
|
-
checker,
|
|
182
|
-
jsImports,
|
|
183
|
-
bundledPackages,
|
|
184
|
-
preambles,
|
|
185
|
-
);
|
|
186
|
-
|
|
187
|
-
const errors = checker.check(ast);
|
|
188
|
-
checker.reportUnusedImports();
|
|
189
|
-
if (errors.length > 0) {
|
|
190
|
-
throw new Error(errors.map((e) => e.message).join("\n"));
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
const cg = new CodeGen(checker, jsImports, bundledPackages);
|
|
194
|
-
let js = cg.generate(ast);
|
|
195
|
-
|
|
196
|
-
if (sourceMap) {
|
|
197
|
-
const outputDir = outputFile ? dirname(resolve(outputFile)) : resolve(".");
|
|
198
|
-
const srcPath = relative(outputDir, inputPath);
|
|
199
|
-
const map = cg.getSourceMap(srcPath, [source]);
|
|
200
|
-
const b64 = Buffer.from(map).toString("base64");
|
|
201
|
-
js += `\n//# sourceMappingURL=data:application/json;base64,${b64}`;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
const output = preambles.length > 0 ? `${preambles.join("\n")}\n${js}` : js;
|
|
205
|
-
return { js: output };
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// ── Minify helper ────────────────────────────────────────────
|
|
209
|
-
|
|
210
|
-
function maybeMinify(js) {
|
|
211
|
-
if (!minifyOutput) return js;
|
|
212
|
-
if (sourceMap) {
|
|
213
|
-
console.error("gofront: --source-map and --minify cannot be used together");
|
|
214
|
-
process.exit(1);
|
|
215
|
-
}
|
|
216
|
-
return minify(js, { mangle: mangleOutput });
|
|
217
|
-
}
|
|
218
|
-
|
|
219
131
|
// ── Single-shot mode ─────────────────────────────────────────
|
|
220
132
|
|
|
221
133
|
if (!watchMode) {
|
|
222
134
|
let result;
|
|
223
135
|
const startMs = performance.now();
|
|
224
136
|
try {
|
|
225
|
-
result = runCompile(
|
|
137
|
+
result = runCompile(inputPath, isDir, {
|
|
138
|
+
sourceMap,
|
|
139
|
+
outputFile,
|
|
140
|
+
dumpTokens,
|
|
141
|
+
dumpAst,
|
|
142
|
+
});
|
|
226
143
|
} catch (e) {
|
|
227
144
|
console.error(`gofront: ${e.message}`);
|
|
228
145
|
process.exit(1);
|
|
229
146
|
}
|
|
230
147
|
|
|
148
|
+
if (result.tokens) {
|
|
149
|
+
for (const tok of result.tokens) console.log(tok.toString());
|
|
150
|
+
process.exit(0);
|
|
151
|
+
}
|
|
152
|
+
if (result.ast) {
|
|
153
|
+
console.log(JSON.stringify(result.ast, null, 2));
|
|
154
|
+
process.exit(0);
|
|
155
|
+
}
|
|
156
|
+
|
|
231
157
|
if (checkOnly) {
|
|
232
158
|
const elapsedMs = (performance.now() - startMs).toFixed(0);
|
|
233
159
|
console.error(`gofront: ${inputArg} — OK (${elapsedMs}ms)`);
|
|
@@ -236,7 +162,11 @@ if (!watchMode) {
|
|
|
236
162
|
|
|
237
163
|
let js;
|
|
238
164
|
try {
|
|
239
|
-
js = maybeMinify(result.js
|
|
165
|
+
js = maybeMinify(result.js, {
|
|
166
|
+
minify: minifyOutput,
|
|
167
|
+
mangle: mangleOutput,
|
|
168
|
+
sourceMap,
|
|
169
|
+
});
|
|
240
170
|
} catch (e) {
|
|
241
171
|
console.error(`gofront: minify failed: ${e.message}`);
|
|
242
172
|
process.exit(1);
|
|
@@ -246,6 +176,7 @@ if (!watchMode) {
|
|
|
246
176
|
|
|
247
177
|
if (outputFile) {
|
|
248
178
|
try {
|
|
179
|
+
mkdirSync(dirname(resolve(outputFile)), { recursive: true });
|
|
249
180
|
writeFileSync(outputFile, `${js}\n`);
|
|
250
181
|
console.error(`gofront: wrote ${outputFile} (${elapsedMs}ms)`);
|
|
251
182
|
} catch (e) {
|
|
@@ -255,6 +186,19 @@ if (!watchMode) {
|
|
|
255
186
|
} else {
|
|
256
187
|
console.log(js);
|
|
257
188
|
}
|
|
189
|
+
|
|
190
|
+
if (copyAssetsFlag) {
|
|
191
|
+
try {
|
|
192
|
+
const projectDir = resolve(".");
|
|
193
|
+
const { copied, skipped } = copyAssets(projectDir);
|
|
194
|
+
if (copied > 0 || skipped > 0) {
|
|
195
|
+
console.error(`gofront: copied ${copied} assets (${skipped} skipped)`);
|
|
196
|
+
}
|
|
197
|
+
} catch (e) {
|
|
198
|
+
console.error(`gofront: asset copy failed: ${e.message}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
258
202
|
process.exit(0);
|
|
259
203
|
}
|
|
260
204
|
|
|
@@ -278,8 +222,12 @@ if (serveMode) {
|
|
|
278
222
|
function buildOnce(changedFile = null) {
|
|
279
223
|
try {
|
|
280
224
|
const startMs = performance.now();
|
|
281
|
-
const result = runCompile();
|
|
282
|
-
let js = maybeMinify(result.js
|
|
225
|
+
const result = runCompile(inputPath, isDir, { sourceMap, outputFile });
|
|
226
|
+
let js = maybeMinify(result.js, {
|
|
227
|
+
minify: minifyOutput,
|
|
228
|
+
mangle: mangleOutput,
|
|
229
|
+
sourceMap,
|
|
230
|
+
});
|
|
283
231
|
if (serveMode) {
|
|
284
232
|
// Insert live reload client before the source map comment so it stays last
|
|
285
233
|
const smIdx = js.lastIndexOf("\n//# sourceMappingURL=");
|
|
@@ -304,6 +252,15 @@ function buildOnce(changedFile = null) {
|
|
|
304
252
|
`[${timestamp()}] gofront: OK (${elapsedMs}ms${changeNote})`,
|
|
305
253
|
);
|
|
306
254
|
}
|
|
255
|
+
|
|
256
|
+
if (copyAssetsFlag) {
|
|
257
|
+
try {
|
|
258
|
+
copyAssets(resolve("."));
|
|
259
|
+
} catch (e) {
|
|
260
|
+
console.error(`gofront: asset copy failed: ${e.message}`);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
307
264
|
devServer?.notify();
|
|
308
265
|
} catch (e) {
|
|
309
266
|
console.error(`[${timestamp()}] gofront: ERROR`);
|