@nudojs/cli 0.2.1 → 0.3.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 (58) hide show
  1. package/package.json +12 -7
  2. package/src/abs-route.ts +273 -0
  3. package/src/builtins/builtin-prototype.ts +279 -0
  4. package/src/builtins/builtin-static.ts +260 -0
  5. package/src/eval-binary.ts +113 -0
  6. package/src/evaluator-api.ts +3 -0
  7. package/src/evaluator.ts +174 -633
  8. package/src/index.ts +373 -270
  9. package/src/narrowing.ts +7 -0
  10. package/src/phi-from-test.ts +42 -0
  11. package/src/run-test.ts +92 -0
  12. package/src/term-registry.ts +96 -0
  13. package/CHANGELOG.md +0 -41
  14. package/dist/chunk-3HCPXPEW.js +0 -5286
  15. package/dist/evaluator-api.d.ts +0 -151
  16. package/dist/evaluator-api.js +0 -214
  17. package/dist/index.d.ts +0 -2
  18. package/dist/index.js +0 -4035
  19. package/examples/real-world.js +0 -66
  20. package/examples/validate-real-world.ts +0 -160
  21. package/src/__tests__/builtin-advanced.test.ts +0 -292
  22. package/src/__tests__/builtin-api.test.ts +0 -308
  23. package/src/__tests__/builtin-functions.test.ts +0 -313
  24. package/src/__tests__/builtin-map.test.ts +0 -129
  25. package/src/__tests__/builtin-promise.test.ts +0 -150
  26. package/src/__tests__/builtin-regexp.test.ts +0 -133
  27. package/src/__tests__/builtin-set.test.ts +0 -163
  28. package/src/__tests__/builtin-url.test.ts +0 -256
  29. package/src/__tests__/builtin-web.test.ts +0 -340
  30. package/src/__tests__/combination-scenarios.test.ts +0 -384
  31. package/src/__tests__/edge-cases.test.ts +0 -749
  32. package/src/__tests__/evaluator-loops.test.ts +0 -283
  33. package/src/__tests__/evaluator-nullish-coalescing.test.ts +0 -86
  34. package/src/__tests__/evaluator-optional-chaining.test.ts +0 -37
  35. package/src/__tests__/evaluator-phase2.test.ts +0 -564
  36. package/src/__tests__/evaluator-phase3.test.ts +0 -864
  37. package/src/__tests__/evaluator-refined.test.ts +0 -121
  38. package/src/__tests__/evaluator-string-methods.test.ts +0 -151
  39. package/src/__tests__/evaluator.test.ts +0 -943
  40. package/src/__tests__/mock-arrow-function.test.ts +0 -169
  41. package/src/__tests__/mock-comparison.test.ts +0 -221
  42. package/src/__tests__/mock-comprehensive.test.ts +0 -250
  43. package/src/__tests__/mock-final-integration.test.ts +0 -263
  44. package/src/__tests__/mock-helpers.test.ts +0 -174
  45. package/src/__tests__/mock-realworld.test.ts +0 -191
  46. package/src/__tests__/mock-rest-debug.test.ts +0 -110
  47. package/src/__tests__/mock-rest-edge.test.ts +0 -176
  48. package/src/__tests__/mock-sinon-runtime.test.ts +0 -168
  49. package/src/__tests__/narrowing-discriminated.test.ts +0 -35
  50. package/src/__tests__/narrowing-in-operator.test.ts +0 -56
  51. package/src/__tests__/narrowing-switch.test.ts +0 -56
  52. package/src/__tests__/narrowing-truthiness.test.ts +0 -52
  53. package/src/__tests__/narrowing.test.ts +0 -82
  54. package/src/__tests__/nudo-mock-syntax.test.ts +0 -245
  55. package/src/__tests__/realworld-patterns.test.ts +0 -430
  56. package/src/__tests__/syntax-sugar.test.ts +0 -345
  57. package/src/builtins/index.ts +0 -61
  58. package/tsconfig.json +0 -9
