bscript-cli 1.0.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 (47) hide show
  1. package/BScript.js +233 -0
  2. package/Docs/BScript/BSCRIPT-REFERENCE-CLI.md +502 -0
  3. package/Docs/Images/BScript-baner.png +0 -0
  4. package/Docs/Images/BooleanType.png +0 -0
  5. package/Docs/Images/FuncionType.png +0 -0
  6. package/Docs/Images/Logo.png +0 -0
  7. package/Docs/Images/NumberType.png +0 -0
  8. package/Docs/Images/ObjectType.png +0 -0
  9. package/Docs/Images/PromiseType.png +0 -0
  10. package/Docs/Images/RawType.png +0 -0
  11. package/Docs/Images/RefType.png +0 -0
  12. package/Docs/Images/TextType.png +0 -0
  13. package/Docs/README.md +157 -0
  14. package/Docs/REFERENCE.md +602 -0
  15. package/Docs/TECHNICAL.md +1143 -0
  16. package/Docs/TUTORIAL.md +604 -0
  17. package/SRC/BScriptHistory.js +98 -0
  18. package/SRC/CMDPermissions.js +4 -0
  19. package/SRC/utils/utils.js +63 -0
  20. package/TerminalCommandController.js +193 -0
  21. package/bin/bscript.js +94 -0
  22. package/commands/.default/BScript/$arg.js +9 -0
  23. package/commands/.default/BScript/$val.js +19 -0
  24. package/commands/.default/BScript/Input.js +10 -0
  25. package/commands/.default/BScript/bool.js +9 -0
  26. package/commands/.default/BScript/delay.js +10 -0
  27. package/commands/.default/BScript/eval.js +9 -0
  28. package/commands/.default/BScript/import.js +17 -0
  29. package/commands/.default/BScript/js_new.js +9 -0
  30. package/commands/.default/BScript/js_require.js +9 -0
  31. package/commands/.default/BScript/jstype.js +9 -0
  32. package/commands/.default/BScript/num.js +9 -0
  33. package/commands/.default/BScript/object.js +19 -0
  34. package/commands/.default/BScript/print.js +9 -0
  35. package/commands/.default/BScript/raw.js +9 -0
  36. package/commands/.default/BScript/ref.js +65 -0
  37. package/commands/.default/BScript/run-with-await.js +13 -0
  38. package/commands/.default/BScript/run.js +11 -0
  39. package/commands/.default/BScript/script.js +13 -0
  40. package/commands/.default/BScript/str.js +9 -0
  41. package/commands/.default/DebugOnly/clear.js +8 -0
  42. package/commands/.default/DebugOnly/update-commands.js +8 -0
  43. package/commands/.default/help.js +20 -0
  44. package/commands/snapshot.md +421 -0
  45. package/index.js +8 -0
  46. package/package.json +12 -0
  47. package/postinstall.js +12 -0
