starlight-cli 1.0.43 → 1.0.45
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 +222 -38
- package/dist/index.js +44 -22
- package/package.json +1 -1
- package/src/evaluator.js +44 -22
package/README.md
CHANGED
|
@@ -1,71 +1,255 @@
|
|
|
1
|
-
# Starlight Language
|
|
1
|
+
# Starlight Language
|
|
2
2
|
|
|
3
|
-
Starlight is a lightweight, developer-oriented programming language designed for server-side scripting, automation, and general-purpose programming
|
|
3
|
+
Starlight is a lightweight, developer-oriented programming language designed for **server-side scripting, automation, and general-purpose programming**. It combines a clean, readable syntax inspired by JavaScript and Python with powerful runtime features such as async/await, modules, and interactive I/O.
|
|
4
4
|
|
|
5
5
|
**Official Reference:** [https://starlight-learn-lang.pages.dev/](https://starlight-learn-lang.pages.dev/)
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
---
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
- Async/Await Support: Handle asynchronous operations cleanly.
|
|
11
|
-
- Modules & Imports: Use `import` to bring in libraries or other `.sl` files.
|
|
12
|
-
- Server-side Ready: Ideal for scripting, automation, and backend logic.
|
|
13
|
-
- Interactive Input: Built-in `ask` and `sldeploy` commands for user interaction.
|
|
14
|
-
- Built-in Utilities: `sleep(ms)`, `len()`, `keys()`, `values()`, `fetch()`, `get()`, `post()`.
|
|
9
|
+
## Key Features
|
|
15
10
|
|
|
16
|
-
|
|
11
|
+
* **Modern, Simple Syntax** – Familiar to JavaScript and Python developers
|
|
12
|
+
* **Async / Await** – Native support for asynchronous operations
|
|
13
|
+
* **Modules & Imports** – Import JavaScript packages or other `.sl` files
|
|
14
|
+
* **Server-side Ready** – Built on Node.js, ideal for backend logic
|
|
15
|
+
* **Interactive I/O** – Built-in `ask` and `sldeploy`
|
|
16
|
+
* **Built-in Utilities** – `sleep`, `len`, `keys`, `values`, `fetch`, `get`, `post`
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
2. Install via NPM:
|
|
18
|
+
---
|
|
20
19
|
|
|
21
|
-
|
|
22
|
-
npm install starlight-cli
|
|
23
|
-
\`\`\`
|
|
20
|
+
## Installation
|
|
24
21
|
|
|
25
|
-
|
|
22
|
+
1. Install **Node.js** (v18+ recommended)
|
|
23
|
+
2. Install Starlight CLI:
|
|
26
24
|
|
|
27
|
-
|
|
25
|
+
```
|
|
26
|
+
npm install -g starlight-cli
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Your First Program (`hello.sl`)
|
|
32
|
+
|
|
33
|
+
```
|
|
28
34
|
let name = ask("What is your name?")
|
|
29
|
-
sldeploy
|
|
30
|
-
|
|
35
|
+
sldeploy "Hello, " + name + "!"
|
|
36
|
+
```
|
|
31
37
|
|
|
32
38
|
Run:
|
|
33
39
|
|
|
34
|
-
|
|
40
|
+
```
|
|
35
41
|
starlight hello.sl
|
|
36
|
-
|
|
42
|
+
```
|
|
37
43
|
|
|
38
|
-
|
|
44
|
+
---
|
|
39
45
|
|
|
40
|
-
|
|
46
|
+
## Output
|
|
47
|
+
|
|
48
|
+
```
|
|
41
49
|
What is your name? Alice
|
|
42
50
|
Hello, Alice!
|
|
43
|
-
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Core Language Concepts
|
|
56
|
+
|
|
57
|
+
### Variables
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
let x = 10
|
|
61
|
+
let text = "hello"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### Functions
|
|
67
|
+
|
|
68
|
+
```
|
|
69
|
+
func add(a, b) {
|
|
70
|
+
return a + b
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
sldeploy add(2, 3)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Async Functions
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
async func load() {
|
|
80
|
+
let data = await get("https://example.com/api")
|
|
81
|
+
sldeploy data
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
load()
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Conditionals
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
if (x > 5) {
|
|
93
|
+
sldeploy "Greater than 5"
|
|
94
|
+
} else {
|
|
95
|
+
sldeploy "5 or less"
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
## Loops
|
|
102
|
+
|
|
103
|
+
### While Loop
|
|
104
|
+
|
|
105
|
+
```
|
|
106
|
+
let i = 0
|
|
107
|
+
while (i < 3) {
|
|
108
|
+
sldeploy i
|
|
109
|
+
i = i + 1
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
### For Loop (C-style)
|
|
116
|
+
|
|
117
|
+
```
|
|
118
|
+
for (let i = 0; i < 3; i = i + 1) {
|
|
119
|
+
sldeploy i
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### For-In Loop (Python-style)
|
|
126
|
+
|
|
127
|
+
Iterate over arrays:
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
let items = ["apple", "banana", "orange"]
|
|
131
|
+
|
|
132
|
+
for item in items {
|
|
133
|
+
sldeploy item
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
With `let` (scoped variable):
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
for let item in items {
|
|
141
|
+
sldeploy item
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Iterate over object keys:
|
|
146
|
+
|
|
147
|
+
```
|
|
148
|
+
let user = { "name": "Alice", "age": 20 }
|
|
149
|
+
|
|
150
|
+
for key in user {
|
|
151
|
+
sldeploy key + ": " + user[key]
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Objects & Arrays
|
|
158
|
+
|
|
159
|
+
```
|
|
160
|
+
let product = {
|
|
161
|
+
"name": "Star Lamp",
|
|
162
|
+
"price": 50,
|
|
163
|
+
"tags": ["space", "light"]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
sldeploy product
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## sldeploy (Output)
|
|
172
|
+
|
|
173
|
+
`sldeploy` works like Python's `print` and can display **any type**:
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
sldeploy 42
|
|
177
|
+
sldeploy "hello"
|
|
178
|
+
sldeploy true
|
|
179
|
+
sldeploy [1, 2, 3]
|
|
180
|
+
sldeploy { "a": 1, "b": 2 }
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
It automatically formats arrays, objects, functions, and nested values.
|
|
184
|
+
|
|
185
|
+
---
|
|
186
|
+
|
|
187
|
+
## ask (User Input)
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
let age = ask("Enter your age:")
|
|
191
|
+
sldeploy "You entered: " + age
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## Modules & Imports
|
|
197
|
+
|
|
198
|
+
### Import JavaScript Packages
|
|
199
|
+
|
|
200
|
+
```
|
|
201
|
+
import colors from "starlight-color"
|
|
202
|
+
|
|
203
|
+
sldeploy colors.blue("Hello Starlight")
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Import Local Files
|
|
207
|
+
|
|
208
|
+
```
|
|
209
|
+
import { add } from "./math.sl"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## Built-in Utilities
|
|
215
|
+
|
|
216
|
+
* `len(value)` – length of array, string, or object
|
|
217
|
+
* `keys(object)` – object keys
|
|
218
|
+
* `values(object)` – object values
|
|
219
|
+
* `sleep(ms)` – async delay
|
|
220
|
+
* `fetch(url)` – low-level fetch
|
|
221
|
+
* `get(url)` – GET request
|
|
222
|
+
* `post(url, data)` – POST request
|
|
223
|
+
* `num(value)` – convert to number
|
|
224
|
+
* `str(value)` – convert to string
|
|
225
|
+
|
|
226
|
+
---
|
|
44
227
|
|
|
45
228
|
## Server-side Example
|
|
46
229
|
|
|
47
|
-
|
|
230
|
+
```
|
|
48
231
|
define server = async () => {
|
|
49
232
|
let response = await get("https://jsonplaceholder.typicode.com/todos/1")
|
|
50
|
-
sldeploy
|
|
233
|
+
sldeploy response
|
|
51
234
|
}
|
|
52
235
|
|
|
53
236
|
server()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
## Core Concepts
|
|
237
|
+
```
|
|
57
238
|
|
|
58
|
-
|
|
59
|
-
- Functions: `func add(a, b) { return a + b }`
|
|
60
|
-
- Async Functions: `async func fetchData() { ... }`
|
|
61
|
-
- Conditionals: `if (x > 5) { ... } else { ... }`
|
|
62
|
-
- Loops: `while`, `for`
|
|
63
|
-
- Modules: `import { something } from "./module.sl"`
|
|
239
|
+
---
|
|
64
240
|
|
|
65
241
|
## Why Starlight?
|
|
66
242
|
|
|
67
|
-
Starlight is
|
|
243
|
+
Starlight is designed for developers who want:
|
|
244
|
+
|
|
245
|
+
* A **simple but powerful** scripting language
|
|
246
|
+
* **Fast server-side automation**
|
|
247
|
+
* Familiar syntax with **less boilerplate**
|
|
248
|
+
* Full access to the **Node.js ecosystem**
|
|
249
|
+
|
|
250
|
+
---
|
|
68
251
|
|
|
69
|
-
|
|
252
|
+
📘 Full documentation and tutorials:
|
|
253
|
+
[https://starlight-learn-lang.pages.dev/](https://starlight-learn-lang.pages.dev/)
|
|
70
254
|
|
|
71
|
-
License
|
|
255
|
+
**License:** MIT
|
package/dist/index.js
CHANGED
|
@@ -1370,56 +1370,78 @@ class Environment {
|
|
|
1370
1370
|
if (this.parent) return this.parent.get(name);
|
|
1371
1371
|
throw new Error(`Undefined variable: ${name}`);
|
|
1372
1372
|
}
|
|
1373
|
+
|
|
1374
|
+
set(name, value) {
|
|
1375
|
+
if (name in this.store) { this.store[name] = value; return value; }
|
|
1376
|
+
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
1377
|
+
this.store[name] = value;
|
|
1378
|
+
return value;
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
define(name, value) {
|
|
1382
|
+
this.store[name] = value;
|
|
1383
|
+
return value;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
|
|
1387
|
+
class Evaluator {
|
|
1388
|
+
constructor() {
|
|
1389
|
+
this.global = new Environment();
|
|
1390
|
+
this.setupBuiltins();
|
|
1391
|
+
}
|
|
1373
1392
|
formatValue(value, seen = new Set()) {
|
|
1393
|
+
// Circular reference handling
|
|
1374
1394
|
if (typeof value === 'object' && value !== null) {
|
|
1375
1395
|
if (seen.has(value)) return '[Circular]';
|
|
1376
1396
|
seen.add(value);
|
|
1377
1397
|
}
|
|
1378
1398
|
|
|
1379
|
-
|
|
1399
|
+
// Python-style null / undefined
|
|
1400
|
+
if (value === null) return 'None';
|
|
1380
1401
|
if (value === undefined) return 'undefined';
|
|
1381
1402
|
|
|
1382
1403
|
const t = typeof value;
|
|
1383
1404
|
|
|
1384
|
-
|
|
1385
|
-
if (t === '
|
|
1405
|
+
// Strings (quoted)
|
|
1406
|
+
if (t === 'string') return `"${value}"`;
|
|
1407
|
+
|
|
1408
|
+
// Numbers
|
|
1409
|
+
if (t === 'number') return String(value);
|
|
1410
|
+
|
|
1411
|
+
// Booleans (Python-style)
|
|
1412
|
+
if (t === 'boolean') return value ? 'True' : 'False';
|
|
1386
1413
|
|
|
1414
|
+
// Native JS functions
|
|
1387
1415
|
if (t === 'function') {
|
|
1388
|
-
return
|
|
1416
|
+
return value.name
|
|
1417
|
+
? `<function ${value.name}>`
|
|
1418
|
+
: '<function>';
|
|
1389
1419
|
}
|
|
1390
1420
|
|
|
1421
|
+
// Arrays
|
|
1391
1422
|
if (Array.isArray(value)) {
|
|
1392
1423
|
return '[' + value.map(v => this.formatValue(v, seen)).join(', ') + ']';
|
|
1393
1424
|
}
|
|
1394
1425
|
|
|
1426
|
+
// Objects (including your language functions)
|
|
1395
1427
|
if (t === 'object') {
|
|
1428
|
+
// Detect user-defined functions (AST-based)
|
|
1429
|
+
if (value.params && value.body) {
|
|
1430
|
+
return value.name
|
|
1431
|
+
? `<function ${value.name}>`
|
|
1432
|
+
: '<function>';
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1396
1435
|
const entries = Object.entries(value).map(
|
|
1397
1436
|
([k, v]) => `${k}: ${this.formatValue(v, seen)}`
|
|
1398
1437
|
);
|
|
1399
1438
|
return '{ ' + entries.join(', ') + ' }';
|
|
1400
1439
|
}
|
|
1401
1440
|
|
|
1441
|
+
// Fallback
|
|
1402
1442
|
return String(value);
|
|
1403
1443
|
}
|
|
1404
1444
|
|
|
1405
|
-
set(name, value) {
|
|
1406
|
-
if (name in this.store) { this.store[name] = value; return value; }
|
|
1407
|
-
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
1408
|
-
this.store[name] = value;
|
|
1409
|
-
return value;
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
define(name, value) {
|
|
1413
|
-
this.store[name] = value;
|
|
1414
|
-
return value;
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
|
|
1418
|
-
class Evaluator {
|
|
1419
|
-
constructor() {
|
|
1420
|
-
this.global = new Environment();
|
|
1421
|
-
this.setupBuiltins();
|
|
1422
|
-
}
|
|
1423
1445
|
|
|
1424
1446
|
setupBuiltins() {
|
|
1425
1447
|
this.global.define('len', arg => {
|
package/package.json
CHANGED
package/src/evaluator.js
CHANGED
|
@@ -27,56 +27,78 @@ class Environment {
|
|
|
27
27
|
if (this.parent) return this.parent.get(name);
|
|
28
28
|
throw new Error(`Undefined variable: ${name}`);
|
|
29
29
|
}
|
|
30
|
+
|
|
31
|
+
set(name, value) {
|
|
32
|
+
if (name in this.store) { this.store[name] = value; return value; }
|
|
33
|
+
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
34
|
+
this.store[name] = value;
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
define(name, value) {
|
|
39
|
+
this.store[name] = value;
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
class Evaluator {
|
|
45
|
+
constructor() {
|
|
46
|
+
this.global = new Environment();
|
|
47
|
+
this.setupBuiltins();
|
|
48
|
+
}
|
|
30
49
|
formatValue(value, seen = new Set()) {
|
|
50
|
+
// Circular reference handling
|
|
31
51
|
if (typeof value === 'object' && value !== null) {
|
|
32
52
|
if (seen.has(value)) return '[Circular]';
|
|
33
53
|
seen.add(value);
|
|
34
54
|
}
|
|
35
55
|
|
|
36
|
-
|
|
56
|
+
// Python-style null / undefined
|
|
57
|
+
if (value === null) return 'None';
|
|
37
58
|
if (value === undefined) return 'undefined';
|
|
38
59
|
|
|
39
60
|
const t = typeof value;
|
|
40
61
|
|
|
41
|
-
|
|
42
|
-
if (t === '
|
|
62
|
+
// Strings (quoted)
|
|
63
|
+
if (t === 'string') return `"${value}"`;
|
|
64
|
+
|
|
65
|
+
// Numbers
|
|
66
|
+
if (t === 'number') return String(value);
|
|
67
|
+
|
|
68
|
+
// Booleans (Python-style)
|
|
69
|
+
if (t === 'boolean') return value ? 'True' : 'False';
|
|
43
70
|
|
|
71
|
+
// Native JS functions
|
|
44
72
|
if (t === 'function') {
|
|
45
|
-
return
|
|
73
|
+
return value.name
|
|
74
|
+
? `<function ${value.name}>`
|
|
75
|
+
: '<function>';
|
|
46
76
|
}
|
|
47
77
|
|
|
78
|
+
// Arrays
|
|
48
79
|
if (Array.isArray(value)) {
|
|
49
80
|
return '[' + value.map(v => this.formatValue(v, seen)).join(', ') + ']';
|
|
50
81
|
}
|
|
51
82
|
|
|
83
|
+
// Objects (including your language functions)
|
|
52
84
|
if (t === 'object') {
|
|
85
|
+
// Detect user-defined functions (AST-based)
|
|
86
|
+
if (value.params && value.body) {
|
|
87
|
+
return value.name
|
|
88
|
+
? `<function ${value.name}>`
|
|
89
|
+
: '<function>';
|
|
90
|
+
}
|
|
91
|
+
|
|
53
92
|
const entries = Object.entries(value).map(
|
|
54
93
|
([k, v]) => `${k}: ${this.formatValue(v, seen)}`
|
|
55
94
|
);
|
|
56
95
|
return '{ ' + entries.join(', ') + ' }';
|
|
57
96
|
}
|
|
58
97
|
|
|
98
|
+
// Fallback
|
|
59
99
|
return String(value);
|
|
60
100
|
}
|
|
61
101
|
|
|
62
|
-
set(name, value) {
|
|
63
|
-
if (name in this.store) { this.store[name] = value; return value; }
|
|
64
|
-
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
65
|
-
this.store[name] = value;
|
|
66
|
-
return value;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
define(name, value) {
|
|
70
|
-
this.store[name] = value;
|
|
71
|
-
return value;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
class Evaluator {
|
|
76
|
-
constructor() {
|
|
77
|
-
this.global = new Environment();
|
|
78
|
-
this.setupBuiltins();
|
|
79
|
-
}
|
|
80
102
|
|
|
81
103
|
setupBuiltins() {
|
|
82
104
|
this.global.define('len', arg => {
|