vaderjs 1.5.9 → 1.6.1

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 CHANGED
@@ -2,7 +2,7 @@
2
2
  <a href="https://vader-js.pages.dev">
3
3
  <picture>
4
4
  <source media="(prefers-color-scheme: dark)" srcset="/icon.jpeg">
5
- <img src="./logo.png" height="128">
5
+ <img src="https://github.com/Postr-Inc/Vader.js/blob/main/logo.png" height="128">
6
6
  </picture>
7
7
  <h1 align="center">Vader.js</h1>
8
8
  </a>
@@ -16,7 +16,7 @@
16
16
  # Installation
17
17
 
18
18
  ```js
19
- npx vaderjs @latest
19
+ bun install vaderjs @latest
20
20
  ```
21
21
 
22
22
 
@@ -39,6 +39,7 @@ Keyword folders - all files are passed from these folders to the build folder
39
39
  ```md
40
40
  1. app - used for jsx route files
41
41
  2. public - used for anything / css / json etc
42
+ 3. Src - components utilities etc
42
43
  ```
43
44
 
44
45
 
@@ -53,4 +54,4 @@ export default defineConfig({
53
54
  hot_reload: true,
54
55
  })
55
56
 
56
- ```
57
+ ```
package/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
  # Installation
17
17
 
18
18
  ```js
19
- npx vaderjs @latest
19
+ bun install vaderjs @latest
20
20
  ```
21
21
 