@@ -1,283 +0,0 @@
1
- import { describe, it, expect, beforeEach } from "vitest";
2
- import { T, typeValueEquals, typeValueToString, createEnvironment } from "@nudojs/core";
3
- import { evaluateProgram, setSampleCount } from "../evaluator.ts";
4
- import { parse } from "@nudojs/parser";
5
- import type { TypeValue } from "@nudojs/core";
6
-
7
- function evalCode(code: string): TypeValue {
8
- const ast = parse(code);
9
- const env = createEnvironment();
10
- return evaluateProgram(ast, env);
11
- }
12
-
13
- function evalWith(code: string, bindings: Record<string, TypeValue>): TypeValue {
14
- const ast = parse(code);
15
- const env = createEnvironment();
16
- for (const [k, v] of Object.entries(bindings)) env.bind(k, v);
17
- return evaluateProgram(ast, env);
18
- }
19
-
20
- describe("ForStatement", () => {
21
- beforeEach(() => setSampleCount(3));
22
-
23
- it("evaluates simple for loop with literal bounds", () => {
24
- const result = evalCode(`
25
- let sum = 0;
26
- for (let i = 0; i < 3; i++) {
27
- sum = sum + i;
28
- }
29
- sum
30
- `);
31
- expect(typeValueEquals(result, T.literal(3))).toBe(true);
32
- });
33
-
34
- it("evaluates for loop that returns early", () => {
35
- const result = evalCode(`
36
- function f() {
37
- for (let i = 0; i < 10; i++) {
38
- if (i === 2) return i;
39
- }
40
- return -1;
41
- }
42
- `);
43
- // f is a function; we just check it's defined
44
- expect(result).toBeDefined();
45
- });
46
-
47
- it("for loop with abstract bounds widens variables", () => {
48
- const result = evalWith(`
49
- let sum = 0;
50
- for (let i = 0; i < n; i++) {
51
- sum = sum + i;
52
- }
53
- sum
54
- `, { n: T.number });
55
- // After widening, sum should be T.number
56
- expect(typeValueEquals(result, T.number)).toBe(true);
57
- });
58
-
59
- it("for loop variable accessible after loop", () => {
60
- const result = evalCode(`
61
- let x = 0;
62
- for (let i = 0; i < 2; i++) {
63
- x = x + 1;
64
- }
65
- x
66
- `);
67
- expect(typeValueEquals(result, T.literal(2))).toBe(true);
68
- });
69
-
70
- it("let loop variable gets a fresh binding per iteration for closures", () => {
71
- // Real JS semantics: let creates a per-iteration scope, so each closure
72
- // captures the value at its own iteration.
73
- const result = evalCode(`
74
- const fns = [];
75
- for (let i = 0; i < 3; i++) {
76
- fns.push(() => i);
77
- }
78
- [fns[0](), fns[1](), fns[2]()]
79
- `);
80
- expect(typeValueToString(result)).toBe("[0, 1, 2]");
81
- });
82
-
83
- it("var loop variable shares one binding across iterations for closures", () => {
84
- // var keeps a single shared cell: every closure observes the final value.
85
- const result = evalCode(`
86
- const fns = [];
87
- for (var i = 0; i < 3; i++) {
88
- fns.push(() => i);
89
- }
90
- [fns[0](), fns[1](), fns[2]()]
91
- `);
92
- expect(typeValueToString(result)).toBe("[3, 3, 3]");
93
- });
94
-
95
- it("let loop closure sees body-side increments; loop still progresses", () => {
96
- // Real JS: an assignment in the body targets the per-iteration binding
97
- // the closure captured (node: fns[0]() === 1), unlike the update clause
98
- // which runs outside it. No update clause here — the copy-back from the
99
- // per-iteration binding must still drive the loop condition.
100
- const result = evalCode(`
101
- const fns = [];
102
- let total = 0;
103
- for (let i = 0; i < 3;) {
104
- fns.push(() => i);
105
- total = total + i;
106
- i = i + 1;
107
- }
108
- [fns[0](), total]
109
- `);
110
- expect(typeValueToString(result)).toBe("[1, 3]");
111
- });
112
-
113
- it("for-of over a union of tuples iterates every member", () => {
114
- const result = evalWith(`
115
- function pick(c) {
116
- if (c) { return [9]; }
117
- return [10, [11, 12]];
118
- }
119
- function f(a, t) {
120
- const r = t || [];
121
- for (const e of a) {
122
- if (Array.isArray(e)) { f(e, r) } else { r.push(e) }
123
- }
124
- return r;
125
- }
126
- f(pick(c))
127
- `, { c: T.boolean });
128
- // Both union members' elements flow through the body (concatenated),
129
- // including the recursive flattening of the nested [11, 12] member.
130
- // (typeValueEquals has no tuple branch — compare rendered form.)
131
- expect(typeValueToString(result)).toBe("[9, 10, 11, 12]");
132
- });
133
-
134
- it("for-of over a union with non-iterable members skips them", () => {
135
- const result = evalWith(`
136
- function pick(c) {
137
- if (c) { return [1, 2]; }
138
- if (c === 2) { return 42; }
139
- return "str";
140
- }
141
- function f(a, t) {
142
- const r = t || [];
143
- for (const e of a) {
144
- if (Array.isArray(e)) { f(e, r) } else { r.push(e) }
145
- }
146
- return r;
147
- }
148
- f(pick(c))
149
- `, { c: T.boolean });
150
- // number/string members of the union contribute nothing; the tuple
151
- // member's pushes still land on the shared accumulator.
152
- expect(typeValueToString(result)).toBe("[1, 2]");
153
- });
154
-
155
- it("break terminates loop iteration and skips the rest of the body", () => {
156
- // Guard-style break (reach.js pattern): the member access after break
157
- // must not execute on the falsy receiver. Before break was implemented
158
- // the loop kept evaluating the body and dereferenced the undefined ref.
159
- const result = evalWith(`
160
- function step(ref, key) {
161
- let out = null;
162
- for (const k of [key]) {
163
- if (!ref) {
164
- out = 'default';
165
- break;
166
- }
167
- out = ref[k];
168
- }
169
- return out;
170
- }
171
- step(ref, 'a')
172
- `, { ref: T.undefined });
173
- expect(typeValueToString(result)).toBe('"default"');
174
- });
175
-
176
- it("break stops the loop and continue skips to the update clause", () => {
177
- const result = evalCode(`
178
- const collected = [];
179
- for (let i = 0; i < 5; i++) {
180
- if (i === 1) { continue; }
181
- if (i === 3) { break; }
182
- collected.push(i);
183
- }
184
- collected
185
- `);
186
- // continue skips push(1); break stops before 3 and 4
187
- expect(typeValueToString(result)).toBe("[0, 2]");
188
- });
189
- });
190
-
191
- describe("WhileStatement", () => {
192
- beforeEach(() => setSampleCount(3));
193
-
194
- it("evaluates while loop with literal false condition", () => {
195
- const result = evalCode(`
196
- let x = 0;
197
- while (false) {
198
- x = 1;
199
- }
200
- x
201
- `);
202
- expect(typeValueEquals(result, T.literal(0))).toBe(true);
203
- });
204
-
205
- it("evaluates while loop with concrete iterations", () => {
206
- const result = evalCode(`
207
- let x = 0;
208
- let i = 0;
209
- while (i < 3) {
210
- x = x + 1;
211
- i = i + 1;
212
- }
213
- x
214
- `);
215
- expect(typeValueEquals(result, T.literal(3))).toBe(true);
216
- });
217
-
218
- it("while loop with abstract condition", () => {
219
- const result = evalWith(`
220
- let count = 0;
221
- while (cond) {
222
- count = count + 1;
223
- }
224
- count
225
- `, { cond: T.boolean });
226
- // After sample iterations, count should be widened to number
227
- expect(typeValueEquals(result, T.number) || result.kind === "literal").toBe(true);
228
- });
229
- });
230
-
231
- describe("DoWhileStatement", () => {
232
- beforeEach(() => setSampleCount(3));
233
-
234
- it("executes body at least once", () => {
235
- const result = evalCode(`
236
- let x = 0;
237
- do {
238
- x = x + 1;
239
- } while (false);
240
- x
241
- `);
242
- expect(typeValueEquals(result, T.literal(1))).toBe(true);
243
- });
244
-
245
- it("evaluates do-while with multiple iterations", () => {
246
- const result = evalCode(`
247
- let x = 0;
248
- let i = 0;
249
- do {
250
- x = x + 1;
251
- i = i + 1;
252
- } while (i < 3);
253
- x
254
- `);
255
- expect(typeValueEquals(result, T.literal(3))).toBe(true);
256
- });
257
- });
258
-
259
- describe("@nudo:sample integration", () => {
260
- it("respects custom sample count", () => {
261
- setSampleCount(5);
262
- const result = evalCode(`
263
- let sum = 0;
264
- for (let i = 0; i < 5; i++) {
265
- sum = sum + i;
266
- }
267
- sum
268
- `);
269
- expect(typeValueEquals(result, T.literal(10))).toBe(true);
270
- });
271
-
272
- it("default sample count is 3", () => {
273
- setSampleCount(3);
274
- const result = evalCode(`
275
- let sum = 0;
276
- for (let i = 0; i < 3; i++) {
277
- sum = sum + i;
278
- }
279
- sum
280
- `);
281
- expect(typeValueEquals(result, T.literal(3))).toBe(true);
282
- });
283
- });
@@ -1,86 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { T, typeValueToString, createEnvironment } from "@nudojs/core";
3
- import type { TypeValue } from "@nudojs/core";
4
- import { evaluateProgram, evaluateFunction } from "../evaluator.ts";
5
- import { parse } from "@nudojs/parser";
6
-
7
- function evalSource(source: string) {
8
- const ast = parse(source);
9
- const env = createEnvironment();
10
- evaluateProgram(ast, env);
11
- return env;
12
- }
13
-
14
- function evalFn(code: string, args: TypeValue[]): TypeValue {
15
- const ast = parse(code);
16
- const env = createEnvironment();
17
- evaluateProgram(ast, env);
18
- const fns = ast.type === "File" ? ast.program.body : [];
19
- const fnNode = fns.find(
20
- (n: any) => n.type === "FunctionDeclaration",
21
- );
22
- if (!fnNode) throw new Error("No function found");
23
- return evaluateFunction(fnNode, args, env);
24
- }
25
-
26
- describe("nullish coalescing narrowing", () => {
27
- it("narrows ?? to exclude null/undefined from left side", () => {
28
- const env = evalSource(`
29
- const x = "hello" ?? "default";
30
- `);
31
- expect(typeValueToString(env.lookup("x"))).toBe('"hello"');
32
- });
33
-
34
- it("returns right side when left is always null", () => {
35
- const env = evalSource(`
36
- const x = null;
37
- const result = x ?? 42;
38
- `);
39
- expect(typeValueToString(env.lookup("result"))).toBe("42");
40
- });
41
-
42
- it("returns left side when left is never null", () => {
43
- const env = evalSource(`
44
- const x = "hello";
45
- const result = x ?? "default";
46
- `);
47
- expect(typeValueToString(env.lookup("result"))).toBe('"hello"');
48
- });
49
-
50
- it("narrows union type by removing null from left side", () => {
51
- const result = evalFn(
52
- `function test(x) { return x ?? "default"; }`,
53
- [T.union(T.string, T.null)],
54
- );
55
- // null is excluded from string | null, leaving string.
56
- // "default" is a subtype of string, so result is string.
57
- expect(typeValueToString(result)).toBe("string");
58
- });
59
-
60
- it("narrows union type by removing undefined from left side", () => {
61
- const result = evalFn(
62
- `function test(x) { return x ?? "fallback"; }`,
63
- [T.union(T.string, T.undefined)],
64
- );
65
- // undefined is excluded from string | undefined, leaving string.
66
- expect(typeValueToString(result)).toBe("string");
67
- });
68
-
69
- it("narrows union type by removing null and undefined from left side", () => {
70
- const result = evalFn(
71
- `function test(x) { return x ?? "fallback"; }`,
72
- [T.union(T.string, T.null, T.undefined)],
73
- );
74
- // null and undefined are excluded, leaving string.
75
- expect(typeValueToString(result)).toBe("string");
76
- });
77
-
78
- it("returns right side when left is always null/undefined union", () => {
79
- const result = evalFn(
80
- `function test(x) { return x ?? 42; }`,
81
- [T.union(T.null, T.undefined)],
82
- );
83
- // All left members are null/undefined, so use right side.
84
- expect(typeValueToString(result)).toBe("42");
85
- });
86
- });
@@ -1,37 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { T, typeValueToString, createEnvironment } from "@nudojs/core";
3
- import { evaluateProgram } from "../evaluator.ts";
4
- import { parse } from "@nudojs/parser";
5
-
6
- function evalSource(source: string) {
7
- const ast = parse(source);
8
- const env = createEnvironment();
9
- evaluateProgram(ast, env);
10
- return env;
11
- }
12
-
13
- describe("optional chaining", () => {
14
- it("evaluates obj?.foo when obj is object", () => {
15
- const env = evalSource(`
16
- const obj = { foo: "hello" };
17
- const result = obj?.foo;
18
- `);
19
- expect(typeValueToString(env.lookup("result"))).toBe('"hello"');
20
- });
21
-
22
- it("evaluates arr?.[0] for optional computed access", () => {
23
- const env = evalSource(`
24
- const arr = [1, 2, 3];
25
- const result = arr?.[0];
26
- `);
27
- expect(typeValueToString(env.lookup("result"))).toBe("1");
28
- });
29
-
30
- it("evaluates fn?.() for optional call", () => {
31
- const env = evalSource(`
32
- const fn = () => 42;
33
- const result = fn?.();
34
- `);
35
- expect(typeValueToString(env.lookup("result"))).toBe("42");
36
- });
37
- });