@@ -0,0 +1,604 @@
1
+ # Getting Started
2
+
3
+ Practical step-by-step guide for installing, configuring, and using BScript to build interactive command-line applications.
4
+
5
+ This guide focuses on real-world usage with complete examples. Detailed API information is available in **REFERENCE.md**.
6
+
7
+ ---
8
+
9
+ ## Contents
10
+
11
+ - [1. Installation](#1-installation)
12
+ - [2. Importing the package](#2-importing-the-package)
13
+ - [3. Initial setup](#3-initial-setup)
14
+ - [4. Core usage scenarios](#4-core-usage-scenarios)
15
+ - [5. Useful examples](#5-useful-examples)
16
+ - [6. Best practices](#6-best-practices)
17
+ - [See also](#see-also)
18
+
19
+ ---
20
+
21
+ <a id="1-installation"></a>
22
+
23
+ ## 1. Installation
24
+
25
+ ### npm
26
+
27
+ ```bash
28
+ npm install bscript
29
+ ```
30
+
31
+ ### pnpm
32
+
33
+ ```bash
34
+ pnpm add bscript
35
+ ```
36
+
37
+ ### yarn
38
+
39
+ ```bash
40
+ yarn add bscript
41
+ ```
42
+
43
+ ---
44
+
45
+ <a id="2-importing-the-package"></a>
46
+
47
+ ## 2. Importing the package
48
+
49
+ ### CommonJS
50
+
51
+ ```javascript
52
+ const BScript = require("bscript");
53
+ ```
54
+
55
+ ### ES Modules
56
+
57
+ ```javascript
58
+ import BScript from "bscript";
59
+ ```
60
+
61
+ or
62
+
63
+ ```javascript
64
+ import { BScript } from "bscript";
65
+ ```
66
+
67
+ ---
68
+
69
+ <a id="3-initial-setup"></a>
70
+
71
+ ## 3. Initial setup
72
+
73
+ ### Basic Initialization
74
+
75
+ ```javascript
76
+ const BScript = require("bscript");
77
+
78
+ const cmd = new BScript({
79
+ commandsPaths: ["./commands"],
80
+ cmdRootPermissions: [0] // default permission level
81
+ });
82
+
83
+ cmd.updateCommands();
84
+ ```
85
+
86
+ ### Description
87
+
88
+ When you create a new BScript instance, you're initializing an interactive command-line environment. The constructor accepts:
89
+
90
+ - **commandsPaths**: Array of directories to scan for command files
91
+ - **cmdRootPermissions**: Permission levels that determine which commands are available
92
+ - **cmdPermissionsHistory**: Initial permission stack for nested contexts
93
+
94
+ After configuration, call `updateCommands()` to load all command files from specified directories. BScript scans recursively and filters commands based on your permission settings.
95
+
96
+ ---
97
+
98
+ <a id="4-core-usage-scenarios"></a>
99
+
100
+ ## 4. Core usage scenarios
101
+
102
+ ### 4.1 Starting Interactive Mode
103
+
104
+ Start a fully-featured interactive command-line interface.
105
+
106
+ ```javascript
107
+ const BScript = require("bscript");
108
+
109
+ const cmd = new BScript();
110
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.default];
111
+ cmd.updateCommands();
112
+
113
+ // Begin interactive mode with prompt
114
+ cmd.Start();
115
+ ```
116
+
117
+ ### Output
118
+
119
+ ```
120
+ <help>? echo "Welcome to BScript"
121
+ > Welcome to BScript
122
+ <help>? help
123
+ ```
124
+
125
+ ---
126
+
127
+ ### 4.2 Executing Scripts from Code
128
+
129
+ Execute BScript code programmatically without interactive mode.
130
+
131
+ ```javascript
132
+ const BScript = require("bscript");
133
+
134
+ const cmd = new BScript();
135
+ cmd.cmdRootPermissions = [
136
+ cmd.perrmissionsKeys.default,
137
+ cmd.perrmissionsKeys.script
138
+ ];
139
+ cmd.updateCommands();
140
+
141
+ // Execute inline script
142
+ const scriptFn = cmd.bscript('echo "Hello from script"');
143
+ scriptFn();
144
+ ```
145
+
146
+ ---
147
+
148
+ ### 4.3 Working with Permissions
149
+
150
+ Create different access levels for different users or contexts.
151
+
152
+ ```javascript
153
+ const BScript = require("bscript");
154
+
155
+ const cmd = new BScript({
156
+ perrmissionsKeys: {
157
+ default: 0,
158
+ admin: 100,
159
+ script: 999
160
+ }
161
+ });
162
+
163
+ // User mode - only default commands available
164
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.default];
165
+ cmd.updateCommands();
166
+ cmd.Start();
167
+
168
+ // Later: switch to admin mode
169
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.admin];
170
+ cmd.updateCommands();
171
+ ```
172
+
173
+ ---
174
+
175
+ ### 4.4 Loading Commands from Multiple Directories
176
+
177
+ Organize commands in separate folders and load them all.
178
+
179
+ ```javascript
180
+ const BScript = require("bscript");
181
+
182
+ const cmd = new BScript({
183
+ commandsPaths: [
184
+ "./built-in-commands",
185
+ "./user-commands",
186
+ "./admin-commands"
187
+ ]
188
+ });
189
+
190
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.default];
191
+ cmd.updateCommands();
192
+ cmd.Start();
193
+ ```
194
+
195
+ ---
196
+
197
+ ### 4.5 Adding Commands Programmatically
198
+
199
+ Register commands without creating files.
200
+
201
+ ```javascript
202
+ const BScript = require("bscript");
203
+
204
+ const cmd = new BScript();
205
+
206
+ // Add a simple echo command
207
+ cmd.createCommand({
208
+ name: "echo",
209
+ description: "Echo text to console",
210
+ syntax: "echo [text...]",
211
+ execute: (args) => {
212
+ console.log(args.join(" "));
213
+ }
214
+ });
215
+
216
+ // Add a math command
217
+ cmd.createCommand({
218
+ name: "add",
219
+ description: "Add numbers",
220
+ syntax: "add [number1] [number2] ...",
221
+ execute: (args) => {
222
+ const sum = args.reduce((a, b) => a + parseFloat(b), 0);
223
+ console.log("Result:", sum);
224
+ }
225
+ });
226
+
227
+ cmd.Start();
228
+ ```
229
+
230
+ ### Expected output
231
+
232
+ ```
233
+ <help>? add 5 10 15
234
+ Result: 30
235
+ <help>? echo Hello World
236
+ Hello World
237
+ ```
238
+
239
+ ---
240
+
241
+ ### 4.6 Using the Loader Animation
242
+
243
+ Display loading animation while executing async operations.
244
+
245
+ ```javascript
246
+ const BScript = require("bscript");
247
+
248
+ const cmd = new BScript();
249
+
250
+ cmd.createCommand({
251
+ name: "fetch-data",
252
+ description: "Fetch data with loading animation",
253
+ execute: () => {
254
+ cmd.loader(async (done, waitForPromise, startAnimation) => {
255
+ // Perform async work
256
+ const result = await waitForPromise(async () => {
257
+ return new Promise(resolve => {
258
+ setTimeout(() => {
259
+ resolve("Data loaded successfully!");
260
+ }, 3000);
261
+ });
262
+ });
263
+
264
+ console.log(result);
265
+ done();
266
+ });
267
+ }
268
+ });
269
+
270
+ cmd.Start();
271
+ ```
272
+
273
+ ### Output
274
+
275
+ ```
276
+ <help>? fetch-data
277
+ Loading...
278
+ Data loaded successfully!
279
+ ```
280
+
281
+ ---
282
+
283
+ <a id="5-useful-examples"></a>
284
+
285
+ ## 5. Useful Examples
286
+
287
+ ### Example 1 — Complete CLI Application
288
+
289
+ Build a complete calculator CLI with multiple commands and permissions.
290
+
291
+ ```javascript
292
+ const BScript = require("bscript");
293
+
294
+ const cmd = new BScript({
295
+ perrmissionsKeys: {
296
+ default: 0,
297
+ admin: 100
298
+ }
299
+ });
300
+
301
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.default];
302
+
303
+ // Basic math commands
304
+ cmd.createCommand({
305
+ name: "add",
306
+ description: "Add numbers: add 2 3 4",
307
+ execute: (args) => {
308
+ const result = args.reduce((a, b) => a + parseFloat(b), 0);
309
+ console.log(`Result: ${result}`);
310
+ }
311
+ });
312
+
313
+ cmd.createCommand({
314
+ name: "multiply",
315
+ description: "Multiply numbers: multiply 2 3 4",
316
+ execute: (args) => {
317
+ const result = args.reduce((a, b) => a * parseFloat(b), 1);
318
+ console.log(`Result: ${result}`);
319
+ }
320
+ });
321
+
322
+ // Admin-only command
323
+ cmd.createCommand({
324
+ name: "admin-reset",
325
+ description: "Reset calculator",
326
+ perms: [cmd.perrmissionsKeys.admin],
327
+ execute: () => {
328
+ console.log("Calculator reset");
329
+ }
330
+ });
331
+
332
+ cmd.updateCommands();
333
+ cmd.Start();
334
+ ```
335
+
336
+ ### Expected output
337
+
338
+ ```
339
+ <help>? add 10 20 30
340
+ Result: 60
341
+ <help>? multiply 2 5 3
342
+ Result: 30
343
+ <help>? admin-reset
344
+ [command not found - permissions required]
345
+ <help>?
346
+ ```
347
+
348
+ ---
349
+
350
+ ### Example 2 — Multi-Role Access Control
351
+
352
+ Create an application with different user roles and permissions.
353
+
354
+ ```javascript
355
+ const BScript = require("bscript");
356
+
357
+ const cmd = new BScript({
358
+ perrmissionsKeys: {
359
+ guest: 0,
360
+ user: 50,
361
+ moderator: 100,
362
+ admin: 999
363
+ }
364
+ });
365
+
366
+ // Set initial role
367
+ let currentRole = "guest";
368
+
369
+ cmd.createCommand({
370
+ name: "status",
371
+ description: "Show current role",
372
+ perms: [cmd.perrmissionsKeys.guest], // Available to all
373
+ execute: () => {
374
+ console.log(`Current role: ${currentRole}`);
375
+ }
376
+ });
377
+
378
+ cmd.createCommand({
379
+ name: "upload",
380
+ description: "Upload a file",
381
+ perms: [cmd.perrmissionsKeys.user], // User and above
382
+ execute: (args) => {
383
+ console.log(`Uploading file: ${args[0]}`);
384
+ }
385
+ });
386
+
387
+ cmd.createCommand({
388
+ name: "ban-user",
389
+ description: "Ban a user",
390
+ perms: [cmd.perrmissionsKeys.moderator], // Moderator and above
391
+ execute: (args) => {
392
+ console.log(`Banned user: ${args[0]}`);
393
+ }
394
+ });
395
+
396
+ cmd.createCommand({
397
+ name: "login",
398
+ description: "Login as user",
399
+ perms: [cmd.perrmissionsKeys.guest],
400
+ execute: (args) => {
401
+ if (args[0] === "admin" && args[1] === "password") {
402
+ currentRole = "admin";
403
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.admin];
404
+ console.log("Logged in as admin");
405
+ } else {
406
+ currentRole = "user";
407
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.user];
408
+ console.log("Logged in as user");
409
+ }
410
+ cmd.updateCommands();
411
+ }
412
+ });
413
+
414
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.guest];
415
+ cmd.updateCommands();
416
+ cmd.Start();
417
+ ```
418
+
419
+ ---
420
+
421
+ ### Example 3 — Script File Execution
422
+
423
+ Execute a BScript file from the command line.
424
+
425
+ **my-script.js:**
426
+ ```javascript
427
+ echo "Script execution started"
428
+ echo "Running calculations..."
429
+ add 5 10
430
+ echo "Done!"
431
+ ```
432
+
433
+ **main.js:**
434
+ ```javascript
435
+ const BScript = require("bscript");
436
+
437
+ const cmd = new BScript();
438
+ cmd.cmdRootPermissions = [
439
+ cmd.perrmissionsKeys.default,
440
+ cmd.perrmissionsKeys.script
441
+ ];
442
+ cmd.updateCommands();
443
+
444
+ // Execute script file
445
+ const scriptFn = cmd.bscript("script my-script.js");
446
+ scriptFn();
447
+ ```
448
+
449
+ ### Run from terminal:
450
+
451
+ ```bash
452
+ node main.js
453
+ ```
454
+
455
+ ### Expected output:
456
+
457
+ ```
458
+ Script execution started
459
+ Running calculations...
460
+ [result of add 5 10]
461
+ Done!
462
+ ```
463
+
464
+ ---
465
+
466
+ <a id="6-best-practices"></a>
467
+
468
+ ## 6. Best practices
469
+
470
+ ### 1. Organize Commands in Separate Files
471
+
472
+ Instead of creating commands in code, create `.js` files in a commands directory:
473
+
474
+ **commands/echo.js:**
475
+ ```javascript
476
+ module.exports = {
477
+ name: "echo",
478
+ description: "Echo text",
479
+ syntax: "echo [text...]",
480
+ execute: (args) => {
481
+ console.log(args.join(" "));
482
+ }
483
+ };
484
+ ```
485
+
486
+ **commands/math/add.js:**
487
+ ```javascript
488
+ module.exports = {
489
+ name: "add",
490
+ description: "Add numbers",
491
+ syntax: "add [num1] [num2] ...",
492
+ execute: (args) => {
493
+ const sum = args.reduce((a, b) => a + parseFloat(b), 0);
494
+ console.log(sum);
495
+ },
496
+ perms: [0] // Available to default permission level
497
+ };
498
+ ```
499
+
500
+ ### 2. Use Permissions Consistently
501
+
502
+ Define permission levels early and use them consistently:
503
+
504
+ ```javascript
505
+ const cmd = new BScript({
506
+ perrmissionsKeys: {
507
+ public: 0,
508
+ authenticated: 50,
509
+ admin: 100
510
+ }
511
+ });
512
+ ```
513
+
514
+ ### 3. Handle Errors Gracefully
515
+
516
+ Always validate arguments and provide helpful error messages:
517
+
518
+ ```javascript
519
+ cmd.createCommand({
520
+ name: "divide",
521
+ execute: (args) => {
522
+ if (args.length < 2) {
523
+ console.error("divide: requires 2 arguments");
524
+ return;
525
+ }
526
+ const [a, b] = args.map(parseFloat);
527
+ if (b === 0) {
528
+ console.error("divide: cannot divide by zero");
529
+ return;
530
+ }
531
+ console.log(a / b);
532
+ }
533
+ });
534
+ ```
535
+
536
+ ### 4. Use Command Metadata
537
+
538
+ Provide description and syntax for every command:
539
+
540
+ ```javascript
541
+ cmd.createCommand({
542
+ name: "user-info",
543
+ description: "Display user information",
544
+ syntax: "user-info [username]",
545
+ execute: (args) => {
546
+ // Implementation
547
+ }
548
+ });
549
+ ```
550
+
551
+ ### 5. Leverage async/await with Loader
552
+
553
+ Provide visual feedback for long-running operations:
554
+
555
+ ```javascript
556
+ cmd.createCommand({
557
+ name: "process-data",
558
+ execute: () => {
559
+ cmd.loader(async (done) => {
560
+ const result = await processLargeDataset();
561
+ console.log("Processing complete:", result);
562
+ done();
563
+ });
564
+ }
565
+ });
566
+ ```
567
+
568
+ ### 6. Keep Command Loading Idempotent
569
+
570
+ Ensure `updateCommands()` can be called multiple times safely:
571
+
572
+ ```javascript
573
+ // Safe to call after permission changes
574
+ cmd.cmdRootPermissions = [cmd.perrmissionsKeys.admin];
575
+ cmd.updateCommands(); // Re-loads commands with new permissions
576
+ ```
577
+
578
+ ### 7. Use Command Aliases for Common Commands
579
+
580
+ Support multiple names for a single command:
581
+
582
+ ```javascript
583
+ module.exports = {
584
+ name: ["exit", "quit", "q"], // Multiple aliases
585
+ description: "Exit the application",
586
+ execute: () => {
587
+ process.exit(0);
588
+ }
589
+ };
590
+ ```
591
+
592
+ ---
593
+
594
+ <a id="see-also"></a>
595
+
596
+ ## See also
597
+
598
+ - **[REFERENCE.md](./REFERENCE.md)** — Complete API documentation
599
+ - **[TECHNICAL.md](./TECHNICAL.md)** — Internal architecture
600
+ - **[README.md](./README.md)** — Project overview
601
+
602
+ ---
603
+
604
+ **Made with ❤️ for the Node.js ecosystem**
@@ -0,0 +1,98 @@
1
+ const fs = require("fs");
2
+ const os = require("os");
3
+ const path = require("path");
4
+
5
+ module.exports = class BScriptHistory {
6
+ constructor(filePath = path.join(os.homedir(), ".bscript_history")) {
7
+ this.filePath = filePath;
8
+ this.history = [];
9
+ this.index = 0;
10
+
11
+ this.load();
12
+ }
13
+
14
+ load() {
15
+ if (!fs.existsSync(this.filePath)) {
16
+ fs.writeFileSync(this.filePath, "", "utf8");
17
+ return;
18
+ }
19
+
20
+ const content = fs.readFileSync(this.filePath, "utf8");
21
+
22
+ this.history = content
23
+ .split("\n")
24
+ .map(x => x.trim())
25
+ .filter(Boolean);
26
+
27
+ this.index = this.history.length;
28
+ }
29
+
30
+ save() {
31
+ fs.writeFileSync(
32
+ this.filePath,
33
+ this.history.join("\n"),
34
+ "utf8"
35
+ );
36
+ }
37
+
38
+ add(command) {
39
+ if (!command?.trim())
40
+ return;
41
+
42
+ if (this.history[this.history.length - 1] === command) {
43
+ this.index = this.history.length;
44
+ return;
45
+ }
46
+
47
+ this.history.push(command);
48
+ this.index = this.history.length;
49
+
50
+ this.save();
51
+ }
52
+
53
+ previous() {
54
+ if (this.index > 0)
55
+ this.index--;
56
+
57
+ return this.history[this.index] ?? "";
58
+ }
59
+
60
+ next() {
61
+ if (this.index < this.history.length)
62
+ this.index++;
63
+
64
+ return this.history[this.index] ?? "";
65
+ }
66
+
67
+ clear() {
68
+ this.history = [];
69
+ this.index = 0;
70
+
71
+ this.save();
72
+ }
73
+
74
+ remove(command) {
75
+ this.history = this.history.filter(x => x !== command);
76
+
77
+ if (this.index > this.history.length)
78
+ this.index = this.history.length;
79
+
80
+ this.save();
81
+ }
82
+
83
+ contains(command) {
84
+ return this.history.includes(command);
85
+ }
86
+
87
+ get(index) {
88
+ return this.history[index] ?? null;
89
+ }
90
+
91
+ getAll() {
92
+ return [...this.history];
93
+ }
94
+
95
+ get length() {
96
+ return this.history.length;
97
+ }
98
+ }
@@ -0,0 +1,4 @@
1
+ module.exports = {
2
+ script: 999,
3
+ default: 0
4
+ }