starlight-cli 1.1.0 → 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 +46 -35
- package/package.json +1 -1
- package/src/evaluator.js +43 -2
- package/src/lexer.js +3 -33
- 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) {
|
|
@@ -2211,22 +2252,7 @@ class Lexer {
|
|
|
2211
2252
|
peek() {
|
|
2212
2253
|
return this.pos + 1 < this.input.length ? this.input[this.pos + 1] : null;
|
|
2213
2254
|
}
|
|
2214
|
-
suggest(word, list) {
|
|
2215
|
-
let best = null;
|
|
2216
|
-
let bestScore = Infinity;
|
|
2217
2255
|
|
|
2218
|
-
for (const item of list) {
|
|
2219
|
-
const dist =
|
|
2220
|
-
Math.abs(item.length - word.length) +
|
|
2221
|
-
[...word].filter((c, i) => c !== item[i]).length;
|
|
2222
|
-
|
|
2223
|
-
if (dist < bestScore && dist <= 2) {
|
|
2224
|
-
bestScore = dist;
|
|
2225
|
-
best = item;
|
|
2226
|
-
}
|
|
2227
|
-
}
|
|
2228
|
-
return best;
|
|
2229
|
-
}
|
|
2230
2256
|
error(msg) {
|
|
2231
2257
|
throw new LexerError(
|
|
2232
2258
|
msg,
|
|
@@ -2289,27 +2315,12 @@ suggest(word, list) {
|
|
|
2289
2315
|
this.advance();
|
|
2290
2316
|
}
|
|
2291
2317
|
|
|
2292
|
-
|
|
2293
2318
|
if (this.keywords.includes(result)) {
|
|
2294
|
-
return {
|
|
2295
|
-
type: result.toUpperCase(),
|
|
2296
|
-
value: result,
|
|
2297
|
-
line: startLine,
|
|
2298
|
-
column: startCol
|
|
2299
|
-
};
|
|
2319
|
+
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
2300
2320
|
}
|
|
2301
2321
|
|
|
2302
|
-
|
|
2303
|
-
if (suggestion) {
|
|
2304
|
-
this.error(`Unknown identifier "${result}". Did you mean "${suggestion}"?`);
|
|
2305
|
-
}
|
|
2322
|
+
return { type: 'IDENTIFIER', value: result, line: startLine, column: startCol };
|
|
2306
2323
|
|
|
2307
|
-
return {
|
|
2308
|
-
type: 'IDENTIFIER',
|
|
2309
|
-
value: result,
|
|
2310
|
-
line: startLine,
|
|
2311
|
-
column: startCol
|
|
2312
|
-
};
|
|
2313
2324
|
|
|
2314
2325
|
}
|
|
2315
2326
|
|
|
@@ -3348,7 +3359,7 @@ const Lexer = __nccwpck_require__(211);
|
|
|
3348
3359
|
const Parser = __nccwpck_require__(222);
|
|
3349
3360
|
const Evaluator = __nccwpck_require__(112);
|
|
3350
3361
|
|
|
3351
|
-
const VERSION = '1.1.
|
|
3362
|
+
const VERSION = '1.1.1';
|
|
3352
3363
|
|
|
3353
3364
|
const COLOR = {
|
|
3354
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
|
@@ -47,22 +47,7 @@ class Lexer {
|
|
|
47
47
|
peek() {
|
|
48
48
|
return this.pos + 1 < this.input.length ? this.input[this.pos + 1] : null;
|
|
49
49
|
}
|
|
50
|
-
|
|
51
|
-
let best = null;
|
|
52
|
-
let bestScore = Infinity;
|
|
53
|
-
|
|
54
|
-
for (const item of list) {
|
|
55
|
-
const dist =
|
|
56
|
-
Math.abs(item.length - word.length) +
|
|
57
|
-
[...word].filter((c, i) => c !== item[i]).length;
|
|
58
|
-
|
|
59
|
-
if (dist < bestScore && dist <= 2) {
|
|
60
|
-
bestScore = dist;
|
|
61
|
-
best = item;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return best;
|
|
65
|
-
}
|
|
50
|
+
|
|
66
51
|
error(msg) {
|
|
67
52
|
throw new LexerError(
|
|
68
53
|
msg,
|
|
@@ -125,27 +110,12 @@ suggest(word, list) {
|
|
|
125
110
|
this.advance();
|
|
126
111
|
}
|
|
127
112
|
|
|
128
|
-
|
|
129
113
|
if (this.keywords.includes(result)) {
|
|
130
|
-
return {
|
|
131
|
-
type: result.toUpperCase(),
|
|
132
|
-
value: result,
|
|
133
|
-
line: startLine,
|
|
134
|
-
column: startCol
|
|
135
|
-
};
|
|
114
|
+
return { type: result.toUpperCase(), value: result, line: startLine, column: startCol };
|
|
136
115
|
}
|
|
137
116
|
|
|
138
|
-
|
|
139
|
-
if (suggestion) {
|
|
140
|
-
this.error(`Unknown identifier "${result}". Did you mean "${suggestion}"?`);
|
|
141
|
-
}
|
|
117
|
+
return { type: 'IDENTIFIER', value: result, line: startLine, column: startCol };
|
|
142
118
|
|
|
143
|
-
return {
|
|
144
|
-
type: 'IDENTIFIER',
|
|
145
|
-
value: result,
|
|
146
|
-
line: startLine,
|
|
147
|
-
column: startCol
|
|
148
|
-
};
|
|
149
119
|
|
|
150
120
|
}
|
|
151
121
|
|
package/src/program.sl
ADDED