22
22
  ```ts
package/bundler/index.js CHANGED
@@ -37,11 +37,10 @@ await Bun.build({
37
37
  entrypoints: [process.env.ENTRYPOINT],
38
38
  minify: false,
39
39
  root: process.cwd() + "/dist/",
40
- outdir: process.cwd() + "/dist/",
41
-
40
+ outdir: process.cwd() + "/dist/",
42
41
  format: "esm",
43
42
  ...(process.env.DEV ? { sourcemap: "inline" } : {}),
44
- external:['*.jsx', '*.js', '*.ts']
43
+ external:['*.jsx', '*.js', '*.ts', '*.tsx']
45
44
  });
46
45
 
47
46
  let builtCode = fs.readFileSync(path.join(process.cwd(), 'dist', process.env.filePath), 'utf-8')
@@ -54,8 +53,8 @@ function handleReplacements(code) {
54
53
  try {
55
54
  let url = line.includes("'") ? line.split("'")[1] : line.split('"')[1]
56
55
 
57
- line = line.replace(url, url.replace('.jsx', '.js'))
58
- line = line.replace(url, url.replace('.ts', '.js'))
56
+ line = line.replace(url, url.replace('.jsx', '.js').replace('.tsx', '.js'))
57
+ line = line.replace(url, url.replace('.ts', '.js').replace('.tsx', '.js'))
59
58
  newLines.push(line)
60
59
  } catch (error) {
61
60
  continue;
@@ -73,6 +72,7 @@ builtCode = handleReplacements(builtCode)
73
72
  fs.writeFileSync(path.join(process.cwd(), 'dist', process.env.filePath), builtCode)
74
73
  }
75
74
  let isClass = function (element) {
75
+ if (!element) return false;
76
76
  return element.toString().startsWith("class");
77
77
  };
78
78
  const generatePage = async (
@@ -84,6 +84,10 @@ const generatePage = async (
84
84
  let { head } = await import(path).then((m) => m);
85
85
  let isFunction = false;
86
86
  globalThis.isServer = true;
87
+ if(!html) {
88
+ console.log(ansiColors.red(`No default export found in ${path}`))
89
+ process.exit(0)
90
+ }
87
91
  if (isClass(html)) {
88
92
  html = new html();
89
93
  html.Mounted = true;
@@ -0,0 +1,10 @@
1
+ import { useState } from "vaderjs";
2
+ export default function App() {
3
+ let [count, setCount] = useState(0);
4
+ return (
5
+ <div>
6
+ <h1>{count()}</h1>
7
+ <button onClick={() => setCount(count() + 1)}>Increment</button>
8
+ </div>
9
+ );
10
+ }
package/index.ts CHANGED
@@ -193,6 +193,7 @@ export class Component {
193
193
  Mounted;
194
194
  effect;
195
195
  key;
196
+ effectCalls: any[]
196
197
  prevState;
197
198
  constructor() {
198
199
  this.key = crypto.randomUUID();
@@ -201,20 +202,66 @@ export class Component {
201
202
  this.effect = [];
202
203
  this.Mounted = false;
203
204
  this.element = null;
205
+ this.effectCalls = []
206
+ this.errorThreshold = 1000
207
+ this.maxIntervalCalls = 10
204
208
  }
205
209
  useEffect(callback, dependencies) {
210
+ const callbackId = callback.toString();
211
+
212
+ if (!this.effectCalls.some(s => s.id === callbackId)) {
213
+ this.effectCalls.push({ id: callbackId, count: 0, lastCall: Date.now() });
214
+ }
215
+
216
+ const effectCall = this.effectCalls.find(s => s.id === callbackId);
217
+
218
+ const executeCallback = () => {
219
+ const now = Date.now();
220
+ const timeSinceLastCall = now - effectCall.lastCall;
221
+
222
+ if (timeSinceLastCall < this.errorThreshold) {
223
+ effectCall.count += 1;
224
+ if (effectCall.count > this.maxIntervalCalls) {
225
+ throw new Error(`Woah wayy too many calls, ensure you are not overlooping you can change the maxThresholdCalls and errorThreshold depending on needs`)
226
+ }
227
+ } else {
228
+ effectCall.count = 1;
229
+ }
230
+
231
+ effectCall.lastCall = now;
232
+
233
+ setTimeout(() => {
234
+ try {
235
+ callback();
236
+ } catch (error) {
237
+ console.error(error);
238
+ }
239
+ }, 0);
240
+ };
241
+
206
242
  if (dependencies.length === 0 && this.Mounted && this.effect.length === 0) {
207
- callback();
208
- this.effect.push(callback);
243
+ executeCallback();
244
+ this.effect.push(callbackId);
209
245
  } else {
210
- for (let i = 0;i < dependencies.length; i++) {
211
- if (this.effect[i] !== dependencies[i]) {
212
- this.effect = dependencies;
213
- callback();
246
+ // Check if dependencies have changed
247
+ let dependenciesChanged = false;
248
+ if (dependencies.length !== this.effect.length) {
249
+ dependenciesChanged = true;
250
+ } else {
251
+ for (let i = 0; i < dependencies.length; i++) {
252
+ if (this.effect[i] !== dependencies[i]) {
253
+ dependenciesChanged = true;
254
+ break;
255
+ }
256
+ }
257
+ }
258
+
259
+ if (dependenciesChanged) {
260
+ this.effect = [...dependencies];
261
+ executeCallback();
214
262
  }
215
- }
216
263
  }
217
- }
264
+ }
218
265
  useState(key, defaultValue, persist = false) {
219
266
  if (typeof window === "undefined")
220
267
  return [defaultValue, () => {
@@ -233,8 +280,7 @@ export class Component {
233
280
  !persist && sessionStorage.removeItem("state_" + key);
234
281
  });
235
282
  }
236
- const setValue = (newValue) => {
237
- console.log("setting value", newValue);
283
+ const setValue = (newValue) => {
238
284
  sessionStorage.setItem("state_" + key, JSON.stringify({ value: newValue }));
239
285
  this.forceUpdate(this.key);
240
286
  };
@@ -274,7 +320,7 @@ export class Component {
274
320
  }
275
321
  Reconciler = {
276
322
  update: (oldElement, newElement) => {
277
-
323
+ if(!oldElement || !newElement) return;
278
324
  if (this.Reconciler.shouldUpdate(oldElement, newElement)) {
279
325
  let part = this.Reconciler.shouldUpdate(oldElement, newElement, true);
280
326
  if (part === true) {
package/main.js CHANGED
@@ -5,35 +5,47 @@ import { Glob } from 'bun'
5
5
  const args = Bun.argv.slice(2)
6
6
  import fs from 'fs'
7
7
  import path from 'path'
8
- if (!fs.existsSync(process.cwd() + '/app')) {
8
+ if (!fs.existsSync(process.cwd() + '/app') && !args.includes('init')) {
9
9
  console.error(`App directory not found in ${process.cwd()}/app`)
10
10
  process.exit(1)
11
11
  }
12
12
  if (!fs.existsSync(process.cwd() + '/public')) {
13
13
  fs.mkdirSync(process.cwd() + '/public')
14
14
  }
15
- if(!fs.existsSync(process.cwd() + '/src')){
15
+ if (!fs.existsSync(process.cwd() + '/src')) {
16
16
  fs.mkdirSync(process.cwd() + '/src')
17
17
  }
18
- if(!fs.existsSync(process.cwd() + '/vader.config.ts')){
19
- fs.writeFileSync(process.cwd() + '/vader.config.ts',
20
- `
21
- import defineConfig from 'vaderjs/config'
18
+ if (!fs.existsSync(process.cwd() + '/vader.config.ts')) {
19
+ fs.writeFileSync(process.cwd() + '/vader.config.ts',
20
+ `import defineConfig from 'vaderjs/config'
22
21
  export default defineConfig({
23
22
  port: 8080,
24
23
  host_provider: 'apache'
25
24
  })`)
26
25
  }
