@nudojs/cli 0.2.1 → 0.3.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.
Files changed (64) hide show
  1. package/dist/{chunk-3HCPXPEW.js → chunk-YDM4HHQ4.js} +1783 -1421
  2. package/dist/evaluator-api.d.ts +12 -1
  3. package/dist/evaluator-api.js +52 -2
  4. package/dist/index.d.ts +1 -2
  5. package/dist/index.js +366 -3572
  6. package/package.json +23 -11
  7. package/CHANGELOG.md +0 -41
  8. package/examples/real-world.js +0 -66
  9. package/examples/validate-real-world.ts +0 -160
  10. package/src/__tests__/builtin-advanced.test.ts +0 -292
  11. package/src/__tests__/builtin-api.test.ts +0 -308
  12. package/src/__tests__/builtin-functions.test.ts +0 -313
  13. package/src/__tests__/builtin-map.test.ts +0 -129
  14. package/src/__tests__/builtin-promise.test.ts +0 -150
  15. package/src/__tests__/builtin-regexp.test.ts +0 -133
  16. package/src/__tests__/builtin-set.test.ts +0 -163
  17. package/src/__tests__/builtin-url.test.ts +0 -256
  18. package/src/__tests__/builtin-web.test.ts +0 -340
  19. package/src/__tests__/combination-scenarios.test.ts +0 -384
  20. package/src/__tests__/edge-cases.test.ts +0 -749
  21. package/src/__tests__/evaluator-loops.test.ts +0 -283
  22. package/src/__tests__/evaluator-nullish-coalescing.test.ts +0 -86
  23. package/src/__tests__/evaluator-optional-chaining.test.ts +0 -37
  24. package/src/__tests__/evaluator-phase2.test.ts +0 -564
  25. package/src/__tests__/evaluator-phase3.test.ts +0 -864
  26. package/src/__tests__/evaluator-refined.test.ts +0 -121
  27. package/src/__tests__/evaluator-string-methods.test.ts +0 -151
  28. package/src/__tests__/evaluator.test.ts +0 -943
  29. package/src/__tests__/mock-arrow-function.test.ts +0 -169
  30. package/src/__tests__/mock-comparison.test.ts +0 -221
  31. package/src/__tests__/mock-comprehensive.test.ts +0 -250
  32. package/src/__tests__/mock-final-integration.test.ts +0 -263
  33. package/src/__tests__/mock-helpers.test.ts +0 -174
  34. package/src/__tests__/mock-realworld.test.ts +0 -191
  35. package/src/__tests__/mock-rest-debug.test.ts +0 -110
  36. package/src/__tests__/mock-rest-edge.test.ts +0 -176
  37. package/src/__tests__/mock-sinon-runtime.test.ts +0 -168
  38. package/src/__tests__/narrowing-discriminated.test.ts +0 -35
  39. package/src/__tests__/narrowing-in-operator.test.ts +0 -56
  40. package/src/__tests__/narrowing-switch.test.ts +0 -56
  41. package/src/__tests__/narrowing-truthiness.test.ts +0 -52
  42. package/src/__tests__/narrowing.test.ts +0 -82
  43. package/src/__tests__/nudo-mock-syntax.test.ts +0 -245
  44. package/src/__tests__/realworld-patterns.test.ts +0 -430
  45. package/src/__tests__/syntax-sugar.test.ts +0 -345
  46. package/src/builtins/builtin-intl.ts +0 -17
  47. package/src/builtins/builtin-map.ts +0 -174
  48. package/src/builtins/builtin-promise.ts +0 -116
  49. package/src/builtins/builtin-reflect.ts +0 -30
  50. package/src/builtins/builtin-regexp.ts +0 -34
  51. package/src/builtins/builtin-set.ts +0 -131
  52. package/src/builtins/builtin-symbol.ts +0 -16
  53. package/src/builtins/builtin-url.ts +0 -58
  54. package/src/builtins/builtin-weak.ts +0 -22
  55. package/src/builtins/builtin-web.ts +0 -111
  56. package/src/builtins/index.ts +0 -61
  57. package/src/config.ts +0 -32
  58. package/src/env-loader.ts +0 -174
  59. package/src/evaluator-api.ts +0 -36
  60. package/src/evaluator.ts +0 -5623
  61. package/src/index.ts +0 -931
  62. package/src/narrowing.ts +0 -537
  63. package/src/resolve-npm.ts +0 -63
  64. package/tsconfig.json +0 -9
