@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,430 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { parse, extractDirectives, type CaseDirective } from "@nudojs/parser";
3
- import { typeValueToString, createEnvironment } from "@nudojs/core";
4
- import { evaluateFunctionFull } from "../evaluator.js";
5
-
6
- function runTest(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
- const caseDirectives = fn.directives.filter((d): d is CaseDirective => d.kind === "case");
14
- for (const dir of caseDirectives) {
15
- const result = evaluateFunctionFull(fn.node, dir.args, env);
16
- results.push({
17
- name: fn.name,
18
- caseName: dir.name,
19
- result: typeValueToString(result.value),
20
- });
21
- }
22
- }
23
- return results;
24
- }
25
-
26
- describe("Real-World Pattern Tests", () => {
27
- describe("Data Processing Pipelines", () => {
28
- it("user data transformation", () => {
29
- const results = runTest(`
30
- // @nudo:case "transform-users" ([{ id: 1, firstName: "Alice", lastName: "Smith", active: true, isAdmin: false }, { id: 2, firstName: "Bob", lastName: "Jones", active: true, isAdmin: true }])
31
- function transformUsers(users) {
32
- return users
33
- .filter(u => u.active)
34
- .map(u => ({
35
- id: u.id,
36
- displayName: u.firstName + " " + u.lastName,
37
- role: u.isAdmin ? "admin" : "user"
38
- }));
39
- }
40
- `);
41
- expect(results[0].result).toContain("[");
42
- expect(results[0].result).toContain("displayName");
43
- expect(results[0].result).toContain("role");
44
- });
45
-
46
- it("group by key", () => {
47
- const results = runTest(`
48
- // @nudo:case "group-by" ([{ type: "a", value: 1 }, { type: "b", value: 2 }, { type: "a", value: 3 }])
49
- function groupByType(items) {
50
- const groups = new Map();
51
- for (const item of items) {
52
- if (!groups.has(item.type)) {
53
- groups.set(item.type, []);
54
- }
55
- groups.get(item.type).push(item.value);
56
- }
57
- return groups;
58
- }
59
- `);
60
- expect(results[0].result).toContain("Map");
61
- });
62
-
63
- it("flatten and deduplicate", () => {
64
- const results = runTest(`
65
- // @nudo:case "flatten-dedup" ([[1, 2], [2, 3], [3, 4]])
66
- function flattenDedup(arrays) {
67
- const flat = arrays.reduce((acc, arr) => acc.concat(arr), []);
68
- return Array.from(new Set(flat));
69
- }
70
- `);
71
- expect(results[0].result).toContain("[");
72
- });
73
- });
74
-
75
- describe("Error Handling Patterns", () => {
76
- it("Result type pattern", () => {
77
- const results = runTest(`
78
- // @nudo:case "result-type" (10, 2)
79
- function safeDivide(a, b) {
80
- try {
81
- if (b === 0) throw new Error("Division by zero");
82
- return { ok: true, value: a / b };
83
- } catch (e) {
84
- return { ok: false, error: e.message };
85
- }
86
- }
87
- `);
88
- expect(results[0].result).toContain("ok");
89
- expect(results[0].result).toContain("value");
90
- });
91
-
92
- it("retry pattern", () => {
93
- const results = runTest(`
94
- // @nudo:case "retry" ()
95
- async function withRetry(fn, maxRetries) {
96
- let lastError;
97
- for (let i = 0; i < maxRetries; i++) {
98
- try {
99
- return { success: true, data: await fn() };
100
- } catch (e) {
101
- lastError = e;
102
- }
103
- }
104
- return { success: false, error: "max retries exceeded" };
105
- }
106
- `);
107
- // Async function returns Promise
108
- expect(results[0].result).toContain("Promise");
109
- });
110
-
111
- it("validation pattern", () => {
112
- const results = runTest(`
113
- // @nudo:case "validate" ({ email: "test@example.com", age: 25 })
114
- function validateUser(user) {
115
- const errors = [];
116
- if (!user.email || !user.email.includes("@")) {
117
- errors.push("Invalid email");
118
- }
119
- if (user.age < 0 || user.age > 150) {
120
- errors.push("Invalid age");
121
- }
122
- return {
123
- valid: errors.length === 0,
124
- errors,
125
- user: errors.length === 0 ? user : undefined
126
- };
127
- }
128
- `);
129
- expect(results[0].result).toContain("valid");
130
- expect(results[0].result).toContain("errors");
131
- });
132
- });
133
-
134
- describe("Event Emitter Pattern", () => {
135
- it("basic event emitter", () => {
136
- const results = runTest(`
137
- // @nudo:case "emitter" ()
138
- function createEmitter() {
139
- const listeners = new Map();
140
- return {
141
- on(event, fn) {
142
- if (!listeners.has(event)) {
143
- listeners.set(event, []);
144
- }
145
- listeners.get(event).push(fn);
146
- },
147
- off(event, fn) {
148
- const fns = listeners.get(event);
149
- if (fns) {
150
- const idx = fns.indexOf(fn);
151
- if (idx >= 0) fns.splice(idx, 1);
152
- }
153
- },
154
- emit(event, ...args) {
155
- const fns = listeners.get(event);
156
- if (fns) {
157
- for (const fn of fns) fn(...args);
158
- }
159
- }
160
- };
161
- }
162
- `);
163
- expect(results[0].result).toContain("on");
164
- expect(results[0].result).toContain("off");
165
- expect(results[0].result).toContain("emit");
166
- });
167
- });
168
-
169
- describe("Configuration Patterns", () => {
170
- it("config with defaults", () => {
171
- const results = runTest(`
172
- // @nudo:case "config" ({ host: "localhost" })
173
- function createConfig(userConfig) {
174
- const defaults = {
175
- port: 3000,
176
- debug: false,
177
- logLevel: "info"
178
- };
179
- return { ...defaults, ...userConfig };
180
- }
181
- `);
182
- expect(results[0].result).toContain("host");
183
- expect(results[0].result).toContain("port");
184
- expect(results[0].result).toContain("debug");
185
- });
186
-
187
- it("config validation", () => {
188
- const results = runTest(`
189
- // @nudo:case "validate-config" ({ host: "localhost", port: 3000 })
190
- function validateConfig(config) {
191
- const errors = [];
192
- if (!config.host) errors.push("host is required");
193
- if (config.port < 1 || config.port > 65535) errors.push("port must be 1-65535");
194
- return {
195
- valid: errors.length === 0,
196
- errors,
197
- config: errors.length === 0 ? config : undefined
198
- };
199
- }
200
- `);
201
- expect(results[0].result).toContain("valid");
202
- expect(results[0].result).toContain("config");
203
- });
204
- });
205
-
206
- describe("API Response Patterns", () => {
207
- it("API response handler", () => {
208
- const results = runTest(`
209
- // @nudo:case "api-response" ({ statusCode: 200, body: { data: "test" }, headers: { "x-request-id": "123" } })
210
- function handleResponse(response) {
211
- if (!response) {
212
- return { status: "error", message: "No response" };
213
- }
214
- if (response.statusCode >= 200 && response.statusCode < 300) {
215
- return {
216
- status: "success",
217
- data: response.body,
218
- meta: { requestId: response.headers["x-request-id"] }
219
- };
220
- }
221
- if (response.statusCode >= 400) {
222
- return {
223
- status: "error",
224
- code: response.statusCode,
225
- message: response.body?.error || "Unknown error"
226
- };
227
- }
228
- return { status: "unknown", code: response.statusCode };
229
- }
230
- `);
231
- expect(results[0].result).toContain("success");
232
- expect(results[0].result).toContain("data");
233
- });
234
-
235
- it("paginated response", () => {
236
- const results = runTest(`
237
- // @nudo:case "paginate" ([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1, 3)
238
- function paginate(items, page, pageSize) {
239
- const start = (page - 1) * pageSize;
240
- const end = start + pageSize;
241
- const pageItems = items.slice(start, end);
242
- return {
243
- items: pageItems,
244
- page,
245
- pageSize,
246
- total: items.length,
247
- totalPages: Math.ceil(items.length / pageSize)
248
- };
249
- }
250
- `);
251
- expect(results[0].result).toContain("items");
252
- expect(results[0].result).toContain("page");
253
- expect(results[0].result).toContain("total");
254
- });
255
- });
256
-
257
- describe("State Management Patterns", () => {
258
- it("counter with actions", () => {
259
- const results = runTest(`
260
- // @nudo:case "counter" ()
261
- function createCounter(initial = 0) {
262
- let count = initial;
263
- return {
264
- increment() { return ++count; },
265
- decrement() { return --count; },
266
- reset() { count = initial; return count; },
267
- get() { return count; }
268
- };
269
- }
270
- `);
271
- expect(results[0].result).toContain("increment");
272
- expect(results[0].result).toContain("decrement");
273
- expect(results[0].result).toContain("reset");
274
- expect(results[0].result).toContain("get");
275
- });
276
-
277
- it("todo list", () => {
278
- const results = runTest(`
279
- // @nudo:case "todo-list" ()
280
- function createTodoList() {
281
- const todos = [];
282
- let nextId = 1;
283
- return {
284
- add(text) {
285
- const todo = { id: nextId++, text, completed: false };
286
- todos.push(todo);
287
- return todo;
288
- },
289
- complete(id) {
290
- const todo = todos.find(t => t.id === id);
291
- if (todo) todo.completed = true;
292
- return todo;
293
- },
294
- getAll() { return todos; },
295
- getActive() { return todos.filter(t => !t.completed); }
296
- };
297
- }
298
- `);
299
- expect(results[0].result).toContain("add");
300
- expect(results[0].result).toContain("complete");
301
- expect(results[0].result).toContain("getAll");
302
- expect(results[0].result).toContain("getActive");
303
- });
304
- });
305
-
306
- describe("Utility Functions", () => {
307
- it("deep clone", () => {
308
- const results = runTest(`
309
- // @nudo:case "deep-clone" ({ a: { b: { c: 1 } }, d: [1, 2, 3] })
310
- function deepClone(obj) {
311
- if (obj === null || typeof obj !== "object") return obj;
312
- if (Array.isArray(obj)) return obj.map(deepClone);
313
- const clone = {};
314
- for (const key in obj) {
315
- clone[key] = deepClone(obj[key]);
316
- }
317
- return clone;
318
- }
319
- `);
320
- expect(results[0].result).toContain("a");
321
- expect(results[0].result).toContain("b");
322
- expect(results[0].result).toContain("d");
323
- });
324
-
325
- it("debounce", () => {
326
- const results = runTest(`
327
- // @nudo:case "debounce" ()
328
- function createDebounce(fn, delay) {
329
- let timeoutId;
330
- return function(...args) {
331
- clearTimeout(timeoutId);
332
- timeoutId = setTimeout(() => fn(...args), delay);
333
- };
334
- }
335
- `);
336
- // Functions are displayed as arrow function syntax
337
- expect(results[0].result).toContain("=>");
338
- });
339
-
340
- it("memoize", () => {
341
- const results = runTest(`
342
- // @nudo:case "memoize" ()
343
- function memoize(fn) {
344
- const cache = new Map();
345
- return function(...args) {
346
- const key = JSON.stringify(args);
347
- if (cache.has(key)) return cache.get(key);
348
- const result = fn(...args);
349
- cache.set(key, result);
350
- return result;
351
- };
352
- }
353
- `);
354
- // Functions are displayed as arrow function syntax
355
- expect(results[0].result).toContain("=>");
356
- });
357
-
358
- it("escape dispatch through a string-keyed method table", () => {
359
- const results = runTest(`
360
- // @nudo:case "table-dispatch" (T.string)
361
- function escapeViaTable(char) {
362
- const Strings = {
363
- '<': () => 'LT',
364
- '>': () => 'GT',
365
- '&': () => 'AMP'
366
- };
367
- return Strings[char]();
368
- }
369
- `);
370
- // Strings[char] unions the table's functions; calling the union runs
371
- // each member, so the result is the union of their results.
372
- const r = results[0].result;
373
- expect(r).toContain("LT");
374
- expect(r).toContain("GT");
375
- expect(r).toContain("AMP");
376
- });
377
- });
378
- });
379
-
380
- describe("Named Function Callbacks through builtin HOFs", () => {
381
- it("arr.map(double) with a named function declaration yields precise literals", () => {
382
- const results = runTest(`
383
- // @nudo:case "xs" ([1, 2, 3])
384
- function doubleAll(xs) {
385
- function double(x) { return x * 2; }
386
- return xs.map(double);
387
- }
388
- `);
389
- // 具名函数回调从其 TypeValue 闭包求值,而非降级 unknown
390
- expect(results[0].result).toBe("[2, 4, 6]");
391
- });
392
-
393
- it("arr.reduce(sum, 0) with a named reducer yields number", () => {
394
- const results = runTest(`
395
- // @nudo:case "xs" ([1, 2, 3])
396
- function sumAll(xs) {
397
- function sum(a, b) { return a + b; }
398
- return xs.reduce(sum, 0);
399
- }
400
- `);
401
- expect(results[0].result).toBe("6");
402
- });
403
-
404
- it("arr.filter(big) with a named predicate keeps the element type", () => {
405
- const results = runTest(`
406
- // @nudo:case "xs" ([1, 2, 3, 4])
407
- function keepBig(xs) {
408
- function big(x) { return x > 2; }
409
- return xs.filter(big);
410
- }
411
- `);
412
- // 过滤结果元素类型不丢失:保留 3、4 字面量成员
413
- expect(results[0].result).toContain("3");
414
- expect(results[0].result).toContain("4");
415
- expect(results[0].result).toContain("[");
416
- });
417
-
418
- it("named callbacks over a union receiver distribute per member", () => {
419
- const results = runTest(`
420
- // @nudo:case "go" ()
421
- function pickThenMap() {
422
- const xs = Math.random() > 0.5 ? [1, 2] : [3, 4, 5];
423
- function double(x) { return x * 2; }
424
- return xs.map(double);
425
- }
426
- `);
427
- // union 接收者:每个数组成员分别经回调求值后 union
428
- expect(results[0].result).toBe("[2, 4] | [6, 8, 10]");
429
- });
430
- });