27
- const mode = args.includes('dev') ? 'development' : args.includes('prod') || args.includes('build') ? 'production' : null
26
+ const mode = args.includes('dev') ? 'development' : args.includes('prod') || args.includes('build') ? 'production' : args.includes('init') ? 'init' : null
28
27
  if (!mode) {
29
28
  console.log(`
30
29
  Usage:
31
30
  bun vaderjs dev - Start development server output in dist/
32
31
  bun vaderjs prod - Build for production output in dist/
32
+ bun vaderjs init - Initialize a new vaderjs project
33
33
  `)
34
34
  process.exit(1)
35
35
  }
36
36
 
37
+ if (mode === 'init') {
38
+ if (fs.existsSync(process.cwd() + '/app')) {
39
+ console.error('App directory already exists: just run `bun vaderjs dev` to start the development server')
40
+ process.exit(1)
41
+ }
42
+ fs.mkdirSync(process.cwd() + '/app')
43
+ fs.copyFileSync(path.join(process.cwd(), "/node_modules/vaderjs/example/counter/index.jsx"), path.join(process.cwd(), "/app/index.jsx"))
44
+
45
+ console.log('Initialized new vaderjs project: run `bun vaderjs dev` to start the development server')
46
+ procss.exit(1)
47
+ }
48
+
37
49
  console.log(
38
50
  `VaderJS - v${require(process.cwd() + '/node_modules/vaderjs/package.json').version} 🚀
39
51
  Mode: ${mode}
@@ -42,6 +54,8 @@ console.log(
42
54
  `
43
55
  )
44
56
 
57
+
58
+ console.log(ansiColors.green('Building...'))
45
59
  let start = Date.now()
46
60
  console.log(`Starting build at ${new Date().toLocaleTimeString()}`)
47
61
  let { port, host, host_provider } = require(process.cwd() + '/vader.config.ts').default