@@ -1,169 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { parse, extractDirectives, type CaseDirective, parseTypeValueExpr } from "@nudojs/parser";
3
- import { typeValueToString, createEnvironment, T } from "@nudojs/core";
4
- import { evaluateFunctionFull } from "../evaluator.js";
5
- import { analyzeFile } from "@nudojs/service";
6
-
7
- function inferWithMocks(source: string): { name: string; caseName: string; result: string }[] {
8
- const ast = parse(source);
9
- const directives = extractDirectives(ast);
10
- const env = createEnvironment();
11
- const results: { name: string; caseName: string; result: string }[] = [];
12
-
13
- for (const fn of directives) {
14
- // Apply mocks first
15
- for (const d of fn.directives) {
16
- if (d.kind === "mock") {
17
- if (d.arrowFn) {
18
- const fnType = T.fn(d.arrowFn.params, d.arrowFn.body, env);
19
- (fnType as any)._paramPatterns = d.arrowFn.paramPatterns;
20
- env.bind(d.name, fnType);
21
- } else if (d.expression) {
22
- env.bind(d.name, parseTypeValueExpr(d.expression));
23
- }
24
- }
25
- }
26
-
27
- const caseDirectives = fn.directives.filter((d): d is CaseDirective => d.kind === "case");
28
- for (const dir of caseDirectives) {
29
- const result = evaluateFunctionFull(fn.node, dir.args, env);
30
- results.push({
31
- name: fn.name,
32
- caseName: dir.name,
33
- result: typeValueToString(result.value),
34
- });
35
- }
36
- }
37
- return results;
38
- }
39
-
40
- describe("Mock Arrow Functions", () => {
41
- it("supports arrow function mock with direct call", () => {
42
- const results = inferWithMocks(`
43
- // @nudo:mock fn = (x) => x > 3
44
- // @nudo:case "num" (5)
45
- function test(x) {
46
- return fn(x);
47
- }
48
- `);
49
- // fn(5) should return true since 5 > 3
50
- expect(results[0].result).toBe("true");
51
- });
52
-
53
- it("supports arrow function mock for filter", () => {
54
- const results = inferWithMocks(`
55
- // @nudo:mock fn = (x) => x > 3
56
- // @nudo:case "nums" ([1, 2, 3, 4, 5])
57
- function filter(arr) {
58
- const result = [];
59
- for (const item of arr) {
60
- if (fn(item)) result.push(item);
61
- }
62
- return result;
63
- }
64
- `);
65
- // Should filter to [4, 5]
66
- expect(results[0].result).toBe("[4, 5]");
67
- });
68
-
69
- it("supports arrow function mock with multiple params", () => {
70
- const results = inferWithMocks(`
71
- // @nudo:mock fn = (a, b) => a + b
72
- // @nudo:case "nums" ([1, 2, 3])
73
- function sum(arr) {
74
- return arr.reduce(fn, 0);
75
- }
76
- `);
77
- // reduce with (a, b) => a + b and [1, 2, 3] should give 6
78
- expect(results[0].result).toBe("6");
79
- });
80
-
81
- it("supports arrow function mock with string operations", () => {
82
- const results = inferWithMocks(`
83
- // @nudo:mock fn = (x) => x.toUpperCase()
84
- // @nudo:case "str" ("hello")
85
- function transform(x) {
86
- return fn(x);
87
- }
88
- `);
89
- // fn("hello") should return "HELLO"
90
- expect(results[0].result).toBe('"HELLO"');
91
- });
92
- });
93
-
94
- describe("Mock Arrow Functions: builtin HOF propagation", () => {
95
- it("mock arrow propagates through items.map(fn) with object results", () => {
96
- const results = inferWithMocks(`
97
- // @nudo:mock fn = (x) => ({ ok: true })
98
- // @nudo:case "items" ([1, 2, 3])
99
- function applyAll(items) {
100
- return items.map(fn);
101
- }
102
- `);
103
- // mock 函数值透传给 builtin HOF:与内联箭头 items.map(x => ({ ok: true })) 同机制
104
- expect(results[0].result).toBe("[{ ok: true }, { ok: true }, { ok: true }]");
105
- });
106
-
107
- it("mock arrow keeps propagating when the receiver is a union of arrays", () => {
108
- const results = inferWithMocks(`
109
- // @nudo:mock fn = (x) => ({ ok: true })
110
- // @nudo:case "go" ()
111
- function applyUnion() {
112
- const items = Math.random() > 0.5 ? [1, 2] : [3, 4, 5];
113
- return items.map(fn);
114
- }
115
- `);
116
- // union 接收者按成员分布求值,不再保守降级 unknown
117
- expect(results[0].result).toBe("[{ ok: true }, { ok: true }] | [{ ok: true }, { ok: true }, { ok: true }]");
118
- });
119
-
120
- it("mock arrow reduce(fn, 0) over a union receiver still accumulates", () => {
121
- const results = inferWithMocks(`
122
- // @nudo:mock add = (a, b) => a + b
123
- // @nudo:case "go" ()
124
- function sumUnion() {
125
- const xs = Math.random() > 0.5 ? [1, 2] : [3, 4, 5];
126
- return xs.reduce(add, 0);
127
- }
128
- `);
129
- expect(results[0].result).toBe("3 | 12");
130
- });
131
- });
132
-
133
- describe("Mock Arrow Functions: callback arg through call sites", () => {
134
- // 直接走 analyzer 主路径:mock 绑定必须先于全程序求值,顶层调用点
135
- // (mockHof([1,2,3]))在 evaluateProgram 中求值并记录 call@ case——
136
- // mock 晚于该点绑定会让「mock 函数值作为回调实参」整体降级 unknown。
137
- it("top-level call site: items.map(fn) with a mock arrow yields precise elements", () => {
138
- const result = analyzeFile("mock-hof-callsite.js", `
139
- // @nudo:mock fn = (x) => ({ ok: true, v: x })
140
- function mockHof(items) { return items.map(fn); }
141
- mockHof([1, 2, 3]);
142
- `);
143
- const fn = result.functions.find((f) => f.name === "mockHof");
144
- expect(fn).toBeDefined();
145
- expect(fn!.cases[0].source).toBe("callsite");
146
- expect(typeValueToString(fn!.cases[0].result)).toBe("[{ ok: true, v: 1 }, { ok: true, v: 2 }, { ok: true, v: 3 }]");
147
- });
148
-
149
- it("in-function call site: mock arrow through map/filter/reduce stays precise", () => {
150
- const result = analyzeFile("mock-hof-inner.js", `
151
- // @nudo:mock fn = (x) => ({ ok: true, v: x })
152
- // @nudo:mock pred = (x) => x > 1
153
- // @nudo:mock add = (a, b) => a + b
154
- function innerMap(items) { return items.map(fn); }
155
- function innerFilter(xs) { return xs.filter(pred); }
156
- function innerReduce(xs) { return xs.reduce(add, 0); }
157
- const a = innerMap([1, 2]);
158
- const b = innerFilter([1, 2, 3]);
159
- const c = innerReduce([1, 2, 3]);
160
- `);
161
- const map = result.functions.find((f) => f.name === "innerMap");
162
- const filter = result.functions.find((f) => f.name === "innerFilter");
163
- const reduce = result.functions.find((f) => f.name === "innerReduce");
164
- expect(typeValueToString(map!.cases[0].result)).toBe("[{ ok: true, v: 1 }, { ok: true, v: 2 }]");
165
- // filter 不丢元素类型
166
- expect(typeValueToString(filter!.cases[0].result)).toBe("2 | 3[]");
167
- expect(typeValueToString(reduce!.cases[0].result)).toBe("6");
168
- });
169
- });
@@ -1,221 +0,0 @@
1
- import { describe, it, expect, beforeAll } from "vitest";
2
- import { parse, extractDirectives, type CaseDirective, parseTypeValueExpr } from "@nudojs/parser";
3
- import { typeValueToString, createEnvironment, T } from "@nudojs/core";
4
- import { evaluateFunctionFull } from "../evaluator.js";
5
-
6
- function runNudoTest(source: string): { name: string; caseName: string; result: string }[] {
7
- const ast = parse(source);
8
- const directives = extractDirectives(ast);
9
- const env = createEnvironment();
10
- const results: { name: string; caseName: string; result: string }[] = [];
11
-
12
- for (const fn of directives) {
13
- for (const d of fn.directives) {
14
- if (d.kind === "mock") {
15
- if (d.arrowFn) {
16
- const fnType = T.fn(d.arrowFn.params, d.arrowFn.body, env);
17
- (fnType as any)._paramPatterns = d.arrowFn.paramPatterns;
18
- env.bind(d.name, fnType);
19
- } else if (d.expression) {
20
- env.bind(d.name, parseTypeValueExpr(d.expression));
21
- }
22
- }
23
- }
24
-
25
- const caseDirectives = fn.directives.filter((d): d is CaseDirective => d.kind === "case");
26
- for (const dir of caseDirectives) {
27
- const result = evaluateFunctionFull(fn.node, dir.args, env);
28
- results.push({
29
- name: fn.name,
30
- caseName: dir.name,
31
- result: typeValueToString(result.value),
32
- });
33
- }
34
- }
35
- return results;
36
- }
37
-
38
- describe("Nudo vs TypeScript 对比测试", () => {
39
- const source = `
40
- // 1. 数组处理管道
41
- // @nudo:mock validateItem = (item) => item !== null && item !== undefined
42
- // @nudo:mock transformItem = (item) => ({ ...item, processed: true })
43
- // @nudo:case "pipeline" ([{ id: 1 }, null, { id: 2 }, undefined, { id: 3 }])
44
- function processItems(items) {
45
- return items
46
- .filter(validateItem)
47
- .map(transformItem);
48
- }
49
-
50
- // 2. 事件处理器
51
- // @nudo:mock handler = (event) => ({ type: event.type, handled: true })
52
- // @nudo:case "event" ({ type: "click", target: "button" })
53
- function dispatchEvent(event) {
54
- const result = handler(event);
55
- return { ...result, timestamp: Date.now() };
56
- }
57
-
58
- // 3. API 客户端
59
- // @nudo:mock httpClient = (url, options) => ({ status: 200, data: { success: true } })
60
- // @nudo:case "api" ("/api/users", { method: "GET" })
61
- function fetchUsers(url, options) {
62
- const response = httpClient(url, options);
63
- if (response.status === 200) {
64
- return response.data;
65
- }
66
- return null;
67
- }
68
-
69
- // 4. 验证器组合
70
- // @nudo:mock isString = (v) => typeof v === "string"
71
- // @nudo:mock isNotEmpty = (v) => v.length > 0
72
- // @nudo:mock isEmail = (v) => v.includes("@")
73
- // @nudo:case "valid-email" ("user@example.com")
74
- // @nudo:case "empty" ("")
75
- // @nudo:case "number" (42)
76
- function validateEmail(value) {
77
- if (!isString(value)) return { valid: false, error: "not a string" };
78
- if (!isNotEmpty(value)) return { valid: false, error: "empty" };
79
- if (!isEmail(value)) return { valid: false, error: "invalid format" };
80
- return { valid: true, value };
81
- }
82
-
83
- // 5. 中间件链
84
- // @nudo:mock authMiddleware = (req) => ({ ...req, user: { id: 1 } })
85
- // @nudo:mock logMiddleware = (req) => req
86
- // @nudo:case "request" ({ path: "/api", method: "GET" })
87
- function applyMiddleware(req) {
88
- let result = req;
89
- result = authMiddleware(result);
90
- result = logMiddleware(result);
91
- return result;
92
- }
93
-
94
- // 6. 数据库查询构建器
95
- // @nudo:mock where = (field, op, value) => ({ field, op, value })
96
- // @nudo:mock orderBy = (field, dir) => ({ field, dir })
97
- // @nudo:case "query" ("age", ">", 18)
98
- function buildQuery(field, op, value) {
99
- const condition = where(field, op, value);
100
- const sort = orderBy("name", "asc");
101
- return { conditions: [condition], sort };
102
- }
103
-
104
- // 7. 缓存装饰器
105
- // @nudo:mock fetchFromDB = (id) => ({ id, name: "User " + id, cached: false })
106
- // @nudo:case "user" (42)
107
- function getUserWithCache(id) {
108
- const user = fetchFromDB(id);
109
- return { ...user, cached: true };
110
- }
111
-
112
- // 8. 策略模式
113
- // @nudo:mock pricingStrategy = (base, quantity) => base * quantity * 0.9
114
- // @nudo:case "order" (100, 5)
115
- function calculatePrice(basePrice, quantity) {
116
- return pricingStrategy(basePrice, quantity);
117
- }
118
-
119
- // 9. 异步操作
120
- // @nudo:mock asyncOperation = (data) => ({ result: data * 2 })
121
- // @nudo:case "async" (21)
122
- function processData(data) {
123
- const result = asyncOperation(data);
124
- return result;
125
- }
126
-
127
- // 10. 复杂嵌套
128
- // @nudo:mock outerFn = (x) => (y) => x + y
129
- // @nudo:case "curried" (10)
130
- function createAdder(x) {
131
- const adder = outerFn(x);
132
- return adder(5);
133
- }
134
- `;
135
-
136
- let results: { name: string; caseName: string; result: string }[];
137
-
138
- beforeAll(() => {
139
- results = runNudoTest(source);
140
- });
141
-
142
- it("1. processItems - 数组处理管道", () => {
143
- const r = results.find(r => r.caseName === "pipeline")!;
144
- console.log("pipeline:", r.result);
145
- expect(r.result).toContain("processed: true");
146
- });
147
-
148
- it("2. dispatchEvent - 事件处理", () => {
149
- const r = results.find(r => r.caseName === "event")!;
150
- console.log("event:", r.result);
151
- expect(r.result).toContain("handled: true");
152
- });
153
-
154
- it("3. fetchUsers - API 调用", () => {
155
- const r = results.find(r => r.caseName === "api")!;
156
- console.log("api:", r.result);
157
- expect(r.result).toContain("success: true");
158
- });
159
-
160
- it("4a. validateEmail - valid", () => {
161
- const r = results.find(r => r.caseName === "valid-email")!;
162
- console.log("valid-email:", r.result);
163
- expect(r.result).toContain("valid: true");
164
- });
165
-
166
- it("4b. validateEmail - empty", () => {
167
- const r = results.find(r => r.caseName === "empty")!;
168
- console.log("empty:", r.result);
169
- expect(r.result).toContain("valid: false");
170
- });
171
-
172
- it("4c. validateEmail - number", () => {
173
- const r = results.find(r => r.caseName === "number")!;
174
- console.log("number:", r.result);
175
- expect(r.result).toContain("not a string");
176
- });
177
-
178
- it("5. applyMiddleware - 中间件", () => {
179
- const r = results.find(r => r.caseName === "request")!;
180
- console.log("request:", r.result);
181
- expect(r.result).toContain("user:");
182
- });
183
-
184
- it("6. buildQuery - 查询构建", () => {
185
- const r = results.find(r => r.caseName === "query")!;
186
- console.log("query:", r.result);
187
- expect(r.result).toContain("conditions:");
188
- });
189
-
190
- it("7. getUserWithCache - 缓存", () => {
191
- const r = results.find(r => r.caseName === "user")!;
192
- console.log("user:", r.result);
193
- expect(r.result).toContain("cached: true");
194
- });
195
-
196
- it("8. calculatePrice - 策略", () => {
197
- const r = results.find(r => r.caseName === "order")!;
198
- console.log("order:", r.result);
199
- expect(r.result).toBe("450");
200
- });
201
-
202
- it("9. processData - 数据处理", () => {
203
- const r = results.find(r => r.caseName === "async")!;
204
- console.log("async:", r.result);
205
- expect(r.result).toContain("result: 42");
206
- });
207
-
208
- it("10. createAdder - 柯里化", () => {
209
- const r = results.find(r => r.caseName === "curried")!;
210
- console.log("curried:", r.result);
211
- expect(r.result).toBe("15");
212
- });
213
-
214
- it("输出完整结果", () => {
215
- console.log("\n=== Nudo @nudo:mock 测试结果 ===\n");
216
- for (const r of results) {
217
- console.log(`${r.name} - ${r.caseName}: ${r.result}`);
218
- }
219
- console.log(`\n总计: ${results.length} 个测试用例`);
220
- });
221
- });
@@ -1,250 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { parse, extractDirectives, type CaseDirective, parseTypeValueExpr } from "@nudojs/parser";
3
- import { typeValueToString, createEnvironment, T } from "@nudojs/core";
4
- import { evaluateFunctionFull } from "../evaluator.js";
5
-
6
- function inferWithMocks(source: string): { name: string; caseName: string; result: string }[] {
7
- const ast = parse(source);
8
- const directives = extractDirectives(ast);
9
- const env = createEnvironment();
10
- const results: { name: string; caseName: string; result: string }[] = [];
11
-
12
- for (const fn of directives) {
13
- // Apply mocks first
14
- for (const d of fn.directives) {
15
- if (d.kind === "mock") {
16
- if (d.arrowFn) {
17
- const fnType = T.fn(d.arrowFn.params, d.arrowFn.body, env);
18
- (fnType as any)._paramPatterns = d.arrowFn.paramPatterns;
19
- env.bind(d.name, fnType);
20
- } else if (d.expression) {
21
- env.bind(d.name, parseTypeValueExpr(d.expression));
22
- }
23
- }
24
- }
25
-
26
- const caseDirectives = fn.directives.filter((d): d is CaseDirective => d.kind === "case");
27
- for (const dir of caseDirectives) {
28
- const result = evaluateFunctionFull(fn.node, dir.args, env);
29
- results.push({
30
- name: fn.name,
31
- caseName: dir.name,
32
- result: typeValueToString(result.value),
33
- });
34
- }
35
- }
36
- return results;
37
- }
38
-
39
- describe("Comprehensive Mock Tests", () => {
40
- describe("Array method mocks", () => {
41
- it("supports filter with mock predicate", () => {
42
- const results = inferWithMocks(`
43
- // @nudo:mock isPositive = (x) => x > 0
44
- // @nudo:case "nums" ([-1, 2, -3, 4, -5])
45
- function filterPositive(arr) {
46
- return arr.filter(isPositive);
47
- }
48
- `);
49
- // filter returns a union type of elements that pass the predicate
50
- expect(results[0].result).toBe("2 | 4[]");
51
- });
52
-
53
- it("supports map with mock transform", () => {
54
- const results = inferWithMocks(`
55
- // @nudo:mock double = (x) => x * 2
56
- // @nudo:case "nums" ([1, 2, 3])
57
- function doubleAll(arr) {
58
- return arr.map(double);
59
- }
60
- `);
61
- expect(results[0].result).toBe("[2, 4, 6]");
62
- });
63
-
64
- it("supports reduce with mock reducer", () => {
65
- const results = inferWithMocks(`
66
- // @nudo:mock add = (a, b) => a + b
67
- // @nudo:case "nums" ([1, 2, 3, 4])
68
- function sumAll(arr) {
69
- return arr.reduce(add, 0);
70
- }
71
- `);
72
- expect(results[0].result).toBe("10");
73
- });
74
-
75
- it("supports find with mock predicate", () => {
76
- const results = inferWithMocks(`
77
- // @nudo:mock isEven = (x) => x % 2 === 0
78
- // @nudo:case "nums" ([1, 2, 3, 4, 5])
79
- function findFirstEven(arr) {
80
- return arr.find(isEven);
81
- }
82
- `);
83
- // find returns a union of all possible values plus undefined
84
- expect(results[0].result).toBe("1 | 2 | 3 | 4 | 5 | undefined");
85
- });
86
-
87
- it("supports some with mock predicate", () => {
88
- const results = inferWithMocks(`
89
- // @nudo:mock isNegative = (x) => x < 0
90
- // @nudo:case "nums" ([1, 2, 3])
91
- function hasNegative(arr) {
92
- return arr.some(isNegative);
93
- }
94
- `);
95
- expect(results[0].result).toBe("false");
96
- });
97
-
98
- it("supports every with mock predicate", () => {
99
- const results = inferWithMocks(`
100
- // @nudo:mock isPositive = (x) => x > 0
101
- // @nudo:case "nums" ([1, 2, 3])
102
- function allPositive(arr) {
103
- return arr.every(isPositive);
104
- }
105
- `);
106
- expect(results[0].result).toBe("true");
107
- });
108
- });
109
-
110
- describe("String method mocks", () => {
111
- it("supports split with mock separator", () => {
112
- const results = inferWithMocks(`
113
- // @nudo:mock separator = (x) => x === ","
114
- // @nudo:case "str" ("a,b,c")
115
- function splitByComma(str) {
116
- return str.split(separator);
117
- }
118
- `);
119
- // split with a function is not standard, but we test the mock mechanism
120
- expect(results[0].result).toBeDefined();
121
- });
122
- });
123
-
124
- describe("Higher-order function patterns", () => {
125
- it("supports function composition", () => {
126
- const results = inferWithMocks(`
127
- // @nudo:mock f = (x) => x + 1
128
- // @nudo:mock g = (x) => x * 2
129
- // @nudo:case "num" (5)
130
- function compose(x) {
131
- return f(g(x));
132
- }
133
- `);
134
- // g(5) = 10, f(10) = 11
135
- expect(results[0].result).toBe("11");
136
- });
137
-
138
- it("supports function as return value", () => {
139
- const results = inferWithMocks(`
140
- // @nudo:mock multiplier = (factor) => (x) => x * factor
141
- // @nudo:case "num" (5)
142
- function getDouble(x) {
143
- const double = multiplier(2);
144
- return double(x);
145
- }
146
- `);
147
- // This tests that mock can return functions
148
- expect(results[0].result).toBeDefined();
149
- });
150
-
151
- it("supports callback pattern", () => {
152
- const results = inferWithMocks(`
153
- // @nudo:mock callback = (result) => result
154
- // @nudo:case "num" (42)
155
- function processWithCallback(x) {
156
- const processed = x * 2;
157
- return callback(processed);
158
- }
159
- `);
160
- // callback(84) should return 84
161
- expect(results[0].result).toBe("84");
162
- });
163
- });
164
-
165
- describe("Multiple mock interactions", () => {
166
- it("supports multiple mocks working together", () => {
167
- const results = inferWithMocks(`
168
- // @nudo:mock predicate = (x) => x > 2
169
- // @nudo:mock transform = (x) => x * 10
170
- // @nudo:case "nums" ([1, 2, 3, 4, 5])
171
- function filterAndTransform(arr) {
172
- const filtered = [];
173
- for (const item of arr) {
174
- if (predicate(item)) {
175
- filtered.push(transform(item));
176
- }
177
- }
178
- return filtered;
179
- }
180
- `);
181
- // Filter items > 2: [3, 4, 5], then transform: [30, 40, 50]
182
- expect(results[0].result).toBe("[30, 40, 50]");
183
- });
184
- });
185
-
186
- describe("Edge cases", () => {
187
- it("handles mock with no parameters", () => {
188
- const results = inferWithMocks(`
189
- // @nudo:mock getter = () => 42
190
- // @nudo:case "empty" ()
191
- function getValue() {
192
- return getter();
193
- }
194
- `);
195
- expect(results[0].result).toBe("42");
196
- });
197
-
198
- it("handles mock with rest parameters", () => {
199
- const results = inferWithMocks(`
200
- // @nudo:mock sum = (...args) => args.length
201
- // @nudo:case "nums" ([1, 2, 3])
202
- function countArgs(arr) {
203
- return sum(...arr);
204
- }
205
- `);
206
- // Rest parameters collect all arguments into a tuple
207
- expect(results[0].result).toBe("3");
208
- });
209
-
210
- it("handles mock with complex expressions", () => {
211
- const results = inferWithMocks(`
212
- // @nudo:mock calc = (a, b) => (a + b) * (a - b)
213
- // @nudo:case "nums" (5, 3)
214
- function calculate(a, b) {
215
- return calc(a, b);
216
- }
217
- `);
218
- // calc(5, 3) = (5+3) * (5-3) = 8 * 2 = 16
219
- expect(results[0].result).toBe("16");
220
- });
221
- });
222
-
223
- describe("Integration with type narrowing", () => {
224
- it("supports mock with typeof narrowing", () => {
225
- const results = inferWithMocks(`
226
- // @nudo:mock processor = (x) => typeof x === "string" ? x.toUpperCase() : x
227
- // @nudo:case "str" ("hello")
228
- // @nudo:case "num" (42)
229
- function process(x) {
230
- return processor(x);
231
- }
232
- `);
233
- expect(results[0].result).toBe('"HELLO"');
234
- expect(results[1].result).toBe("42");
235
- });
236
-
237
- it("supports mock with conditional logic", () => {
238
- const results = inferWithMocks(`
239
- // @nudo:mock validator = (x) => x > 0 && x < 100
240
- // @nudo:case "valid" (50)
241
- // @nudo:case "invalid" (150)
242
- function validate(x) {
243
- return validator(x);
244
- }
245
- `);
246
- expect(results[0].result).toBe("true");
247
- expect(results[1].result).toBe("false");
248
- });
249
- });
250
- });