bimba-cli 0.1.7 → 0.1.9
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 +119 -119
- package/package.json +1 -1
- package/plugin.js +193 -193
- package/utils.js +29 -29
package/index.js
CHANGED
|
@@ -1,120 +1,120 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
import { parseArgs } from "util";
|
|
4
|
-
import { imbaPlugin, stats, cache } from './plugin.js'
|
|
5
|
-
import {theme} from './utils.js';
|
|
6
|
-
import fs from 'fs'
|
|
7
|
-
import path from 'path';
|
|
8
|
-
import { rmSync } from "node:fs";
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
let flags = {}
|
|
12
|
-
let entrypoint = ''
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const { values, positionals } = parseArgs({
|
|
16
|
-
args: Bun.argv,
|
|
17
|
-
options: {
|
|
18
|
-
watch: { type: 'boolean' },
|
|
19
|
-
outdir: { type: 'string' },
|
|
20
|
-
help: { type: 'boolean' },
|
|
21
|
-
clearcache: { type: 'boolean' },
|
|
22
|
-
minify: { type: 'boolean' },
|
|
23
|
-
target: { type: 'string' },
|
|
24
|
-
sourcemap: { type: 'string' },
|
|
25
|
-
},
|
|
26
|
-
strict: true,
|
|
27
|
-
allowPositionals: true,
|
|
28
|
-
});
|
|
29
|
-
flags = values;
|
|
30
|
-
entrypoint = Bun.argv[2];
|
|
31
|
-
}
|
|
32
|
-
catch (error) {
|
|
33
|
-
if (error instanceof Error)
|
|
34
|
-
console.log(error.message);
|
|
35
|
-
else
|
|
36
|
-
console.log("Could not resolve CLI arguments. Read help to know them: " + theme.flags('--entry file.imba'));
|
|
37
|
-
process.exit(0);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// help: more on bun building params here: https://bun.sh/docs/bundler
|
|
41
|
-
if(flags.help) {
|
|
42
|
-
console.log("");
|
|
43
|
-
console.log("Bimba requeres an .imba file and a folder where to put compiled .js files.");
|
|
44
|
-
console.log("For example like this: "+theme.filedir('bimba file.imba --outdir public'));
|
|
45
|
-
console.log("");
|
|
46
|
-
console.log(" "+theme.flags('--outdir <folder>')+" Compile imba files to the specified folder");
|
|
47
|
-
console.log(" "+theme.flags('--minify')+" Minify compiled .js files");
|
|
48
|
-
console.log(" "+theme.flags('--sourcemap <inline|external|none>')+" How should sourcemap files be included in the .js");
|
|
49
|
-
console.log(" "+theme.flags('--platform <browser|node>')+" Flag that will be passed to Imba compiler ('node' value does not work in Bun)");
|
|
50
|
-
console.log(" "+theme.flags('--watch')+" Watch for changes in the entrypoint folder");
|
|
51
|
-
console.log(" "+theme.flags('--clearcache')+" Clear cache on exit, works only when in watch mode");
|
|
52
|
-
console.log("");
|
|
53
|
-
process.exit(0);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
// no entrypoint or outdir
|
|
58
|
-
if(!entrypoint || !flags.outdir) {
|
|
59
|
-
console.log("");
|
|
60
|
-
console.log("You should provide entrypoint and the output dir: "+theme.flags('bimba file.imba --outdir public'));
|
|
61
|
-
console.log("For more information: "+theme.flags('--help'));
|
|
62
|
-
console.log("");
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// build
|
|
67
|
-
bundle();
|
|
68
|
-
watch(bundle);
|
|
69
|
-
|
|
70
|
-
function watch(callback) {
|
|
71
|
-
if (flags.watch) {
|
|
72
|
-
const watcher = fs.watch(path.dirname(entrypoint), {recursive: true}, async (event, filename) => ( callback() ));
|
|
73
|
-
|
|
74
|
-
process.on("SIGINT", () => {
|
|
75
|
-
if(flags.clearcache) rmSync(cache, { recursive: true, force: true });
|
|
76
|
-
|
|
77
|
-
if(watcher) {
|
|
78
|
-
watcher.close();
|
|
79
|
-
process.exit(0);
|
|
80
|
-
}
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function bundle() {
|
|
86
|
-
if (!fs.existsSync(entrypoint)) {
|
|
87
|
-
console.log(theme.failure('Error.') + ` The specified entrypoint does not exist: ${theme.filedir(entrypoint)}`);
|
|
88
|
-
process.exit(0);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
stats.failed = 0
|
|
92
|
-
stats.compiled = 0
|
|
93
|
-
stats.errors = 0
|
|
94
|
-
stats.bundled = 0
|
|
95
|
-
|
|
96
|
-
const start = Date.now();
|
|
97
|
-
|
|
98
|
-
console.log("──────────────────────────────────────────────────────────────────────");
|
|
99
|
-
console.log(theme.start(`Start building the Imba entrypoint: ${theme.filedir(entrypoint)}`));
|
|
100
|
-
|
|
101
|
-
const result = await Bun.build({
|
|
102
|
-
entrypoints: [entrypoint],
|
|
103
|
-
outdir: flags.outdir,
|
|
104
|
-
target: flags.target || 'browser',
|
|
105
|
-
sourcemap: flags.sourcemap || 'none',
|
|
106
|
-
minify: flags.minify || true,
|
|
107
|
-
plugins: [imbaPlugin]
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
if(stats.failed)
|
|
111
|
-
console.log(theme.start(theme.failure("Failure.") +` Imba compiler failed to proceed ${theme.count(stats.failed)} file${stats.failed > 1 ? 's' : ''}`));
|
|
112
|
-
else
|
|
113
|
-
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)}`));
|
|
114
|
-
|
|
115
|
-
if(!result.success && !stats.errors){
|
|
116
|
-
for (const log of result.logs) {
|
|
117
|
-
console.log(log);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
|
|
3
|
+
import { parseArgs } from "util";
|
|
4
|
+
import { imbaPlugin, stats, cache } from './plugin.js'
|
|
5
|
+
import {theme} from './utils.js';
|
|
6
|
+
import fs from 'fs'
|
|
7
|
+
import path from 'path';
|
|
8
|
+
import { rmSync } from "node:fs";
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
let flags = {}
|
|
12
|
+
let entrypoint = ''
|
|
13
|
+
|
|
14
|
+
try {
|
|
15
|
+
const { values, positionals } = parseArgs({
|
|
16
|
+
args: Bun.argv,
|
|
17
|
+
options: {
|
|
18
|
+
watch: { type: 'boolean' },
|
|
19
|
+
outdir: { type: 'string' },
|
|
20
|
+
help: { type: 'boolean' },
|
|
21
|
+
clearcache: { type: 'boolean' },
|
|
22
|
+
minify: { type: 'boolean' },
|
|
23
|
+
target: { type: 'string' },
|
|
24
|
+
sourcemap: { type: 'string' },
|
|
25
|
+
},
|
|
26
|
+
strict: true,
|
|
27
|
+
allowPositionals: true,
|
|
28
|
+
});
|
|
29
|
+
flags = values;
|
|
30
|
+
entrypoint = Bun.argv[2];
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof Error)
|
|
34
|
+
console.log(error.message);
|
|
35
|
+
else
|
|
36
|
+
console.log("Could not resolve CLI arguments. Read help to know them: " + theme.flags('--entry file.imba'));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// help: more on bun building params here: https://bun.sh/docs/bundler
|
|
41
|
+
if(flags.help) {
|
|
42
|
+
console.log("");
|
|
43
|
+
console.log("Bimba requeres an .imba file and a folder where to put compiled .js files.");
|
|
44
|
+
console.log("For example like this: "+theme.filedir('bimba file.imba --outdir public'));
|
|
45
|
+
console.log("");
|
|
46
|
+
console.log(" "+theme.flags('--outdir <folder>')+" Compile imba files to the specified folder");
|
|
47
|
+
console.log(" "+theme.flags('--minify')+" Minify compiled .js files");
|
|
48
|
+
console.log(" "+theme.flags('--sourcemap <inline|external|none>')+" How should sourcemap files be included in the .js");
|
|
49
|
+
console.log(" "+theme.flags('--platform <browser|node>')+" Flag that will be passed to Imba compiler ('node' value does not work in Bun)");
|
|
50
|
+
console.log(" "+theme.flags('--watch')+" Watch for changes in the entrypoint folder");
|
|
51
|
+
console.log(" "+theme.flags('--clearcache')+" Clear cache on exit, works only when in watch mode");
|
|
52
|
+
console.log("");
|
|
53
|
+
process.exit(0);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
// no entrypoint or outdir
|
|
58
|
+
if(!entrypoint || !flags.outdir) {
|
|
59
|
+
console.log("");
|
|
60
|
+
console.log("You should provide entrypoint and the output dir: "+theme.flags('bimba file.imba --outdir public'));
|
|
61
|
+
console.log("For more information: "+theme.flags('--help'));
|
|
62
|
+
console.log("");
|
|
63
|
+
process.exit(1);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// build
|
|
67
|
+
bundle();
|
|
68
|
+
watch(bundle);
|
|
69
|
+
|
|
70
|
+
function watch(callback) {
|
|
71
|
+
if (flags.watch) {
|
|
72
|
+
const watcher = fs.watch(path.dirname(entrypoint), {recursive: true}, async (event, filename) => ( callback() ));
|
|
73
|
+
|
|
74
|
+
process.on("SIGINT", () => {
|
|
75
|
+
if(flags.clearcache) rmSync(cache, { recursive: true, force: true });
|
|
76
|
+
|
|
77
|
+
if(watcher) {
|
|
78
|
+
watcher.close();
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function bundle() {
|
|
86
|
+
if (!fs.existsSync(entrypoint)) {
|
|
87
|
+
console.log(theme.failure('Error.') + ` The specified entrypoint does not exist: ${theme.filedir(entrypoint)}`);
|
|
88
|
+
process.exit(0);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
stats.failed = 0
|
|
92
|
+
stats.compiled = 0
|
|
93
|
+
stats.errors = 0
|
|
94
|
+
stats.bundled = 0
|
|
95
|
+
|
|
96
|
+
const start = Date.now();
|
|
97
|
+
|
|
98
|
+
console.log("──────────────────────────────────────────────────────────────────────");
|
|
99
|
+
console.log(theme.start(`Start building the Imba entrypoint: ${theme.filedir(entrypoint)}`));
|
|
100
|
+
|
|
101
|
+
const result = await Bun.build({
|
|
102
|
+
entrypoints: [entrypoint],
|
|
103
|
+
outdir: flags.outdir,
|
|
104
|
+
target: flags.target || 'browser',
|
|
105
|
+
sourcemap: flags.sourcemap || 'none',
|
|
106
|
+
minify: flags.minify || true,
|
|
107
|
+
plugins: [imbaPlugin]
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if(stats.failed)
|
|
111
|
+
console.log(theme.start(theme.failure("Failure.") +` Imba compiler failed to proceed ${theme.count(stats.failed)} file${stats.failed > 1 ? 's' : ''}`));
|
|
112
|
+
else
|
|
113
|
+
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)}`));
|
|
114
|
+
|
|
115
|
+
if(!result.success && !stats.errors){
|
|
116
|
+
for (const log of result.logs) {
|
|
117
|
+
console.log(log);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
120
|
}
|
package/package.json
CHANGED
package/plugin.js
CHANGED
|
@@ -1,193 +1,193 @@
|
|
|
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 = 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
|
-
export const imbaPlugin = {
|
|
22
|
-
name: "imba",
|
|
23
|
-
async setup(build) {
|
|
24
|
-
|
|
25
|
-
// when there is import without file extension
|
|
26
|
-
build.onResolve({filter: /^.*[^.]{5}$/ }, ({ path, importer }) => {
|
|
27
|
-
|
|
28
|
-
let filename = path;
|
|
29
|
-
// resolve relative path
|
|
30
|
-
if (path.startsWith('.')) { filename = dir.resolve(dir.dirname(importer), filename) };
|
|
31
|
-
|
|
32
|
-
// assume that the file is .js
|
|
33
|
-
try { return {path: Bun.resolveSync(filename + '.js', '.')}}
|
|
34
|
-
catch (error) {
|
|
35
|
-
// assume that the file is .mjs
|
|
36
|
-
try { return {path: Bun.resolveSync(filename + '.mjs', '.')}}
|
|
37
|
-
catch (error) {
|
|
38
|
-
// assume that the file is .cs
|
|
39
|
-
try { return {path: Bun.resolveSync(filename + '.cjs', '.')}}
|
|
40
|
-
catch (error) {
|
|
41
|
-
// assume that the file is .imba
|
|
42
|
-
try { return {path: Bun.resolveSync(filename + '.imba', '.')}}
|
|
43
|
-
catch (error) {
|
|
44
|
-
// if direct resolution failed
|
|
45
|
-
filename += '.imba';
|
|
46
|
-
|
|
47
|
-
// assume that the relative path should be resolved relative to importer
|
|
48
|
-
let fn = dir.resolve(dir.dirname(importer), filename);
|
|
49
|
-
if (fs.existsSync(fn)) return {path: fn};
|
|
50
|
-
// assume that the relative path should be resolved relative to node_modules
|
|
51
|
-
fn = dir.resolve('./node_modules', filename);
|
|
52
|
-
if (fs.existsSync(fn)) return {path: fn};
|
|
53
|
-
// assume that the relative path should be resolved relative to project root
|
|
54
|
-
fn = dir.resolve(process.cwd(), filename);
|
|
55
|
-
if (fs.existsSync(fn)) return {path: fn};
|
|
56
|
-
|
|
57
|
-
// if the path still is unresolved throw error and leave the further resolution on Bun's resolver
|
|
58
|
-
if (error instanceof Error) {
|
|
59
|
-
throw new Error(error.message);
|
|
60
|
-
}
|
|
61
|
-
else
|
|
62
|
-
throw new Error('Could not resolve file: ' + path);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
// when an .imba file is imported...
|
|
70
|
-
build.onLoad({ filter: /\.imba$/ }, async ({ path }) => {
|
|
71
|
-
|
|
72
|
-
const f = dir.parse(path)
|
|
73
|
-
let contents = '';
|
|
74
|
-
|
|
75
|
-
// return the cached version if it exists
|
|
76
|
-
const cached = cache + Bun.hash(path) + '_' + fs.statSync(path).mtimeMs + '.js';
|
|
77
|
-
if (fs.existsSync(cached)) {
|
|
78
|
-
stats.bundled++;
|
|
79
|
-
stats.cached++;
|
|
80
|
-
//console.log(theme.action("cached: ") + theme.folder(f.dir + '/') + theme.filename(f.base) + " - " + theme.success("ok"));
|
|
81
|
-
return {
|
|
82
|
-
contents: await Bun.file(cached).text(),
|
|
83
|
-
loader: "js",
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// clear previous cached version
|
|
88
|
-
const glob = new Glob(Bun.hash(path) + '_' + "*.js");
|
|
89
|
-
for await (const file of glob.scan(cache)) unlink(cache + file);
|
|
90
|
-
|
|
91
|
-
// if no cached version read and compile it with the imba compiler
|
|
92
|
-
const file = await Bun.file(path).text();
|
|
93
|
-
const out = compiler.compile(file, {
|
|
94
|
-
sourcePath: path,
|
|
95
|
-
platform: 'browser'
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
// print about file complitaion
|
|
99
|
-
console.write(theme.action("compiling: ") + theme.folder(f.dir + '/') + theme.filename(f.base) + " - ");
|
|
100
|
-
|
|
101
|
-
// the file has been successfully compiled
|
|
102
|
-
if (!out.errors || !out.errors.length) {
|
|
103
|
-
stats.bundled++;
|
|
104
|
-
stats.compiled++;
|
|
105
|
-
contents = out.js;
|
|
106
|
-
await Bun.write(cached, contents);
|
|
107
|
-
console.write(theme.success("cached" + "\n"));
|
|
108
|
-
}
|
|
109
|
-
// there were errors during compilation
|
|
110
|
-
else {
|
|
111
|
-
console.write(theme.failure(" fail ") + "\n");
|
|
112
|
-
stats.failed++;
|
|
113
|
-
for (let i = 0; i < out.errors.length; i++) {
|
|
114
|
-
if(out.errors[i]) printerr(out.errors[i]);
|
|
115
|
-
}
|
|
116
|
-
stats.errors++;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// and return the compiled source code as "js"
|
|
120
|
-
return {
|
|
121
|
-
contents,
|
|
122
|
-
loader: "js",
|
|
123
|
-
};
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
|
-
|
|
128
|
-
plugin(imbaPlugin);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
// -------------------------------------------------------------------------------
|
|
132
|
-
// print pretty messages produced by the imba compiler
|
|
133
|
-
// -------------------------------------------------------------------------------
|
|
134
|
-
|
|
135
|
-
// print an error generated by the imba compiler
|
|
136
|
-
function printerr(err) {
|
|
137
|
-
|
|
138
|
-
// halper function to produce empty strings
|
|
139
|
-
const fill = (len = 0) => {return new Array(len + 1).join(' ')}
|
|
140
|
-
|
|
141
|
-
// gather the needed information from the compiler error
|
|
142
|
-
const snippet = err.toSnippet().split("\n");
|
|
143
|
-
const display = {
|
|
144
|
-
error: " " + err.message + " ",
|
|
145
|
-
outdent: fill(10),
|
|
146
|
-
source: snippet[1] + " ",
|
|
147
|
-
margin: " line " + err.range.start.line + " ",
|
|
148
|
-
errs: snippet[2].indexOf('^'),
|
|
149
|
-
erre: snippet[2].lastIndexOf('^') + 1,
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
// calculate parameters for priniting a message
|
|
153
|
-
const center = display.margin.length + display.errs + Math.floor((display.erre - display.errs) / 2);
|
|
154
|
-
const half = Math.ceil((display.error.length - 1) / 2);
|
|
155
|
-
const start = Math.max(0, center - half);
|
|
156
|
-
const end = start + display.error.length;
|
|
157
|
-
const total = Math.max(display.margin.length + display.source.length, end);
|
|
158
|
-
|
|
159
|
-
// print emtpy line
|
|
160
|
-
console.log('');
|
|
161
|
-
|
|
162
|
-
// print line with the error message
|
|
163
|
-
console.log(
|
|
164
|
-
display.outdent +
|
|
165
|
-
theme.margin(fill(Math.min(start, display.margin.length))) +
|
|
166
|
-
theme.code(fill(Math.max(0, start - display.margin.length))) +
|
|
167
|
-
theme.error(display.error) +
|
|
168
|
-
theme.margin(fill(Math.max(0, display.margin.length - end))) +
|
|
169
|
-
theme.code(fill(Math.min(total - display.margin.length, total - end)))
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
// print line with the source code
|
|
173
|
-
console.log(
|
|
174
|
-
display.outdent +
|
|
175
|
-
theme.margin(display.margin) +
|
|
176
|
-
theme.code(display.source.slice(0,display.errs)) +
|
|
177
|
-
theme.error(display.source.slice(display.errs,display.erre)) +
|
|
178
|
-
theme.code(display.source.slice(display.erre)) +
|
|
179
|
-
theme.code(fill(total - display.source.length - display.margin.length))
|
|
180
|
-
);
|
|
181
|
-
|
|
182
|
-
// print empty line to balance the view
|
|
183
|
-
// later we can put something usefull here
|
|
184
|
-
// for example a link to online docs about the error
|
|
185
|
-
console.log(
|
|
186
|
-
display.outdent +
|
|
187
|
-
theme.margin(fill(display.margin.length)) +
|
|
188
|
-
theme.code(fill(total - display.margin.length))
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
// print emtpy line
|
|
192
|
-
console.log('');
|
|
193
|
-
}
|
|
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 = 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
|
+
export const imbaPlugin = {
|
|
22
|
+
name: "imba",
|
|
23
|
+
async setup(build) {
|
|
24
|
+
|
|
25
|
+
// when there is import without file extension
|
|
26
|
+
build.onResolve({filter: /^.*[^.]{5}$/ }, ({ path, importer }) => {
|
|
27
|
+
|
|
28
|
+
let filename = path;
|
|
29
|
+
// resolve relative path
|
|
30
|
+
if (path.startsWith('.')) { filename = dir.resolve(dir.dirname(importer), filename) };
|
|
31
|
+
|
|
32
|
+
// assume that the file is .js
|
|
33
|
+
try { return {path: Bun.resolveSync(filename + '.js', '.')}}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// assume that the file is .mjs
|
|
36
|
+
try { return {path: Bun.resolveSync(filename + '.mjs', '.')}}
|
|
37
|
+
catch (error) {
|
|
38
|
+
// assume that the file is .cs
|
|
39
|
+
try { return {path: Bun.resolveSync(filename + '.cjs', '.')}}
|
|
40
|
+
catch (error) {
|
|
41
|
+
// assume that the file is .imba
|
|
42
|
+
try { return {path: Bun.resolveSync(filename + '.imba', '.')}}
|
|
43
|
+
catch (error) {
|
|
44
|
+
// if direct resolution failed
|
|
45
|
+
filename += '.imba';
|
|
46
|
+
|
|
47
|
+
// assume that the relative path should be resolved relative to importer
|
|
48
|
+
let fn = dir.resolve(dir.dirname(importer), filename);
|
|
49
|
+
if (fs.existsSync(fn)) return {path: fn};
|
|
50
|
+
// assume that the relative path should be resolved relative to node_modules
|
|
51
|
+
fn = dir.resolve('./node_modules', filename);
|
|
52
|
+
if (fs.existsSync(fn)) return {path: fn};
|
|
53
|
+
// assume that the relative path should be resolved relative to project root
|
|
54
|
+
fn = dir.resolve(process.cwd(), filename);
|
|
55
|
+
if (fs.existsSync(fn)) return {path: fn};
|
|
56
|
+
|
|
57
|
+
// if the path still is unresolved throw error and leave the further resolution on Bun's resolver
|
|
58
|
+
if (error instanceof Error) {
|
|
59
|
+
throw new Error(error.message);
|
|
60
|
+
}
|
|
61
|
+
else
|
|
62
|
+
throw new Error('Could not resolve file: ' + path);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
// when an .imba file is imported...
|
|
70
|
+
build.onLoad({ filter: /\.imba$/ }, async ({ path }) => {
|
|
71
|
+
|
|
72
|
+
const f = dir.parse(path)
|
|
73
|
+
let contents = '';
|
|
74
|
+
|
|
75
|
+
// return the cached version if it exists
|
|
76
|
+
const cached = cache + Bun.hash(path) + '_' + fs.statSync(path).mtimeMs + '.js';
|
|
77
|
+
if (fs.existsSync(cached)) {
|
|
78
|
+
stats.bundled++;
|
|
79
|
+
stats.cached++;
|
|
80
|
+
//console.log(theme.action("cached: ") + theme.folder(f.dir + '/') + theme.filename(f.base) + " - " + theme.success("ok"));
|
|
81
|
+
return {
|
|
82
|
+
contents: await Bun.file(cached).text(),
|
|
83
|
+
loader: "js",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// clear previous cached version
|
|
88
|
+
const glob = new Glob(Bun.hash(path) + '_' + "*.js");
|
|
89
|
+
for await (const file of glob.scan(cache)) if (fs.existsSync(cache + file)) unlink(cache + file);
|
|
90
|
+
|
|
91
|
+
// if no cached version read and compile it with the imba compiler
|
|
92
|
+
const file = await Bun.file(path).text();
|
|
93
|
+
const out = compiler.compile(file, {
|
|
94
|
+
sourcePath: path,
|
|
95
|
+
platform: 'browser'
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
// print about file complitaion
|
|
99
|
+
console.write(theme.action("compiling: ") + theme.folder(f.dir + '/') + theme.filename(f.base) + " - ");
|
|
100
|
+
|
|
101
|
+
// the file has been successfully compiled
|
|
102
|
+
if (!out.errors || !out.errors.length) {
|
|
103
|
+
stats.bundled++;
|
|
104
|
+
stats.compiled++;
|
|
105
|
+
contents = out.js;
|
|
106
|
+
await Bun.write(cached, contents);
|
|
107
|
+
console.write(theme.success("cached" + "\n"));
|
|
108
|
+
}
|
|
109
|
+
// there were errors during compilation
|
|
110
|
+
else {
|
|
111
|
+
console.write(theme.failure(" fail ") + "\n");
|
|
112
|
+
stats.failed++;
|
|
113
|
+
for (let i = 0; i < out.errors.length; i++) {
|
|
114
|
+
if(out.errors[i]) printerr(out.errors[i]);
|
|
115
|
+
}
|
|
116
|
+
stats.errors++;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// and return the compiled source code as "js"
|
|
120
|
+
return {
|
|
121
|
+
contents,
|
|
122
|
+
loader: "js",
|
|
123
|
+
};
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
|
|
128
|
+
plugin(imbaPlugin);
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
// -------------------------------------------------------------------------------
|
|
132
|
+
// print pretty messages produced by the imba compiler
|
|
133
|
+
// -------------------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
// print an error generated by the imba compiler
|
|
136
|
+
function printerr(err) {
|
|
137
|
+
|
|
138
|
+
// halper function to produce empty strings
|
|
139
|
+
const fill = (len = 0) => {return new Array(len + 1).join(' ')}
|
|
140
|
+
|
|
141
|
+
// gather the needed information from the compiler error
|
|
142
|
+
const snippet = err.toSnippet().split("\n");
|
|
143
|
+
const display = {
|
|
144
|
+
error: " " + err.message + " ",
|
|
145
|
+
outdent: fill(10),
|
|
146
|
+
source: snippet[1] + " ",
|
|
147
|
+
margin: " line " + err.range.start.line + " ",
|
|
148
|
+
errs: snippet[2].indexOf('^'),
|
|
149
|
+
erre: snippet[2].lastIndexOf('^') + 1,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
// calculate parameters for priniting a message
|
|
153
|
+
const center = display.margin.length + display.errs + Math.floor((display.erre - display.errs) / 2);
|
|
154
|
+
const half = Math.ceil((display.error.length - 1) / 2);
|
|
155
|
+
const start = Math.max(0, center - half);
|
|
156
|
+
const end = start + display.error.length;
|
|
157
|
+
const total = Math.max(display.margin.length + display.source.length, end);
|
|
158
|
+
|
|
159
|
+
// print emtpy line
|
|
160
|
+
console.log('');
|
|
161
|
+
|
|
162
|
+
// print line with the error message
|
|
163
|
+
console.log(
|
|
164
|
+
display.outdent +
|
|
165
|
+
theme.margin(fill(Math.min(start, display.margin.length))) +
|
|
166
|
+
theme.code(fill(Math.max(0, start - display.margin.length))) +
|
|
167
|
+
theme.error(display.error) +
|
|
168
|
+
theme.margin(fill(Math.max(0, display.margin.length - end))) +
|
|
169
|
+
theme.code(fill(Math.min(total - display.margin.length, total - end)))
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
// print line with the source code
|
|
173
|
+
console.log(
|
|
174
|
+
display.outdent +
|
|
175
|
+
theme.margin(display.margin) +
|
|
176
|
+
theme.code(display.source.slice(0,display.errs)) +
|
|
177
|
+
theme.error(display.source.slice(display.errs,display.erre)) +
|
|
178
|
+
theme.code(display.source.slice(display.erre)) +
|
|
179
|
+
theme.code(fill(total - display.source.length - display.margin.length))
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
// print empty line to balance the view
|
|
183
|
+
// later we can put something usefull here
|
|
184
|
+
// for example a link to online docs about the error
|
|
185
|
+
console.log(
|
|
186
|
+
display.outdent +
|
|
187
|
+
theme.margin(fill(display.margin.length)) +
|
|
188
|
+
theme.code(fill(total - display.margin.length))
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
// print emtpy line
|
|
192
|
+
console.log('');
|
|
193
|
+
}
|
package/utils.js
CHANGED
|
@@ -1,30 +1,30 @@
|
|
|
1
|
-
function colorize(text, fg, bg) {
|
|
2
|
-
let result = ''
|
|
3
|
-
if(fg) result += "\x1b[38;5;" + fg.toString() + "m"
|
|
4
|
-
if(bg) result += "\x1b[48;5;" + bg.toString() + "m"
|
|
5
|
-
result += text
|
|
6
|
-
if(fg || bg) result += "\x1b[0m"
|
|
7
|
-
return result
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// theme for messages printed in terminal
|
|
11
|
-
// https://i.stack.imgur.com/KTSQa.png
|
|
12
|
-
export const theme = {
|
|
13
|
-
code: (text) => colorize(text, 252, 238),
|
|
14
|
-
margin: (text) => colorize(text, 229, 145),
|
|
15
|
-
error: (text) => colorize(text, 196 , 52),
|
|
16
|
-
ecode: (text) => colorize(text, 196, 238),
|
|
17
|
-
action: (text) => colorize(text, 237),
|
|
18
|
-
folder: (text) => colorize(text, 240),
|
|
19
|
-
filename: (text) => colorize(text, 15),
|
|
20
|
-
success: (text) => colorize(text, 40),
|
|
21
|
-
failure: (text) => colorize(text, 15, 124),
|
|
22
|
-
|
|
23
|
-
flags: (text) => colorize(text, 5),
|
|
24
|
-
count: (text) => colorize(text, 15),
|
|
25
|
-
start: (text) => colorize(text, 252, 233),
|
|
26
|
-
filedir: (text) => colorize(text, 15),
|
|
27
|
-
time: (text) => colorize(text, 41),
|
|
28
|
-
link: (text) => colorize(text, 15),
|
|
29
|
-
online: (text) => colorize(text, 40, 22)
|
|
1
|
+
function colorize(text, fg, bg) {
|
|
2
|
+
let result = ''
|
|
3
|
+
if(fg) result += "\x1b[38;5;" + fg.toString() + "m"
|
|
4
|
+
if(bg) result += "\x1b[48;5;" + bg.toString() + "m"
|
|
5
|
+
result += text
|
|
6
|
+
if(fg || bg) result += "\x1b[0m"
|
|
7
|
+
return result
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// theme for messages printed in terminal
|
|
11
|
+
// https://i.stack.imgur.com/KTSQa.png
|
|
12
|
+
export const theme = {
|
|
13
|
+
code: (text) => colorize(text, 252, 238),
|
|
14
|
+
margin: (text) => colorize(text, 229, 145),
|
|
15
|
+
error: (text) => colorize(text, 196 , 52),
|
|
16
|
+
ecode: (text) => colorize(text, 196, 238),
|
|
17
|
+
action: (text) => colorize(text, 237),
|
|
18
|
+
folder: (text) => colorize(text, 240),
|
|
19
|
+
filename: (text) => colorize(text, 15),
|
|
20
|
+
success: (text) => colorize(text, 40),
|
|
21
|
+
failure: (text) => colorize(text, 15, 124),
|
|
22
|
+
|
|
23
|
+
flags: (text) => colorize(text, 5),
|
|
24
|
+
count: (text) => colorize(text, 15),
|
|
25
|
+
start: (text) => colorize(text, 252, 233),
|
|
26
|
+
filedir: (text) => colorize(text, 15),
|
|
27
|
+
time: (text) => colorize(text, 41),
|
|
28
|
+
link: (text) => colorize(text, 15),
|
|
29
|
+
online: (text) => colorize(text, 40, 22)
|
|
30
30
|
}
|