@@ -61,31 +75,31 @@ if (!fs.existsSync(process.cwd() + '/jsconfig.json')) {
61
75
 
62
76
  var bindes = []
63
77
 
64
- const handleReplacements = (code ) => {
78
+ const handleReplacements = (code) => {
65
79
  let lines = code.split('\n')
66
80
  let newLines = []
67
81
  for (let line of lines) {
68
82
  let hasImport = line.includes('import')
69
-
83
+
70
84
  if (hasImport && line.includes('.css')) {
71
85
  try {
72
- let isSmallColon = line.includes("'")
73
- let url = isSmallColon ? line.split("'")[1] : line.split('"')[1]
74
- // start from "/" not "/app"
75
- // remvoe all ./ and ../
76
- url = url.replaceAll('./', '/').replaceAll('../', '/')
77
-
78
- let p = path.join(process.cwd() , '/', url)
79
- line = '';
80
- url = url.replace(process.cwd() + '/app', '')
81
- url = url.replace(/\\/g, '/')
82
- if (!bindes.includes(`<link rel="stylesheet" href="${url}">`)) {
83
- bindes.push(`
86
+ let isSmallColon = line.includes("'")
87
+ let url = isSmallColon ? line.split("'")[1] : line.split('"')[1]
88
+ // start from "/" not "/app"
89
+ // remvoe all ./ and ../
90
+ url = url.replaceAll('./', '/').replaceAll('../', '/')
91
+
92
+ let p = path.join(process.cwd(), '/', url)
93
+ line = '';
94
+ url = url.replace(process.cwd() + '/app', '')
95
+ url = url.replace(/\\/g, '/')
96
+ if (!bindes.includes(`<link rel="stylesheet" href="${url}">`)) {
97
+ bindes.push(`
84
98
  <style>
85
99
  ${fs.readFileSync(p, 'utf-8')}
86
100
  </style>
87
101
  `)
88
- }
102
+ }
89
103
  } catch (error) {
90
104
  console.error(error)
91
105
  }
@@ -139,7 +153,7 @@ async function generateApp() {
139
153
  style: 'nextjs'
140
154
  })
141
155
  routes.reload()
142
- globalThis.routes = routes.routes
156
+ globalThis.routes = routes.routes
143
157
  Object.keys(routes.routes).forEach(async (route) => {
144
158
 
145
159
  let r = routes.routes[route]
@@ -147,13 +161,13 @@ async function generateApp() {
147
161
  code = handleReplacements(code)
148
162
  let size = code.length / 1024
149
163
  r = r.replace(process.cwd().replace(/\\/g, '/') + '/app', '')
150
- r = r.replace('.jsx', '.js')
164
+ r = r.replace('.jsx', '.js').replace('.tsx', '.js')
151
165
  fs.mkdirSync(path.dirname(process.cwd() + '/dist/' + r), { recursive: true })
152
166
  fs.writeFileSync(process.cwd() + '/dist/' + path.dirname(r) + '/' + path.basename(r), `
153
167
  let route = window.location.pathname.split('/').filter(v => v !== '')
154
168
  let params = {
155
169
  ${Object.keys(routes.match(route).params || {}).length > 0 ? Object.keys(routes.match(route).params || {}).map(p => {
156
- return `${p}: route[${Object.keys(routes.match(route).params).indexOf(p) + Object.keys(routes.match(route).params).length}]`
170
+ return `${p}: route[${Object.keys(routes.match(route).params).indexOf(p) + Object.keys(routes.match(route).params).length}]`
157
171
  }).join(',') : ""}
158
172
  }
159
173
  \n${code}
@@ -183,7 +197,7 @@ async function generateApp() {
183
197
  size,
184
198
  bindes: bindes.join('\n'),
185
199
  filePath: r,
186
- INPUT: `../app/${r.replace('.js', '.jsx')}`,
200
+ INPUT: `../app/${r.replace('.js', '.jsx').replace('.tsx', '.js')}`,
187
201
  },
188
202
  onExit({ exitCode: code }) {
189
203
  if (code === 0) {
@@ -205,8 +219,8 @@ async function generateApp() {
205
219
  rewrites: []
206
220
  }
207
221
 
208
- for (let route in routes.routes) {
209
- let { filePath, kind, name, params, pathname, query } = routes.match(route)
222
+ for (let route in routes.routes) {
223
+ let { filePath, kind, name, params, pathname, query } = routes.match(route)
210
224
  let r = route
211
225
 
212
226
  if (r.includes('[')) {
@@ -214,8 +228,8 @@ async function generateApp() {
214
228
  }
215
229
  if (r === '/') {
216
230
  continue
217
- }
218
-
231
+ }
232
+
219
233
  vercelData.rewrites.push({
220
234
  source: r,
221
235
  destination: `${path.dirname(routes.routes[route]).replace(process.cwd().replace(/\\/g, '/') + '/app', '')}/index.html`
@@ -224,6 +238,9 @@ async function generateApp() {
224
238
 
225
239
  fs.writeFileSync(process.cwd() + '/vercel.json', JSON.stringify(vercelData, null, 4))
226
240
  break;
241
+ case 'apache':
242
+ let data = ''
243
+
227
244
  }
228
245
 
229
246
  })
@@ -245,28 +262,28 @@ function handleFiles() {
245
262
  }
246
263
  let glob2 = new Glob('src/**/*')
247
264
  for await (var i of glob2.scan()) {
248
- var file = i
265
+ var file = i
249
266
  fs.mkdirSync(path.join(process.cwd() + '/dist', path.dirname(file)), { recursive: true })
250
- // turn jsx to js
251
- if (file.includes('.jsx')) {
267
+ // turn jsx to js
268
+ if (file.includes('.jsx') || file.includes('.tsx')) {
252
269
  let code = await Bun.file(file).text()
253
270
  code = handleReplacements(code)
254
-
255
- file = file.replace('.jsx', '.js')
256
- fs.writeFileSync(path.join(process.cwd() + '/dist', file.replace('.jsx', '.js')), code)
271
+
272
+ file = file.replace('.jsx', '.js').replace('.tsx', '.js')
273
+ fs.writeFileSync(path.join(process.cwd() + '/dist', file.replace('.jsx', '.js').replace('.tsx', '.js')), code)
257
274
  await Bun.spawn({
258
275
  cmd: ['bun', 'run', './dev/bundler.js'],
259
276
  cwd: process.cwd(),
260
277
  stdout: 'inherit',
261
278
  env: {
262
- ENTRYPOINT: path.join(process.cwd() + '/dist/' + file.replace('.jsx', '.js')),
279
+ ENTRYPOINT: path.join(process.cwd() + '/dist/' + file.replace('.jsx', '.js').replace('.tsx', '.js')),
263
280
  ROOT: process.cwd() + '/app/',
264
281
  OUT: path.dirname(file),
265
- file: process.cwd() + '/dist/' + file.replace('.jsx', '.js'),
282
+ file: process.cwd() + '/dist/' + file.replace('.jsx', '.js').replace('.tsx', '.js'),
266
283
  DEV: mode === 'development',
267
284
  size: code.length / 1024,
268
285
  filePath: file.replace('.jsx', '.js'),
269
- INPUT: path.join(process.cwd() , file.replace('.js', '.jsx')),
286
+ INPUT: path.join(process.cwd(), file.replace('.js', '.jsx').replace('.tsx', '.js')),
270
287
  },
271
288
  onExit({ exitCode: code }) {
272
289
  if (code === 0) {
@@ -276,7 +293,7 @@ function handleFiles() {
276
293
  }
277
294
  }
278
295
  })
279
- }else if(file.includes('.ts')){
296
+ } else if (file.includes('.ts')) {
280
297
  let code = await Bun.file(file).text()
281
298
  code = handleReplacements(code)
282
299
  file = file.replace('.ts', '.js')
@@ -294,7 +311,7 @@ function handleFiles() {
294
311
  isTS: true,
295
312
  size: code.length / 1024,
296
313
  filePath: file.replace('.ts', '.js'),
297
- INPUT: path.join(process.cwd() , file.replace('.js', '.jsx')),
314
+ INPUT: path.join(process.cwd(), file.replace('.js', '.jsx')),
298
315
  },
299
316
  onExit({ exitCode: code }) {
300
317
  if (code === 0) {
@@ -305,9 +322,9 @@ function handleFiles() {
305
322
  }
306
323
  })
307
324
  }
308
-
325
+
309
326
  }
310
-
327
+
311
328
  resolve()
312
329
  } catch (error) {
313
330
  reject(error)
@@ -318,7 +335,7 @@ await handleFiles()
318
335
  globalThis.clients = []
319
336
 
320
337
  if (mode === 'development') {
321
- const watcher = fs.watch(path.join(process.cwd() + '/'), { recursive: true })
338
+ const watcher = fs.watch(path.join(process.cwd() + '/'), { recursive: true })
322
339
  let isBuilding = false; // Flag to track build status
323
340
 
324
341
  // Initialize a variable to hold the timeout ID
@@ -326,33 +343,33 @@ if (mode === 'development') {
326
343
 
327
344
  // Function to handle file changes with debounce
328
345
  const handleFileChangeDebounced = async (change, file) => {
329
- if(file.endsWith('.tsx') || file.endsWith('.jsx') || file.endsWith('.css') || file.endsWith('.ts') ) {
330
- if(file.includes('dist')) return
346
+ if (file.endsWith('.tsx') || file.endsWith('.jsx') || file.endsWith('.css') || file.endsWith('.ts')) {
347
+ if (file.includes('dist')) return
331
348
  clearTimeout(debounceTimeout);
332
- debounceTimeout = setTimeout(async () => {
333
- if (!isBuilding) { // Check if not already building
334
- isBuilding = true; // Set build flag to true
335
- try {
336
- await generateApp();
337
- await handleFiles();
338
- let t = setTimeout(() => {
339
- clients.forEach(c => {
340
- c.send('reload');
341
- });
342
- clearTimeout(t)
343
- }, 1000)
344
- } catch (error) {
345
- console.error(error);
346
- } finally {
347
- isBuilding = false; // Reset build flag
349
+ debounceTimeout = setTimeout(async () => {
350
+ if (!isBuilding) { // Check if not already building
351
+ isBuilding = true; // Set build flag to true
352
+ try {
353
+ await generateApp();
354
+ await handleFiles();
355
+ let t = setTimeout(() => {
356
+ clients.forEach(c => {
357
+ c.send('reload');
358
+ });
359
+ clearTimeout(t)
360
+ }, 1000)
361
+ } catch (error) {
362
+ console.error(error);
363
+ } finally {
364
+ isBuilding = false; // Reset build flag
365
+ }
348
366
  }
349
- }
350
- }, 500);
367
+ }, 500);
351
368
  }
352
369
  };
353
370
 
354
371
  // Event listeners with debounced handling
355
- watcher.on('change', handleFileChangeDebounced);
372
+ watcher.on('change', handleFileChangeDebounced);
356
373
  let server = Bun.serve({
357
374
  port: port || 8080,
358
375
  websocket: {
@@ -374,11 +391,11 @@ if (mode === 'development') {
374
391
 
375
392
  let url = new URL(req.url)
376
393
  if (url.pathname.includes('.')) {
377
- let p = url.pathname.replaceAll("%5B", "[").replaceAll("%5D", "]")
394
+ let p = url.pathname.replaceAll("%5B", "[").replaceAll("%5D", "]")
378
395
  let file = await Bun.file(path.join(process.cwd() + '/dist' + p))
379
396
  if (!await file.exists()) return new Response('Not found', { status: 404 })
380
397
  let imageTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/svg+xml', 'image/webp', 'image/tiff', 'image/bmp', 'image/ico', 'image/cur', 'image/jxr', 'image/jpg']
381
-
398
+
382
399
  return new Response(imageTypes.includes(file.type) ? await file.arrayBuffer() : await file.text(), {
383
400
  headers: {
384
401
  'Content-Type': file.type,
@@ -399,9 +416,9 @@ if (mode === 'development') {
399
416
  let p = route.pathname;
400
417
  let base = path.dirname(route.filePath)
401
418
  base = base.replace(/\\/g, '/')
402
- base = base.replace(path.join(process.cwd() + '/app').replace(/\\/g, '/'), '')
419
+ base = base.replace(path.join(process.cwd() + '/app').replace(/\\/g, '/'), '')
403
420
  base = base.replace(/\\/g, '/').replace('/app', '/dist')
404
- base = process.cwd() + "/dist/" + base
421
+ base = process.cwd() + "/dist/" + base
405
422
  let data = await Bun.file(path.join(base, 'index.html')).text()
406
423
  if (mode == "development") {
407
424
  return new Response(data + `
@@ -414,9 +431,9 @@ if (mode === 'development') {
414
431
  }
415
432
  </script>
416
433
  `, {
417
- headers:{
418
- 'Content-Type': 'text/html'
419
- }
434
+ headers: {
435
+ 'Content-Type': 'text/html'
436
+ }
420
437
  })
421
438
  } else {
422
439
  return new Response(data, {
@@ -431,4 +448,6 @@ if (mode === 'development') {
431
448
  } else {
432
449
  console.log(`Build complete in ${Date.now() - start}ms at ${new Date().toLocaleTimeString()}`)
433
450
  process.exit(0)
434
- }
451
+ }
452
+
453
+ console.log(ansiColors.green('Server started at http://localhost:' + port || 8080))
package/package.json CHANGED
@@ -1,10 +1,14 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "1.5.9",
3
+ "version": "1.6.1",
4
4
  "description": "A simple and powerful JavaScript library for building modern web applications.",
5
5
  "bin": {
6
6
  "vaderjs": "./main.js"
7
7
  },
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/Postr-Inc/Vader.js"
11
+ },
8
12
  "dependencies": {
9
13
  "ansi-colors": "latest"
10
14
  }