bimba-cli 0.1.9 → 0.2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/plugin.js +198 -193
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bimba-cli",
3
- "version": "0.1.9",
3
+ "version": "0.2.0",
4
4
  "repository": "github:HeapVoid/bimba",
5
5
  "module": "index.js",
6
6
  "bin": {
package/plugin.js CHANGED
@@ -1,193 +1,198 @@
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
- }
1
+ import { plugin } from "bun";
2
+ import {theme} from './utils.js';
3
+ import * as compiler from 'imba/compiler'
4
+ import {resolve, join, dirname, parse} from 'path'
5
+ import fs from 'fs'
6
+ import { Glob } from "bun";
7
+ import { unlink } from "node:fs/promises";
8
+
9
+ export const cache = 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
+ 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 = resolve(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 = resolve(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 = 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 = 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 = parse(path)
73
+ let contents = '';
74
+
75
+ // return the cached version if it exists
76
+ const path_hash = Bun.hash(path)
77
+ const time_hash = Bun.hash(fs.statSync(path).mtimeMs)
78
+ const cached = join(cache, path_hash + '_' + time_hash + '.js');
79
+ if (fs.existsSync(cached)) {
80
+ console.log('from cache')
81
+ stats.bundled++;
82
+ stats.cached++;
83
+ return {
84
+ contents: await Bun.file(cached).text(),
85
+ loader: "js",
86
+ };
87
+ }
88
+
89
+ // clear previous cached version
90
+ const glob = new Glob(path_hash + '_' + "*.js");
91
+ for await (const file of glob.scan(cache)) {
92
+ const prev_cached = join(cache, file);
93
+ if (fs.existsSync(prev_cached)) unlink(prev_cached);
94
+ }
95
+
96
+ // if no cached version read and compile it with the imba compiler
97
+ const file = await Bun.file(path).text();
98
+ const out = compiler.compile(file, {
99
+ sourcePath: path,
100
+ platform: 'browser'
101
+ })
102
+
103
+ // print about file complitaion
104
+ console.write(theme.action("compiling: ") + theme.folder(f.dir + '/') + theme.filename(f.base) + " - ");
105
+
106
+ // the file has been successfully compiled
107
+ if (!out.errors || !out.errors.length) {
108
+ stats.bundled++;
109
+ stats.compiled++;
110
+ contents = out.js;
111
+ await Bun.write(cached, contents);
112
+ console.write(theme.success("cached" + "\n"));
113
+ }
114
+ // there were errors during compilation
115
+ else {
116
+ console.write(theme.failure(" fail ") + "\n");
117
+ stats.failed++;
118
+ for (let i = 0; i < out.errors.length; i++) {
119
+ if(out.errors[i]) printerr(out.errors[i]);
120
+ }
121
+ stats.errors++;
122
+ }
123
+
124
+ // and return the compiled source code as "js"
125
+ return {
126
+ contents,
127
+ loader: "js",
128
+ };
129
+ });
130
+ }
131
+ };
132
+
133
+ plugin(imbaPlugin);
134
+
135
+
136
+ // -------------------------------------------------------------------------------
137
+ // print pretty messages produced by the imba compiler
138
+ // -------------------------------------------------------------------------------
139
+
140
+ // print an error generated by the imba compiler
141
+ function printerr(err) {
142
+
143
+ // halper function to produce empty strings
144
+ const fill = (len = 0) => {return new Array(len + 1).join(' ')}
145
+
146
+ // gather the needed information from the compiler error
147
+ const snippet = err.toSnippet().split("\n");
148
+ const display = {
149
+ error: " " + err.message + " ",
150
+ outdent: fill(10),
151
+ source: snippet[1] + " ",
152
+ margin: " line " + err.range.start.line + " ",
153
+ errs: snippet[2].indexOf('^'),
154
+ erre: snippet[2].lastIndexOf('^') + 1,
155
+ };
156
+
157
+ // calculate parameters for priniting a message
158
+ const center = display.margin.length + display.errs + Math.floor((display.erre - display.errs) / 2);
159
+ const half = Math.ceil((display.error.length - 1) / 2);
160
+ const start = Math.max(0, center - half);
161
+ const end = start + display.error.length;
162
+ const total = Math.max(display.margin.length + display.source.length, end);
163
+
164
+ // print emtpy line
165
+ console.log('');
166
+
167
+ // print line with the error message
168
+ console.log(
169
+ display.outdent +
170
+ theme.margin(fill(Math.min(start, display.margin.length))) +
171
+ theme.code(fill(Math.max(0, start - display.margin.length))) +
172
+ theme.error(display.error) +
173
+ theme.margin(fill(Math.max(0, display.margin.length - end))) +
174
+ theme.code(fill(Math.min(total - display.margin.length, total - end)))
175
+ );
176
+
177
+ // print line with the source code
178
+ console.log(
179
+ display.outdent +
180
+ theme.margin(display.margin) +
181
+ theme.code(display.source.slice(0,display.errs)) +
182
+ theme.error(display.source.slice(display.errs,display.erre)) +
183
+ theme.code(display.source.slice(display.erre)) +
184
+ theme.code(fill(total - display.source.length - display.margin.length))
185
+ );
186
+
187
+ // print empty line to balance the view
188
+ // later we can put something usefull here
189
+ // for example a link to online docs about the error
190
+ console.log(
191
+ display.outdent +
192
+ theme.margin(fill(display.margin.length)) +
193
+ theme.code(fill(total - display.margin.length))
194
+ );
195
+
196
+ // print emtpy line
197
+ console.log('');
198
+ }