bimba-cli 0.7.19 → 0.7.20
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/index.js +5 -2
- package/package.json +1 -1
- package/plugin.js +214 -162
- package/serve.js +110 -26
package/index.js
CHANGED
|
@@ -168,6 +168,7 @@ async function bundle() {
|
|
|
168
168
|
stats.failed = 0
|
|
169
169
|
stats.compiled = 0
|
|
170
170
|
stats.errors = 0
|
|
171
|
+
stats.reported = 0
|
|
171
172
|
stats.bundled = 0
|
|
172
173
|
|
|
173
174
|
const start = Date.now();
|
|
@@ -208,8 +209,10 @@ async function bundle() {
|
|
|
208
209
|
}
|
|
209
210
|
}
|
|
210
211
|
|
|
211
|
-
if(stats.failed)
|
|
212
|
-
|
|
212
|
+
if(stats.failed) {
|
|
213
|
+
if (stats.reported)
|
|
214
|
+
console.log(theme.start(theme.failure(" Failure ") + theme.filename(` Imba compiler failed to proceed ${stats.failed} file${stats.failed > 1 ? 's' : ''}`)));
|
|
215
|
+
}
|
|
213
216
|
else
|
|
214
217
|
console.log(theme.start(theme.success("Success") +` It took ${theme.time(Date.now() - start)} ms to bundle ${theme.count(stats.bundled)} file${stats.bundled > 1 ? 's' : ''} to the folder: ${theme.filedir(flags.outdir)}`));
|
|
215
218
|
|
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -1,162 +1,214 @@
|
|
|
1
|
-
import { plugin } from "bun";
|
|
2
|
-
import {theme} from './utils.js';
|
|
3
|
-
import * as compiler from 'imba/compiler'
|
|
4
|
-
import dir from 'path'
|
|
5
|
-
import fs from 'fs'
|
|
6
|
-
import { Glob } from "bun";
|
|
7
|
-
import { unlink } from "node:fs/promises";
|
|
8
|
-
|
|
9
|
-
export const cache = dir.join(process.cwd(), '.cache')
|
|
10
|
-
if (!fs.existsSync(cache)){ fs.mkdirSync(cache);}
|
|
11
|
-
|
|
12
|
-
// this should be reset from outside to get results of entrypoint building
|
|
13
|
-
export let stats = {
|
|
14
|
-
failed: 0,
|
|
15
|
-
compiled: 0,
|
|
16
|
-
cached: 0,
|
|
17
|
-
bundled: 0,
|
|
18
|
-
errors: 0,
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
//
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
}
|
|
1
|
+
import { plugin } from "bun";
|
|
2
|
+
import {theme} from './utils.js';
|
|
3
|
+
import * as compiler from 'imba/compiler'
|
|
4
|
+
import dir from 'path'
|
|
5
|
+
import fs from 'fs'
|
|
6
|
+
import { Glob } from "bun";
|
|
7
|
+
import { unlink } from "node:fs/promises";
|
|
8
|
+
|
|
9
|
+
export const cache = dir.join(process.cwd(), '.cache')
|
|
10
|
+
if (!fs.existsSync(cache)){ fs.mkdirSync(cache);}
|
|
11
|
+
|
|
12
|
+
// this should be reset from outside to get results of entrypoint building
|
|
13
|
+
export let stats = {
|
|
14
|
+
failed: 0,
|
|
15
|
+
compiled: 0,
|
|
16
|
+
cached: 0,
|
|
17
|
+
bundled: 0,
|
|
18
|
+
errors: 0,
|
|
19
|
+
reported: 0,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
const _activeCompileErrors = new Map();
|
|
23
|
+
|
|
24
|
+
function normalizeCompilePath(filepath) {
|
|
25
|
+
let value = String(filepath || '');
|
|
26
|
+
if (dir.isAbsolute(value)) {
|
|
27
|
+
const rel = dir.relative(process.cwd(), value);
|
|
28
|
+
if (!rel.startsWith('..')) value = rel;
|
|
29
|
+
}
|
|
30
|
+
return value.replaceAll('\\', '/');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function compileErrorMessage(error) {
|
|
34
|
+
return error?.message || String(error);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function compileErrorLine(error) {
|
|
38
|
+
return error?.range?.start?.line ?? error?.line ?? '';
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function compileErrorSnippet(error) {
|
|
42
|
+
try {
|
|
43
|
+
return error?.toSnippet?.() || error?.snippet || error?.stack || compileErrorMessage(error);
|
|
44
|
+
} catch(_) {
|
|
45
|
+
return error?.snippet || error?.stack || compileErrorMessage(error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function compileErrorSignature(errors) {
|
|
50
|
+
return errors
|
|
51
|
+
.map(error => [compileErrorMessage(error), compileErrorLine(error), compileErrorSnippet(error)].join('\n'))
|
|
52
|
+
.join('\n---\n');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function shouldPrintCompileError(filepath, errors) {
|
|
56
|
+
const key = normalizeCompilePath(filepath);
|
|
57
|
+
const signature = compileErrorSignature(errors);
|
|
58
|
+
const previous = _activeCompileErrors.get(key);
|
|
59
|
+
_activeCompileErrors.set(key, { signature, time: Date.now() });
|
|
60
|
+
return previous?.signature !== signature;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function clearCompileError(filepath) {
|
|
64
|
+
_activeCompileErrors.delete(normalizeCompilePath(filepath));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Target platform for the Imba compiler: 'browser' or 'node'
|
|
68
|
+
// Set via setTarget() from the CLI before building
|
|
69
|
+
export let target = 'browser';
|
|
70
|
+
export function setTarget(t) { target = t; }
|
|
71
|
+
|
|
72
|
+
export const imbaPlugin = {
|
|
73
|
+
name: "imba",
|
|
74
|
+
async setup(build) {
|
|
75
|
+
|
|
76
|
+
// when an .imba file is imported...
|
|
77
|
+
build.onLoad({ filter: /\.imba$/ }, async ({ path }) => {
|
|
78
|
+
|
|
79
|
+
const f = dir.parse(path)
|
|
80
|
+
let contents = '';
|
|
81
|
+
|
|
82
|
+
// return the cached version if exists (include target in hash to avoid cross-platform cache hits)
|
|
83
|
+
const cached = dir.join(cache, Bun.hash(path + ':' + target) + '_' + fs.statSync(path).mtimeMs + '.js');
|
|
84
|
+
if (fs.existsSync(cached)) {
|
|
85
|
+
clearCompileError(path);
|
|
86
|
+
stats.bundled++;
|
|
87
|
+
stats.cached++;
|
|
88
|
+
return {
|
|
89
|
+
contents: await Bun.file(cached).text(),
|
|
90
|
+
loader: "js",
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// clear previous cached version
|
|
95
|
+
const glob = new Glob(Bun.hash(path + ':' + target) + '_' + "*.js");
|
|
96
|
+
for await (const file of glob.scan(cache)) if (fs.existsSync(dir.join(cache, file))) unlink(dir.join(cache, file));
|
|
97
|
+
|
|
98
|
+
// if no cached version read and compile it with the imba compiler
|
|
99
|
+
const file = await Bun.file(path).text();
|
|
100
|
+
const platform = target === 'node' || target === 'bun' ? 'node' : 'browser';
|
|
101
|
+
const out = compiler.compile(file, {
|
|
102
|
+
sourcePath: path,
|
|
103
|
+
platform: platform,
|
|
104
|
+
comments: false
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
// the file has been successfully compiled
|
|
108
|
+
if (!out.errors?.length) {
|
|
109
|
+
clearCompileError(path);
|
|
110
|
+
console.log(theme.action("compiling: ") + theme.folder(dir.join(f.dir,'/')) + theme.filename(f.base) + " - " + theme.success("compiled"));
|
|
111
|
+
stats.bundled++;
|
|
112
|
+
stats.compiled++;
|
|
113
|
+
contents = out.js;
|
|
114
|
+
await Bun.write(cached, contents);
|
|
115
|
+
}
|
|
116
|
+
// there were errors during compilation
|
|
117
|
+
else {
|
|
118
|
+
const shouldPrint = shouldPrintCompileError(path, out.errors);
|
|
119
|
+
if (shouldPrint) console.log(theme.action("compiling: ") + theme.folder(dir.join(f.dir,'/')) + theme.filename(f.base) + " - " + theme.failure(" fail "));
|
|
120
|
+
stats.failed++;
|
|
121
|
+
if (shouldPrint) {
|
|
122
|
+
stats.reported++;
|
|
123
|
+
for (let i = 0; i < out.errors.length; i++) {
|
|
124
|
+
if(out.errors[i]) printerr(out.errors[i]);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
stats.errors++;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// and return the compiled source code as "js"
|
|
131
|
+
return {
|
|
132
|
+
contents,
|
|
133
|
+
loader: "js",
|
|
134
|
+
};
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
plugin(imbaPlugin);
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
// -------------------------------------------------------------------------------
|
|
143
|
+
// print pretty messages produced by the imba compiler
|
|
144
|
+
// -------------------------------------------------------------------------------
|
|
145
|
+
|
|
146
|
+
// print an error generated by the imba compiler
|
|
147
|
+
export function printerr(err) {
|
|
148
|
+
|
|
149
|
+
// halper function to produce empty strings
|
|
150
|
+
const fill = (len = 0) => {return new Array(len + 1).join(' ')}
|
|
151
|
+
|
|
152
|
+
// gather the needed information from the compiler error
|
|
153
|
+
const snippet = err.toSnippet().split("\n");
|
|
154
|
+
const errs = snippet[2] ? snippet[2].indexOf('^') : -1;
|
|
155
|
+
|
|
156
|
+
// no source context available — print compact fallback
|
|
157
|
+
if (!snippet[1] || errs === -1) {
|
|
158
|
+
console.log('');
|
|
159
|
+
console.log(fill(10) + theme.error(" " + err.message + " "));
|
|
160
|
+
console.log('');
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
const display = {
|
|
165
|
+
error: " " + err.message + " ",
|
|
166
|
+
outdent: fill(10),
|
|
167
|
+
source: snippet[1] + " ",
|
|
168
|
+
margin: " line " + (err.range.start.line + 1) + " ",
|
|
169
|
+
errs: errs,
|
|
170
|
+
erre: snippet[2].lastIndexOf('^') + 1,
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// calculate parameters for priniting a message
|
|
174
|
+
const center = display.margin.length + display.errs + Math.floor((display.erre - display.errs) / 2);
|
|
175
|
+
const half = Math.ceil((display.error.length - 1) / 2);
|
|
176
|
+
const start = Math.max(0, center - half);
|
|
177
|
+
const end = start + display.error.length;
|
|
178
|
+
const total = Math.max(display.margin.length + display.source.length, end);
|
|
179
|
+
|
|
180
|
+
// print emtpy line
|
|
181
|
+
console.log('');
|
|
182
|
+
|
|
183
|
+
// print line with the error message
|
|
184
|
+
console.log(
|
|
185
|
+
display.outdent +
|
|
186
|
+
theme.margin(fill(Math.min(start, display.margin.length))) +
|
|
187
|
+
theme.code(fill(Math.max(0, start - display.margin.length))) +
|
|
188
|
+
theme.error(display.error) +
|
|
189
|
+
theme.margin(fill(Math.max(0, display.margin.length - end))) +
|
|
190
|
+
theme.code(fill(Math.min(total - display.margin.length, total - end)))
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
// print line with the source code
|
|
194
|
+
console.log(
|
|
195
|
+
display.outdent +
|
|
196
|
+
theme.margin(display.margin) +
|
|
197
|
+
theme.code(display.source.slice(0,display.errs)) +
|
|
198
|
+
theme.error(display.source.slice(display.errs,display.erre)) +
|
|
199
|
+
theme.code(display.source.slice(display.erre)) +
|
|
200
|
+
theme.code(fill(total - display.source.length - display.margin.length))
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// print empty line to balance the view
|
|
204
|
+
// later we can put something usefull here
|
|
205
|
+
// for example a link to online docs about the error
|
|
206
|
+
console.log(
|
|
207
|
+
display.outdent +
|
|
208
|
+
theme.margin(fill(display.margin.length)) +
|
|
209
|
+
theme.code(fill(total - display.margin.length))
|
|
210
|
+
);
|
|
211
|
+
|
|
212
|
+
// print emtpy line
|
|
213
|
+
console.log('');
|
|
214
|
+
}
|
package/serve.js
CHANGED
|
@@ -207,7 +207,7 @@ const hmrClient = `
|
|
|
207
207
|
const msg = JSON.parse(e.data);
|
|
208
208
|
if (msg.type === 'update') _applyUpdate(msg.file, msg.slots);
|
|
209
209
|
else if (msg.type === 'reload') location.reload();
|
|
210
|
-
else if (msg.type === 'error') showError(msg.file, msg.errors);
|
|
210
|
+
else if (msg.type === 'error') showError(msg.file, msg.errors, msg.time);
|
|
211
211
|
else if (msg.type === 'clear-error') clearError(msg.file);
|
|
212
212
|
};
|
|
213
213
|
|
|
@@ -223,8 +223,9 @@ const hmrClient = `
|
|
|
223
223
|
return value;
|
|
224
224
|
}
|
|
225
225
|
|
|
226
|
-
function showError(file, errors) {
|
|
226
|
+
function showError(file, errors, time) {
|
|
227
227
|
const displayFile = normalizeFile(file);
|
|
228
|
+
const displayTime = time || new Date().toLocaleTimeString();
|
|
228
229
|
let overlay = document.getElementById('__bimba_error__');
|
|
229
230
|
if (!overlay) {
|
|
230
231
|
overlay = document.createElement('div');
|
|
@@ -237,7 +238,7 @@ const hmrClient = `
|
|
|
237
238
|
overlay.innerHTML = \`
|
|
238
239
|
<div style="background:#1a1a1a;border:1px solid #ff4444;border-radius:8px;max-width:860px;width:100%;max-height:90vh;overflow:auto;box-shadow:0 0 40px rgba(255,68,68,.3)">
|
|
239
240
|
<div style="background:#ff4444;color:#fff;padding:10px 16px;font-size:13px;font-weight:600;display:flex;justify-content:space-between;align-items:center">
|
|
240
|
-
<span>Compile error — \${displayFile}</span>
|
|
241
|
+
<span>Compile error — \${displayFile} <span style="opacity:.75;font-weight:400">\${displayTime}</span></span>
|
|
241
242
|
<span onclick="document.getElementById('__bimba_error__').remove()" style="cursor:pointer;opacity:.7;font-size:16px">✕</span>
|
|
242
243
|
</div>
|
|
243
244
|
\${errors.map(err => \`
|
|
@@ -609,14 +610,98 @@ export function serve(entrypoint, flags) {
|
|
|
609
610
|
|
|
610
611
|
// ── File watcher ───────────────────────────────────────────────────────────
|
|
611
612
|
|
|
613
|
+
const _activeErrors = new Map()
|
|
614
|
+
|
|
612
615
|
function broadcast(payload) {
|
|
613
616
|
const msg = JSON.stringify(payload)
|
|
614
617
|
for (const socket of sockets) socket.send(msg)
|
|
615
618
|
}
|
|
616
619
|
|
|
620
|
+
function normalizeFile(file) {
|
|
621
|
+
let value = String(file || '')
|
|
622
|
+
if (path.isAbsolute(value)) {
|
|
623
|
+
const rel = path.relative(process.cwd(), value)
|
|
624
|
+
if (!rel.startsWith('..')) value = rel
|
|
625
|
+
}
|
|
626
|
+
value = value.replaceAll('\\', '/')
|
|
627
|
+
while (value.startsWith('./')) value = value.slice(2)
|
|
628
|
+
while (value.startsWith('/')) value = value.slice(1)
|
|
629
|
+
return value
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
function errorMessage(error) {
|
|
633
|
+
return error?.message || String(error)
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function errorLine(error) {
|
|
637
|
+
return error?.range?.start?.line ?? error?.line
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
function errorSnippet(error) {
|
|
641
|
+
try {
|
|
642
|
+
return error?.toSnippet?.() || error?.snippet || error?.stack || errorMessage(error)
|
|
643
|
+
} catch(_) {
|
|
644
|
+
return error?.snippet || error?.stack || errorMessage(error)
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
function serializeErrors(errors) {
|
|
649
|
+
return errors.map(error => ({
|
|
650
|
+
message: errorMessage(error),
|
|
651
|
+
line: errorLine(error),
|
|
652
|
+
snippet: errorSnippet(error),
|
|
653
|
+
}))
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
function errorSignature(errors) {
|
|
657
|
+
return serializeErrors(errors)
|
|
658
|
+
.map(error => [error.message, error.line || '', error.snippet || ''].join('\n'))
|
|
659
|
+
.join('\n---\n')
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
function showTrackedError(file, item) {
|
|
663
|
+
printStatus(file, 'fail', item.errors)
|
|
664
|
+
broadcast({ type: 'error', file, time: item.time, errors: item.payload })
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
function reportError(file, errors) {
|
|
668
|
+
const key = normalizeFile(file)
|
|
669
|
+
const list = Array.isArray(errors) ? errors : [errors]
|
|
670
|
+
const signature = errorSignature(list)
|
|
671
|
+
const previous = _activeErrors.get(key)
|
|
672
|
+
|
|
673
|
+
const item = {
|
|
674
|
+
signature,
|
|
675
|
+
errors: list,
|
|
676
|
+
payload: serializeErrors(list),
|
|
677
|
+
time: new Date().toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit', second: '2-digit' }),
|
|
678
|
+
}
|
|
679
|
+
_activeErrors.set(key, item)
|
|
680
|
+
if (previous?.signature === signature && !_isTTY) {
|
|
681
|
+
broadcast({ type: 'error', file: key, time: item.time, errors: item.payload })
|
|
682
|
+
return
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
showTrackedError(key, item)
|
|
686
|
+
}
|
|
687
|
+
|
|
617
688
|
function clearError(file) {
|
|
618
|
-
|
|
619
|
-
|
|
689
|
+
const key = file ? normalizeFile(file) : null
|
|
690
|
+
const wasStatusFile = key && _statusFile === key
|
|
691
|
+
const hadError = key ? _activeErrors.has(key) : _activeErrors.size > 0
|
|
692
|
+
|
|
693
|
+
if (key) _activeErrors.delete(key)
|
|
694
|
+
else _activeErrors.clear()
|
|
695
|
+
|
|
696
|
+
if (key && !hadError && !wasStatusFile) return
|
|
697
|
+
|
|
698
|
+
clearStatus(key)
|
|
699
|
+
broadcast({ type: 'clear-error', file: key })
|
|
700
|
+
|
|
701
|
+
if (wasStatusFile && _activeErrors.size) {
|
|
702
|
+
const [nextFile, nextItem] = Array.from(_activeErrors.entries()).at(-1)
|
|
703
|
+
showTrackedError(nextFile, nextItem)
|
|
704
|
+
}
|
|
620
705
|
}
|
|
621
706
|
|
|
622
707
|
const _debounce = new Map()
|
|
@@ -644,7 +729,7 @@ export function serve(entrypoint, flags) {
|
|
|
644
729
|
|
|
645
730
|
async function compileChangedFile(filename, version) {
|
|
646
731
|
const filepath = path.join(srcDir, filename)
|
|
647
|
-
const rel = path.join(path.relative('.', srcDir), filename)
|
|
732
|
+
const rel = normalizeFile(path.join(path.relative('.', srcDir), filename))
|
|
648
733
|
|
|
649
734
|
try {
|
|
650
735
|
if (!existsSync(filepath)) {
|
|
@@ -659,12 +744,7 @@ export function serve(entrypoint, flags) {
|
|
|
659
744
|
if (!isCurrentChange(filename, version)) return
|
|
660
745
|
|
|
661
746
|
if (out.errors?.length) {
|
|
662
|
-
|
|
663
|
-
broadcast({ type: 'error', file: rel, errors: out.errors.map(e => ({
|
|
664
|
-
message: e.message,
|
|
665
|
-
line: e.range?.start?.line,
|
|
666
|
-
snippet: e.toSnippet(),
|
|
667
|
-
})) })
|
|
747
|
+
reportError(rel, out.errors)
|
|
668
748
|
return
|
|
669
749
|
}
|
|
670
750
|
|
|
@@ -677,8 +757,7 @@ export function serve(entrypoint, flags) {
|
|
|
677
757
|
broadcast({ type: 'update', file: rel, slots: out.slots || 'shifted' })
|
|
678
758
|
} catch(e) {
|
|
679
759
|
if (!isCurrentChange(filename, version)) return
|
|
680
|
-
|
|
681
|
-
broadcast({ type: 'error', file: rel, errors: [{ message: e.message, snippet: e.stack || e.message }] })
|
|
760
|
+
reportError(rel, [{ message: e.message, snippet: e.stack || e.message }])
|
|
682
761
|
}
|
|
683
762
|
}
|
|
684
763
|
|
|
@@ -723,23 +802,17 @@ export function serve(entrypoint, flags) {
|
|
|
723
802
|
// Imba files: compile on demand and serve as JS
|
|
724
803
|
if (pathname.endsWith('.imba')) {
|
|
725
804
|
const filepath = '.' + pathname
|
|
805
|
+
const file = normalizeFile(pathname)
|
|
726
806
|
try {
|
|
727
807
|
const out = await compileFile(filepath)
|
|
728
808
|
if (out.errors?.length) {
|
|
729
|
-
|
|
730
|
-
printStatus(file, 'fail', out.errors)
|
|
731
|
-
broadcast({ type: 'error', file, errors: out.errors.map(e => ({
|
|
732
|
-
message: e.message,
|
|
733
|
-
line: e.range?.start?.line,
|
|
734
|
-
snippet: e.toSnippet(),
|
|
735
|
-
})) })
|
|
809
|
+
reportError(file, out.errors)
|
|
736
810
|
return new Response(out.errors.map(e => e.message).join('\n'), { status: 500 })
|
|
737
811
|
}
|
|
812
|
+
clearError(file)
|
|
738
813
|
return new Response(out.js, { headers: { 'Content-Type': 'application/javascript' } })
|
|
739
814
|
} catch(e) {
|
|
740
|
-
|
|
741
|
-
printStatus(file, 'fail', [{ message: e.message }])
|
|
742
|
-
broadcast({ type: 'error', file, errors: [{ message: e.message, snippet: e.stack || e.message }] })
|
|
815
|
+
reportError(file, [{ message: e.message, snippet: e.stack || e.message }])
|
|
743
816
|
return new Response(e.message, { status: 500 })
|
|
744
817
|
}
|
|
745
818
|
}
|
|
@@ -779,7 +852,12 @@ export function serve(entrypoint, flags) {
|
|
|
779
852
|
const resolved = resolveFileCandidate('.' + pathname)
|
|
780
853
|
if (resolved?.endsWith('.imba')) {
|
|
781
854
|
const out = await compileFile(resolved)
|
|
782
|
-
|
|
855
|
+
const file = normalizeFile(resolved)
|
|
856
|
+
if (out.errors?.length) {
|
|
857
|
+
reportError(file, out.errors)
|
|
858
|
+
return new Response(out.errors.map(e => e.message).join('\n'), { status: 500 })
|
|
859
|
+
}
|
|
860
|
+
clearError(file)
|
|
783
861
|
return new Response(out.js, { headers: { 'Content-Type': 'application/javascript' } })
|
|
784
862
|
}
|
|
785
863
|
|
|
@@ -805,7 +883,13 @@ export function serve(entrypoint, flags) {
|
|
|
805
883
|
const imbaPath = '.' + pathname + '.imba'
|
|
806
884
|
if (existsSync(imbaPath)) {
|
|
807
885
|
const out = await compileFile(imbaPath)
|
|
808
|
-
|
|
886
|
+
const file = normalizeFile(imbaPath)
|
|
887
|
+
if (out.errors?.length) {
|
|
888
|
+
reportError(file, out.errors)
|
|
889
|
+
return new Response(out.errors.map(e => e.message).join('\n'), { status: 500 })
|
|
890
|
+
}
|
|
891
|
+
clearError(file)
|
|
892
|
+
return new Response(out.js, { headers: { 'Content-Type': 'application/javascript' } })
|
|
809
893
|
}
|
|
810
894
|
for (const ext of ['.js', '.mjs']) {
|
|
811
895
|
const withExt = '.' + pathname + ext
|