bimba-cli 0.7.28 → 0.7.29
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/package.json +1 -1
- package/plugin.js +82 -56
- package/serve.js +59 -38
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -45,6 +45,16 @@ function compileErrorKey(filepath) {
|
|
|
45
45
|
return physicalCompileKey(filepath) || `path:${normalizeCompilePath(filepath)}`;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
function compileFileStamp(filepath) {
|
|
49
|
+
try {
|
|
50
|
+
const stat = fs.statSync(filepath);
|
|
51
|
+
if (!stat.isFile()) return null;
|
|
52
|
+
return `${stat.mtimeMs ?? stat.mtime?.getTime?.() ?? 0}_${stat.size ?? 0}`;
|
|
53
|
+
} catch(_) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
48
58
|
function compileErrorMessage(error) {
|
|
49
59
|
return error?.message || String(error);
|
|
50
60
|
}
|
|
@@ -102,66 +112,82 @@ export const imbaPlugin = {
|
|
|
102
112
|
build.onLoad({ filter: /\.imba$/ }, async ({ path }) => {
|
|
103
113
|
|
|
104
114
|
const f = dir.parse(path)
|
|
105
|
-
let contents = '';
|
|
106
|
-
|
|
107
|
-
// return the cached version if exists (include target in hash to avoid cross-platform cache hits)
|
|
108
|
-
const cached = dir.join(cache, Bun.hash(path + ':' + target) + '_' + fs.statSync(path).mtimeMs + '.js');
|
|
109
|
-
if (fs.existsSync(cached)) {
|
|
110
|
-
clearCompileError(path);
|
|
111
|
-
stats.bundled++;
|
|
112
|
-
stats.cached++;
|
|
113
|
-
return {
|
|
114
|
-
contents: await Bun.file(cached).text(),
|
|
115
|
-
loader: "js",
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
115
|
|
|
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
|
-
await
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
116
|
+
while (true) {
|
|
117
|
+
const stamp = compileFileStamp(path);
|
|
118
|
+
if (!stamp) {
|
|
119
|
+
clearCompileError(path);
|
|
120
|
+
return { contents: '', loader: "js" };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
let contents = '';
|
|
124
|
+
|
|
125
|
+
// return the cached version if exists (include target in hash to avoid cross-platform cache hits)
|
|
126
|
+
const cached = dir.join(cache, Bun.hash(path + ':' + target) + '_' + stamp + '.js');
|
|
127
|
+
if (fs.existsSync(cached)) {
|
|
128
|
+
const cachedContents = await Bun.file(cached).text();
|
|
129
|
+
if (compileFileStamp(path) !== stamp) continue;
|
|
130
|
+
clearCompileError(path);
|
|
131
|
+
stats.bundled++;
|
|
132
|
+
stats.cached++;
|
|
133
|
+
return {
|
|
134
|
+
contents: cachedContents,
|
|
135
|
+
loader: "js",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// clear previous cached version
|
|
140
|
+
const glob = new Glob(Bun.hash(path + ':' + target) + '_' + "*.js");
|
|
141
|
+
for await (const file of glob.scan(cache)) if (fs.existsSync(dir.join(cache, file))) unlink(dir.join(cache, file));
|
|
142
|
+
|
|
143
|
+
// if no cached version read and compile it with the imba compiler
|
|
144
|
+
const file = await Bun.file(path).text();
|
|
145
|
+
if (compileFileStamp(path) !== stamp) continue;
|
|
146
|
+
|
|
147
|
+
const platform = target === 'node' || target === 'bun' ? 'node' : 'browser';
|
|
148
|
+
let out
|
|
149
|
+
try {
|
|
150
|
+
out = compiler.compile(file, {
|
|
151
|
+
sourcePath: path,
|
|
152
|
+
platform: platform,
|
|
153
|
+
comments: false
|
|
154
|
+
})
|
|
155
|
+
} catch (error) {
|
|
156
|
+
out = { js: '', errors: [error] }
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Never report or cache a result from an older source snapshot.
|
|
160
|
+
if (compileFileStamp(path) !== stamp) continue;
|
|
161
|
+
|
|
162
|
+
// the file has been successfully compiled
|
|
163
|
+
if (!out.errors?.length) {
|
|
164
|
+
clearCompileError(path);
|
|
165
|
+
console.log(theme.action("compiling: ") + theme.folder(dir.join(f.dir,'/')) + theme.filename(f.base) + " - " + theme.success("compiled"));
|
|
166
|
+
stats.bundled++;
|
|
167
|
+
stats.compiled++;
|
|
168
|
+
contents = out.js;
|
|
169
|
+
await Bun.write(cached, contents);
|
|
170
|
+
}
|
|
171
|
+
// there were errors during compilation
|
|
172
|
+
else {
|
|
173
|
+
const shouldPrint = shouldPrintCompileError(path, out.errors);
|
|
174
|
+
if (shouldPrint) console.log(theme.action("compiling: ") + theme.folder(dir.join(f.dir,'/')) + theme.filename(f.base) + " - " + theme.failure(" fail "));
|
|
175
|
+
stats.failed++;
|
|
176
|
+
if (shouldPrint) {
|
|
177
|
+
stats.reported++;
|
|
178
|
+
for (let i = 0; i < out.errors.length; i++) {
|
|
179
|
+
if(out.errors[i]) printCompileError(out.errors[i]);
|
|
180
|
+
}
|
|
155
181
|
}
|
|
182
|
+
stats.errors++;
|
|
156
183
|
}
|
|
157
|
-
|
|
184
|
+
|
|
185
|
+
// and return the compiled source code as "js"
|
|
186
|
+
return {
|
|
187
|
+
contents,
|
|
188
|
+
loader: "js",
|
|
189
|
+
};
|
|
158
190
|
}
|
|
159
|
-
|
|
160
|
-
// and return the compiled source code as "js"
|
|
161
|
-
return {
|
|
162
|
-
contents,
|
|
163
|
-
loader: "js",
|
|
164
|
-
};
|
|
165
191
|
});
|
|
166
192
|
}
|
|
167
193
|
};
|
package/serve.js
CHANGED
|
@@ -409,6 +409,17 @@ function isMissingFileError(error) {
|
|
|
409
409
|
return error?.code === 'ENOENT' || String(error?.message || error).includes('ENOENT: no such file or directory')
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
+
function fileStamp(abs) {
|
|
413
|
+
try {
|
|
414
|
+
const stat = statSync(abs)
|
|
415
|
+
if (!stat.isFile()) return null
|
|
416
|
+
return `${stat.mtimeMs ?? stat.mtime?.getTime?.() ?? 0}:${stat.size ?? 0}`
|
|
417
|
+
} catch (error) {
|
|
418
|
+
if (isMissingFileError(error)) return null
|
|
419
|
+
throw error
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
412
423
|
function missingCompileResult(filepath) {
|
|
413
424
|
dropFileState(filepath)
|
|
414
425
|
return { js: '', errors: [], slots: null, changeType: 'missing', missing: true }
|
|
@@ -416,49 +427,59 @@ function missingCompileResult(filepath) {
|
|
|
416
427
|
|
|
417
428
|
async function compileFile(filepath) {
|
|
418
429
|
const abs = path.resolve(filepath)
|
|
419
|
-
if (!existsSync(abs)) return missingCompileResult(abs)
|
|
420
430
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
stat = await file.stat()
|
|
425
|
-
} catch (error) {
|
|
426
|
-
if (isMissingFileError(error)) return missingCompileResult(abs)
|
|
427
|
-
throw error
|
|
428
|
-
}
|
|
429
|
-
const stamp = `${stat.mtimeMs ?? stat.mtime?.getTime?.() ?? 0}:${stat.size ?? 0}`
|
|
431
|
+
while (true) {
|
|
432
|
+
const stamp = fileStamp(abs)
|
|
433
|
+
if (!stamp) return missingCompileResult(abs)
|
|
430
434
|
|
|
431
|
-
|
|
432
|
-
|
|
435
|
+
const cached = _compileCache.get(abs)
|
|
436
|
+
if (cached && cached.stamp === stamp) {
|
|
437
|
+
if (fileStamp(abs) !== stamp) continue
|
|
438
|
+
return _normalizeResult(cached.result, { changeType: 'cached' })
|
|
439
|
+
}
|
|
433
440
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
sourcePath: filepath,
|
|
443
|
-
platform: 'browser',
|
|
444
|
-
sourcemap: 'inline',
|
|
445
|
-
})
|
|
441
|
+
const file = Bun.file(abs)
|
|
442
|
+
let code
|
|
443
|
+
try {
|
|
444
|
+
code = await file.text()
|
|
445
|
+
} catch (error) {
|
|
446
|
+
if (isMissingFileError(error)) return missingCompileResult(abs)
|
|
447
|
+
throw error
|
|
448
|
+
}
|
|
446
449
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
result.js = rewriteBareImports(js)
|
|
451
|
-
const prev = _prevSlots.get(abs)
|
|
452
|
-
result.slots = (prev === undefined || prev === slotCount) ? 'stable' : 'shifted'
|
|
453
|
-
_prevSlots.set(abs, slotCount)
|
|
454
|
-
}
|
|
450
|
+
// A save can land while an older request is compiling. Never publish,
|
|
451
|
+
// cache, or report a result unless it still matches the current file.
|
|
452
|
+
if (fileStamp(abs) !== stamp) continue
|
|
455
453
|
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
454
|
+
let result
|
|
455
|
+
try {
|
|
456
|
+
result = compiler.compile(code, {
|
|
457
|
+
sourcePath: filepath,
|
|
458
|
+
platform: 'browser',
|
|
459
|
+
sourcemap: 'inline',
|
|
460
|
+
})
|
|
461
|
+
} catch (error) {
|
|
462
|
+
result = { js: '', errors: [error], slots: null }
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
if (fileStamp(abs) !== stamp) continue
|
|
466
|
+
|
|
467
|
+
const errors = result.errors || []
|
|
468
|
+
if (!errors.length && result.js) {
|
|
469
|
+
const { js, slotCount } = stabilizeSymbols(result.js, abs)
|
|
470
|
+
result.js = rewriteBareImports(js)
|
|
471
|
+
const prev = _prevSlots.get(abs)
|
|
472
|
+
result.slots = (prev === undefined || prev === slotCount) ? 'stable' : 'shifted'
|
|
473
|
+
_prevSlots.set(abs, slotCount)
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// Bake errors as an own property so caching/spreading preserves them.
|
|
477
|
+
const baked = { js: result.js, errors, slots: result.slots }
|
|
478
|
+
const changeType = _prevJs.get(abs) === baked.js ? 'none' : 'full'
|
|
479
|
+
_prevJs.set(abs, baked.js)
|
|
480
|
+
_compileCache.set(abs, { stamp, result: baked })
|
|
481
|
+
return _normalizeResult(baked, { changeType })
|
|
482
|
+
}
|
|
462
483
|
}
|
|
463
484
|
|
|
464
485
|
// ─── HTML helpers ─────────────────────────────────────────────────────────────
|