starlight-cli 1.0.51 → 1.1.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/dist/index.js +56 -16
- package/package.json +1 -1
- package/src/evaluator.js +43 -2
- package/src/lexer.js +12 -12
- package/src/program.sl +2 -0
- package/src/starlight.js +1 -1
package/dist/index.js
CHANGED
|
@@ -1388,13 +1388,25 @@ class Environment {
|
|
|
1388
1388
|
return false;
|
|
1389
1389
|
}
|
|
1390
1390
|
|
|
1391
|
-
|
|
1391
|
+
get(name, node, source) {
|
|
1392
1392
|
if (name in this.store) return this.store[name];
|
|
1393
1393
|
if (this.parent) return this.parent.get(name, node, source);
|
|
1394
|
-
|
|
1394
|
+
|
|
1395
|
+
// Only suggest for top-level variable/function names
|
|
1396
|
+
let suggestion = null;
|
|
1397
|
+
if (node && source) {
|
|
1398
|
+
suggestion = this.suggest?.(name, this) || null;
|
|
1399
|
+
}
|
|
1400
|
+
|
|
1401
|
+
const message = suggestion
|
|
1402
|
+
? `Undefined variable: "${name}". Did you mean "${suggestion}"?`
|
|
1403
|
+
: `Undefined variable: "${name}"`;
|
|
1404
|
+
|
|
1405
|
+
throw new RuntimeError(message, node, source);
|
|
1395
1406
|
}
|
|
1396
1407
|
|
|
1397
1408
|
|
|
1409
|
+
|
|
1398
1410
|
set(name, value) {
|
|
1399
1411
|
if (name in this.store) { this.store[name] = value; return value; }
|
|
1400
1412
|
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
@@ -1414,6 +1426,35 @@ class Evaluator {
|
|
|
1414
1426
|
this.global = new Environment();
|
|
1415
1427
|
this.setupBuiltins();
|
|
1416
1428
|
}
|
|
1429
|
+
suggest(name, env) {
|
|
1430
|
+
// Collect all variable/function names from the environment chain
|
|
1431
|
+
const names = new Set();
|
|
1432
|
+
let current = env;
|
|
1433
|
+
while (current) {
|
|
1434
|
+
for (const key of Object.keys(current.store)) {
|
|
1435
|
+
names.add(key);
|
|
1436
|
+
}
|
|
1437
|
+
current = current.parent;
|
|
1438
|
+
}
|
|
1439
|
+
|
|
1440
|
+
let best = null;
|
|
1441
|
+
let bestScore = Infinity;
|
|
1442
|
+
|
|
1443
|
+
for (const item of names) {
|
|
1444
|
+
// simple edit distance approximation
|
|
1445
|
+
const dist = Math.abs(item.length - name.length) +
|
|
1446
|
+
[...name].filter((c, i) => c !== item[i]).length;
|
|
1447
|
+
|
|
1448
|
+
if (dist < bestScore && dist <= 2) { // max distance 2
|
|
1449
|
+
bestScore = dist;
|
|
1450
|
+
best = item;
|
|
1451
|
+
}
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
return best;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
|
|
1417
1458
|
formatValue(value, seen = new Set()) {
|
|
1418
1459
|
// Circular reference handling
|
|
1419
1460
|
if (typeof value === 'object' && value !== null) {
|
|
@@ -2187,6 +2228,13 @@ class Lexer {
|
|
|
2187
2228
|
this.currentChar = input[0] || null;
|
|
2188
2229
|
this.line = 1;
|
|
2189
2230
|
this.column = 1;
|
|
2231
|
+
this.keywords = [
|
|
2232
|
+
'let', 'sldeploy', 'if', 'else', 'while', 'for',
|
|
2233
|
+
'break', 'continue', 'func', 'return',
|
|
2234
|
+
'true', 'false', 'null',
|
|
2235
|
+
'ask', 'define', 'import', 'from', 'as',
|
|
2236
|
+
'async', 'await', 'new', 'in', 'do', 'track'
|
|
2237
|
+
];
|
|
2190
2238
|
}
|
|
2191
2239
|
|
|
2192
2240
|
|
|
@@ -2267,20 +2315,13 @@ class Lexer {
|
|
|
2267
2315
|
this.advance();
|
|
2268
2316
|
}
|
|
2269
2317
|
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
'true', 'false', 'null',
|
|
2274
|
-
'ask', 'define', 'import', 'from', 'as',
|
|
2275
|
-
'async', 'await', 'new', 'in', 'do', 'track'
|
|
2276
|
-
];
|
|
2318
|
+
if (this.keywords.includes(result)) {
|
|
2319
|
+
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
2320
|
+
}
|
|
2277
2321
|
|
|
2322
|
+
return { type: 'IDENTIFIER', value: result, line: startLine, column: startCol };
|
|
2278
2323
|
|
|
2279
|
-
if (keywords.includes(result)) {
|
|
2280
|
-
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
2281
|
-
}
|
|
2282
2324
|
|
|
2283
|
-
return { type: 'IDENTIFIER', value: result, line: startLine, column: startCol };
|
|
2284
2325
|
}
|
|
2285
2326
|
|
|
2286
2327
|
string() {
|
|
@@ -2373,8 +2414,7 @@ if (char === '-' && next === '>') {
|
|
|
2373
2414
|
}
|
|
2374
2415
|
}
|
|
2375
2416
|
|
|
2376
|
-
module.exports = Lexer;
|
|
2377
|
-
|
|
2417
|
+
module.exports = Lexer;
|
|
2378
2418
|
|
|
2379
2419
|
/***/ }),
|
|
2380
2420
|
|
|
@@ -3319,7 +3359,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
3319
3359
|
const Parser = __nccwpck_require__(222);
|
|
3320
3360
|
const Evaluator = __nccwpck_require__(112);
|
|
3321
3361
|
|
|
3322
|
-
const VERSION = '1.
|
|
3362
|
+
const VERSION = '1.1.1';
|
|
3323
3363
|
|
|
3324
3364
|
const COLOR = {
|
|
3325
3365
|
reset: '\x1b[0m',
|
package/package.json
CHANGED
package/src/evaluator.js
CHANGED
|
@@ -45,13 +45,25 @@ class Environment {
|
|
|
45
45
|
return false;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
get(name, node, source) {
|
|
49
49
|
if (name in this.store) return this.store[name];
|
|
50
50
|
if (this.parent) return this.parent.get(name, node, source);
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
// Only suggest for top-level variable/function names
|
|
53
|
+
let suggestion = null;
|
|
54
|
+
if (node && source) {
|
|
55
|
+
suggestion = this.suggest?.(name, this) || null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const message = suggestion
|
|
59
|
+
? `Undefined variable: "${name}". Did you mean "${suggestion}"?`
|
|
60
|
+
: `Undefined variable: "${name}"`;
|
|
61
|
+
|
|
62
|
+
throw new RuntimeError(message, node, source);
|
|
52
63
|
}
|
|
53
64
|
|
|
54
65
|
|
|
66
|
+
|
|
55
67
|
set(name, value) {
|
|
56
68
|
if (name in this.store) { this.store[name] = value; return value; }
|
|
57
69
|
if (this.parent && this.parent.has(name)) { return this.parent.set(name, value); }
|
|
@@ -71,6 +83,35 @@ class Evaluator {
|
|
|
71
83
|
this.global = new Environment();
|
|
72
84
|
this.setupBuiltins();
|
|
73
85
|
}
|
|
86
|
+
suggest(name, env) {
|
|
87
|
+
// Collect all variable/function names from the environment chain
|
|
88
|
+
const names = new Set();
|
|
89
|
+
let current = env;
|
|
90
|
+
while (current) {
|
|
91
|
+
for (const key of Object.keys(current.store)) {
|
|
92
|
+
names.add(key);
|
|
93
|
+
}
|
|
94
|
+
current = current.parent;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let best = null;
|
|
98
|
+
let bestScore = Infinity;
|
|
99
|
+
|
|
100
|
+
for (const item of names) {
|
|
101
|
+
// simple edit distance approximation
|
|
102
|
+
const dist = Math.abs(item.length - name.length) +
|
|
103
|
+
[...name].filter((c, i) => c !== item[i]).length;
|
|
104
|
+
|
|
105
|
+
if (dist < bestScore && dist <= 2) { // max distance 2
|
|
106
|
+
bestScore = dist;
|
|
107
|
+
best = item;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return best;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
74
115
|
formatValue(value, seen = new Set()) {
|
|
75
116
|
// Circular reference handling
|
|
76
117
|
if (typeof value === 'object' && value !== null) {
|
package/src/lexer.js
CHANGED
|
@@ -23,6 +23,13 @@ class Lexer {
|
|
|
23
23
|
this.currentChar = input[0] || null;
|
|
24
24
|
this.line = 1;
|
|
25
25
|
this.column = 1;
|
|
26
|
+
this.keywords = [
|
|
27
|
+
'let', 'sldeploy', 'if', 'else', 'while', 'for',
|
|
28
|
+
'break', 'continue', 'func', 'return',
|
|
29
|
+
'true', 'false', 'null',
|
|
30
|
+
'ask', 'define', 'import', 'from', 'as',
|
|
31
|
+
'async', 'await', 'new', 'in', 'do', 'track'
|
|
32
|
+
];
|
|
26
33
|
}
|
|
27
34
|
|
|
28
35
|
|
|
@@ -103,20 +110,13 @@ class Lexer {
|
|
|
103
110
|
this.advance();
|
|
104
111
|
}
|
|
105
112
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
'true', 'false', 'null',
|
|
110
|
-
'ask', 'define', 'import', 'from', 'as',
|
|
111
|
-
'async', 'await', 'new', 'in', 'do', 'track'
|
|
112
|
-
];
|
|
113
|
+
if (this.keywords.includes(result)) {
|
|
114
|
+
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
115
|
+
}
|
|
113
116
|
|
|
117
|
+
return { type: 'IDENTIFIER', value: result, line: startLine, column: startCol };
|
|
114
118
|
|
|
115
|
-
if (keywords.includes(result)) {
|
|
116
|
-
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
117
|
-
}
|
|
118
119
|
|
|
119
|
-
return { type: 'IDENTIFIER', value: result, line: startLine, column: startCol };
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
string() {
|
|
@@ -209,4 +209,4 @@ if (char === '-' && next === '>') {
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
module.exports = Lexer;
|
|
212
|
+
module.exports = Lexer;
|
package/src/program.sl
ADDED