starlight-cli 1.1.3 → 1.1.4
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 +110 -157
- package/dist/index.js +38 -10
- package/package.json +1 -1
- package/src/evaluator.js +23 -6
- package/src/parser.js +14 -3
- package/src/starlight.js +1 -1
package/README.md
CHANGED
|
@@ -2,52 +2,64 @@
|
|
|
2
2
|
|
|
3
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
|
-
**Official Reference:** [
|
|
5
|
+
**Official Reference:** [
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
## Key Features
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
|
|
12
|
+
- **Modern, Simple Syntax** – Familiar to JavaScript and Python developers
|
|
13
|
+
- **Async / Await** – Native support for asynchronous operations
|
|
14
|
+
- **Modules & Imports** – Import JavaScript packages or other `.sl` files
|
|
15
|
+
- **Server-side Ready** – Built on Node.js, ideal for backend logic
|
|
16
|
+
- **Interactive I/O** – Built-in `ask` and `sldeploy`
|
|
17
|
+
- **Built-in Utilities** – `sleep`, `len`, `keys`, `values`, `fetch`, `get`, `post`
|
|
18
|
+
|
|
17
19
|
|
|
18
20
|
---
|
|
19
21
|
|
|
20
22
|
## Installation
|
|
21
23
|
|
|
22
|
-
1. Install **Node.js** (v18+ recommended)
|
|
23
|
-
2. Install Starlight CLI:
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Install **Node.js** (v18+ recommended)1. $1
|
|
26
|
+
Install Starlight CLI:1. $1
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
|
|
26
31
|
npm install -g starlight-cli
|
|
32
|
+
|
|
27
33
|
```
|
|
28
34
|
|
|
29
35
|
---
|
|
30
36
|
|
|
31
37
|
## Your First Program (`hello.sl`)
|
|
32
38
|
|
|
33
|
-
```
|
|
39
|
+
```
|
|
40
|
+
|
|
34
41
|
let name = ask("What is your name?")
|
|
35
42
|
sldeploy "Hello, " + name + "!"
|
|
43
|
+
|
|
36
44
|
```
|
|
37
45
|
|
|
38
46
|
Run:
|
|
39
47
|
|
|
40
|
-
```
|
|
48
|
+
```
|
|
49
|
+
|
|
41
50
|
starlight hello.sl
|
|
51
|
+
|
|
42
52
|
```
|
|
43
53
|
|
|
44
54
|
---
|
|
45
55
|
|
|
46
56
|
## Output
|
|
47
57
|
|
|
48
|
-
```
|
|
58
|
+
```
|
|
59
|
+
|
|
49
60
|
What is your name? Alice
|
|
50
61
|
Hello, Alice!
|
|
62
|
+
|
|
51
63
|
```
|
|
52
64
|
|
|
53
65
|
---
|
|
@@ -56,246 +68,187 @@ Hello, Alice!
|
|
|
56
68
|
|
|
57
69
|
### Variables
|
|
58
70
|
|
|
59
|
-
```
|
|
71
|
+
```
|
|
72
|
+
|
|
60
73
|
let x = 10
|
|
61
74
|
let text = "hello"
|
|
75
|
+
|
|
62
76
|
```
|
|
63
77
|
|
|
64
78
|
---
|
|
65
79
|
|
|
66
80
|
### Functions
|
|
67
81
|
|
|
68
|
-
```
|
|
82
|
+
```
|
|
83
|
+
|
|
69
84
|
func add(a, b) {
|
|
70
85
|
return a + b
|
|
71
86
|
}
|
|
72
87
|
|
|
73
88
|
sldeploy add(2, 3)
|
|
89
|
+
|
|
74
90
|
```
|
|
75
91
|
|
|
76
92
|
### Async Functions
|
|
77
93
|
|
|
78
|
-
```
|
|
94
|
+
```
|
|
95
|
+
|
|
79
96
|
async func load() {
|
|
80
97
|
let data = await get("https://example.com/api")
|
|
81
98
|
sldeploy data
|
|
82
99
|
}
|
|
83
100
|
|
|
84
101
|
load()
|
|
102
|
+
|
|
85
103
|
```
|
|
86
104
|
|
|
87
105
|
---
|
|
88
106
|
|
|
89
|
-
##
|
|
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
|
|
107
|
+
## Arrow Functions
|
|
102
108
|
|
|
103
|
-
|
|
109
|
+
Arrow functions provide a **concise and expressive** way to define functions. They support expressions, block bodies, conditionals, loops, and `return` statements.
|
|
104
110
|
|
|
105
|
-
|
|
106
|
-
let i = 0
|
|
107
|
-
while (i < 3) {
|
|
108
|
-
sldeploy i
|
|
109
|
-
i = i + 1
|
|
110
|
-
}
|
|
111
|
-
```
|
|
111
|
+
### Basic Arrow Function
|
|
112
112
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
### For Loop (C-style)
|
|
113
|
+
```
|
|
116
114
|
|
|
115
|
+
let square = x => x * x
|
|
116
|
+
sldeploy square(5)
|
|
117
|
+
|
|
117
118
|
```
|
|
118
|
-
for (let i = 0; i < 3; i = i + 1) {
|
|
119
|
-
sldeploy i
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
119
|
|
|
125
|
-
###
|
|
120
|
+
### Multiple Parameters
|
|
126
121
|
|
|
127
|
-
|
|
122
|
+
```
|
|
128
123
|
|
|
124
|
+
let add = (a, b) => a + b
|
|
125
|
+
sldeploy add(10, 20)
|
|
126
|
+
|
|
129
127
|
```
|
|
130
|
-
let items = ["apple", "banana", "orange"]
|
|
131
128
|
|
|
132
|
-
|
|
133
|
-
sldeploy item
|
|
134
|
-
}
|
|
135
|
-
```
|
|
129
|
+
### Block Body with if / else
|
|
136
130
|
|
|
137
|
-
|
|
131
|
+
```
|
|
138
132
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
133
|
+
let label = p => {
|
|
134
|
+
if (p.price > 1000) {
|
|
135
|
+
return "Premium"
|
|
136
|
+
} else {
|
|
137
|
+
return "Standard"
|
|
138
|
+
}
|
|
142
139
|
}
|
|
140
|
+
|
|
143
141
|
```
|
|
144
142
|
|
|
145
|
-
|
|
143
|
+
### Arrow Functions with Objects
|
|
146
144
|
|
|
147
|
-
```
|
|
148
|
-
let user = { "name": "Alice", "age": 20 }
|
|
145
|
+
```
|
|
149
146
|
|
|
150
|
-
|
|
151
|
-
|
|
147
|
+
let summarize = p => {
|
|
148
|
+
return {
|
|
149
|
+
"name": p.name,
|
|
150
|
+
"value": p.price * p.stock
|
|
151
|
+
}
|
|
152
152
|
}
|
|
153
|
+
|
|
153
154
|
```
|
|
154
155
|
|
|
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
|
-
```
|
|
156
|
+
Arrow functions capture their surrounding scope and behave like standard functions while remaining lightweight and readable.
|
|
193
157
|
|
|
194
158
|
---
|
|
195
159
|
|
|
196
|
-
##
|
|
197
|
-
|
|
198
|
-
### Import JavaScript Packages
|
|
199
|
-
|
|
200
|
-
```
|
|
201
|
-
import colors from "starlight-color"
|
|
202
|
-
|
|
203
|
-
sldeploy colors.blue("Hello Starlight")
|
|
204
|
-
```
|
|
160
|
+
## Conditionals
|
|
205
161
|
|
|
206
|
-
|
|
162
|
+
```
|
|
207
163
|
|
|
208
|
-
|
|
209
|
-
|
|
164
|
+
if (x > 5) {
|
|
165
|
+
sldeploy "Greater than 5"
|
|
166
|
+
} else {
|
|
167
|
+
sldeploy "5 or less"
|
|
168
|
+
}
|
|
169
|
+
|
|
210
170
|
```
|
|
211
171
|
|
|
212
172
|
---
|
|
213
173
|
|
|
214
|
-
##
|
|
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
|
|
174
|
+
## Loops
|
|
225
175
|
|
|
226
|
-
|
|
176
|
+
### While Loop
|
|
227
177
|
|
|
228
|
-
|
|
178
|
+
```
|
|
229
179
|
|
|
230
|
-
|
|
231
|
-
|
|
180
|
+
let i = 0
|
|
181
|
+
while (i {
|
|
232
182
|
let response = await get("https://jsonplaceholder.typicode.com/todos/1")
|
|
233
183
|
sldeploy response
|
|
234
184
|
}
|
|
235
185
|
|
|
236
186
|
server()
|
|
187
|
+
|
|
237
188
|
```
|
|
238
189
|
|
|
239
190
|
---
|
|
191
|
+
|
|
240
192
|
## Start & Race Statements
|
|
241
193
|
|
|
242
|
-
Starlight includes a
|
|
194
|
+
Starlight includes a **start / race** control structure similar to a switch statement, with **fall-through behavior**.
|
|
243
195
|
|
|
244
196
|
### Syntax
|
|
245
197
|
|
|
246
|
-
```
|
|
247
|
-
start (<discriminant>) {
|
|
248
|
-
race (<value>) {
|
|
249
|
-
# body
|
|
250
|
-
}
|
|
198
|
+
```
|
|
251
199
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
200
|
+
start (value) {
|
|
201
|
+
race (1) {
|
|
202
|
+
# body
|
|
203
|
+
}
|
|
255
204
|
|
|
205
|
+
race (2) {
|
|
206
|
+
# body
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
256
210
|
```
|
|
257
211
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
- `start` – evaluates the discriminant expression.
|
|
261
|
-
- `race` – each clause is checked; execution starts at the first matching `race` and continues to subsequent races (fall-through).
|
|
262
|
-
- Optional `break` can stop execution early (if implemented).
|
|
263
|
-
|
|
264
212
|
### Example
|
|
265
213
|
|
|
266
|
-
```
|
|
214
|
+
```
|
|
215
|
+
|
|
267
216
|
define x = 2;
|
|
268
217
|
|
|
269
218
|
start (x) {
|
|
270
|
-
race (1) { sldeploy("Race 1 executed"); }
|
|
271
|
-
race (2) { sldeploy("Race 2 executed"); }
|
|
272
|
-
race (3) { sldeploy("Race 3 executed"); }
|
|
219
|
+
race (1) { sldeploy("Race 1 executed"); }
|
|
220
|
+
race (2) { sldeploy("Race 2 executed"); }
|
|
221
|
+
race (3) { sldeploy("Race 3 executed"); }
|
|
273
222
|
}
|
|
274
223
|
|
|
275
224
|
sldeploy("Done with start statement");
|
|
276
|
-
|
|
225
|
+
|
|
277
226
|
```
|
|
278
227
|
|
|
279
|
-
|
|
228
|
+
### Expected Output
|
|
229
|
+
|
|
230
|
+
```
|
|
280
231
|
|
|
281
|
-
```
|
|
282
232
|
Race 2 executed
|
|
283
233
|
Race 3 executed
|
|
284
234
|
Done with start statement
|
|
285
|
-
|
|
235
|
+
|
|
286
236
|
```
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
287
240
|
## Why Starlight?
|
|
288
241
|
|
|
289
|
-
Starlight is designed for developers who want:
|
|
290
242
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
243
|
+
- A **simple but powerful** scripting language
|
|
244
|
+
- **Fast server-side automation**
|
|
245
|
+
- Familiar syntax with **less boilerplate**
|
|
246
|
+
- Full access to the **Node.js ecosystem**
|
|
247
|
+
|
|
295
248
|
|
|
296
249
|
---
|
|
297
250
|
|
|
298
251
|
📘 Full documentation and tutorials:
|
|
299
|
-
|
|
252
|
+
https://starlight-learn-lang.pages.dev/](https://starlight-learn-lang.pages.dev/>https://starlight-learn-lang.pages.dev/</link)
|
|
300
253
|
|
|
301
|
-
**License:** MIT
|
|
254
|
+
**License:** MIT
|
package/dist/index.js
CHANGED
|
@@ -1874,16 +1874,33 @@ evalArrowFunction(node, env) {
|
|
|
1874
1874
|
if (!node.body) {
|
|
1875
1875
|
throw new RuntimeError('Arrow function missing body', node, this.source);
|
|
1876
1876
|
}
|
|
1877
|
+
|
|
1877
1878
|
if (!Array.isArray(node.params)) {
|
|
1878
1879
|
throw new RuntimeError('Invalid arrow function parameters', node, this.source);
|
|
1879
1880
|
}
|
|
1880
1881
|
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1882
|
+
const evaluator = this;
|
|
1883
|
+
|
|
1884
|
+
return async function (...args) {
|
|
1885
|
+
const localEnv = new Environment(env);
|
|
1886
|
+
|
|
1887
|
+
node.params.forEach((p, i) => {
|
|
1888
|
+
localEnv.define(p.name, args[i]);
|
|
1889
|
+
});
|
|
1890
|
+
|
|
1891
|
+
try {
|
|
1892
|
+
if (node.isBlock) {
|
|
1893
|
+
const result = await evaluator.evaluate(node.body, localEnv);
|
|
1894
|
+
return result ?? null;
|
|
1895
|
+
} else {
|
|
1896
|
+
return await evaluator.evaluate(node.body, localEnv);
|
|
1897
|
+
}
|
|
1898
|
+
} catch (err) {
|
|
1899
|
+
if (err instanceof ReturnValue) {
|
|
1900
|
+
return err.value;
|
|
1901
|
+
}
|
|
1902
|
+
throw err;
|
|
1903
|
+
}
|
|
1887
1904
|
};
|
|
1888
1905
|
}
|
|
1889
1906
|
|
|
@@ -3175,15 +3192,26 @@ postfix() {
|
|
|
3175
3192
|
|
|
3176
3193
|
arrowFunction(params) {
|
|
3177
3194
|
const t = this.current;
|
|
3178
|
-
|
|
3179
|
-
|
|
3195
|
+
this.eat('ARROW');
|
|
3196
|
+
|
|
3197
|
+
let body;
|
|
3198
|
+
let isBlock = false;
|
|
3199
|
+
|
|
3200
|
+
if (this.current.type === 'LBRACE') {
|
|
3201
|
+
body = this.block();
|
|
3202
|
+
isBlock = true;
|
|
3203
|
+
} else {
|
|
3204
|
+
body = this.expression();
|
|
3205
|
+
}
|
|
3206
|
+
|
|
3180
3207
|
const startLine = params.length > 0 ? params[0].line : t.line;
|
|
3181
|
-
const startCol
|
|
3208
|
+
const startCol = params.length > 0 ? params[0].column : t.column;
|
|
3182
3209
|
|
|
3183
3210
|
return {
|
|
3184
3211
|
type: 'ArrowFunctionExpression',
|
|
3185
3212
|
params,
|
|
3186
3213
|
body,
|
|
3214
|
+
isBlock,
|
|
3187
3215
|
line: startLine,
|
|
3188
3216
|
column: startCol
|
|
3189
3217
|
};
|
|
@@ -3512,7 +3540,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
3512
3540
|
const Parser = __nccwpck_require__(222);
|
|
3513
3541
|
const Evaluator = __nccwpck_require__(112);
|
|
3514
3542
|
|
|
3515
|
-
const VERSION = '1.1.
|
|
3543
|
+
const VERSION = '1.1.4';
|
|
3516
3544
|
|
|
3517
3545
|
const COLOR = {
|
|
3518
3546
|
reset: '\x1b[0m',
|
package/package.json
CHANGED
package/src/evaluator.js
CHANGED
|
@@ -531,16 +531,33 @@ evalArrowFunction(node, env) {
|
|
|
531
531
|
if (!node.body) {
|
|
532
532
|
throw new RuntimeError('Arrow function missing body', node, this.source);
|
|
533
533
|
}
|
|
534
|
+
|
|
534
535
|
if (!Array.isArray(node.params)) {
|
|
535
536
|
throw new RuntimeError('Invalid arrow function parameters', node, this.source);
|
|
536
537
|
}
|
|
537
538
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
539
|
+
const evaluator = this;
|
|
540
|
+
|
|
541
|
+
return async function (...args) {
|
|
542
|
+
const localEnv = new Environment(env);
|
|
543
|
+
|
|
544
|
+
node.params.forEach((p, i) => {
|
|
545
|
+
localEnv.define(p.name, args[i]);
|
|
546
|
+
});
|
|
547
|
+
|
|
548
|
+
try {
|
|
549
|
+
if (node.isBlock) {
|
|
550
|
+
const result = await evaluator.evaluate(node.body, localEnv);
|
|
551
|
+
return result ?? null;
|
|
552
|
+
} else {
|
|
553
|
+
return await evaluator.evaluate(node.body, localEnv);
|
|
554
|
+
}
|
|
555
|
+
} catch (err) {
|
|
556
|
+
if (err instanceof ReturnValue) {
|
|
557
|
+
return err.value;
|
|
558
|
+
}
|
|
559
|
+
throw err;
|
|
560
|
+
}
|
|
544
561
|
};
|
|
545
562
|
}
|
|
546
563
|
|
package/src/parser.js
CHANGED
|
@@ -700,15 +700,26 @@ postfix() {
|
|
|
700
700
|
|
|
701
701
|
arrowFunction(params) {
|
|
702
702
|
const t = this.current;
|
|
703
|
-
|
|
704
|
-
|
|
703
|
+
this.eat('ARROW');
|
|
704
|
+
|
|
705
|
+
let body;
|
|
706
|
+
let isBlock = false;
|
|
707
|
+
|
|
708
|
+
if (this.current.type === 'LBRACE') {
|
|
709
|
+
body = this.block();
|
|
710
|
+
isBlock = true;
|
|
711
|
+
} else {
|
|
712
|
+
body = this.expression();
|
|
713
|
+
}
|
|
714
|
+
|
|
705
715
|
const startLine = params.length > 0 ? params[0].line : t.line;
|
|
706
|
-
const startCol
|
|
716
|
+
const startCol = params.length > 0 ? params[0].column : t.column;
|
|
707
717
|
|
|
708
718
|
return {
|
|
709
719
|
type: 'ArrowFunctionExpression',
|
|
710
720
|
params,
|
|
711
721
|
body,
|
|
722
|
+
isBlock,
|
|
712
723
|
line: startLine,
|
|
713
724
|
column: startCol
|
|
714
725
|
};
|