@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,345 +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("Syntax Sugar Tests", () => {
27
- describe("Compound Assignment Operators", () => {
28
- it("+=", () => {
29
- const results = runTest(`
30
- // @nudo:case "add-assign" ([1, 2, 3, 4, 5])
31
- function sum(arr) {
32
- let total = 0;
33
- for (const n of arr) {
34
- total += n;
35
- }
36
- return total;
37
- }
38
- `);
39
- expect(results[0].result).toBe("15");
40
- });
41
-
42
- it("-=", () => {
43
- const results = runTest(`
44
- // @nudo:case "sub-assign" (100, [10, 20, 30])
45
- function subtract(initial, values) {
46
- let result = initial;
47
- for (const v of values) {
48
- result -= v;
49
- }
50
- return result;
51
- }
52
- `);
53
- expect(results[0].result).toBe("40");
54
- });
55
-
56
- it("*=", () => {
57
- const results = runTest(`
58
- // @nudo:case "mul-assign" ([2, 3, 4])
59
- function product(arr) {
60
- let result = 1;
61
- for (const n of arr) {
62
- result *= n;
63
- }
64
- return result;
65
- }
66
- `);
67
- expect(results[0].result).toBe("24");
68
- });
69
-
70
- it("/=", () => {
71
- const results = runTest(`
72
- // @nudo:case "div-assign" (1000, [2, 5])
73
- function divide(initial, divisors) {
74
- let result = initial;
75
- for (const d of divisors) {
76
- result /= d;
77
- }
78
- return result;
79
- }
80
- `);
81
- expect(results[0].result).toBe("100");
82
- });
83
-
84
- it("%=", () => {
85
- const results = runTest(`
86
- // @nudo:case "mod-assign" (17, [5, 3])
87
- function modChain(initial, divisors) {
88
- let result = initial;
89
- for (const d of divisors) {
90
- result %= d;
91
- }
92
- return result;
93
- }
94
- `);
95
- expect(results[0].result).toBe("2");
96
- });
97
-
98
- it("string +=", () => {
99
- const results = runTest(`
100
- // @nudo:case "concat-assign" (["Hello", " ", "World"])
101
- function concat(parts) {
102
- let result = "";
103
- for (const part of parts) {
104
- result += part;
105
- }
106
- return result;
107
- }
108
- `);
109
- expect(results[0].result).toBe('"Hello World"');
110
- });
111
- });
112
-
113
- describe("Object Method Shorthand", () => {
114
- it("basic method shorthand", () => {
115
- const results = runTest(`
116
- // @nudo:case "method" ()
117
- function createObj() {
118
- return {
119
- greet(name) {
120
- return "Hello, " + name;
121
- }
122
- };
123
- }
124
- `);
125
- expect(results[0].result).toContain("greet");
126
- });
127
-
128
- it("multiple methods", () => {
129
- const results = runTest(`
130
- // @nudo:case "methods" ()
131
- function createCalculator() {
132
- return {
133
- add(a, b) { return a + b; },
134
- subtract(a, b) { return a - b; },
135
- multiply(a, b) { return a * b; }
136
- };
137
- }
138
- `);
139
- expect(results[0].result).toContain("add");
140
- expect(results[0].result).toContain("subtract");
141
- expect(results[0].result).toContain("multiply");
142
- });
143
-
144
- it("method with rest parameters", () => {
145
- const results = runTest(`
146
- // @nudo:case "rest-params" ()
147
- function createLogger() {
148
- return {
149
- log(...args) {
150
- return args;
151
- }
152
- };
153
- }
154
- `);
155
- expect(results[0].result).toContain("log");
156
- });
157
-
158
- it("mixed properties and methods", () => {
159
- const results = runTest(`
160
- // @nudo:case "mixed" ()
161
- function createService() {
162
- return {
163
- name: "MyService",
164
- version: 1,
165
- start() { return "started"; },
166
- stop() { return "stopped"; }
167
- };
168
- }
169
- `);
170
- expect(results[0].result).toContain("name");
171
- expect(results[0].result).toContain("version");
172
- expect(results[0].result).toContain("start");
173
- expect(results[0].result).toContain("stop");
174
- });
175
- });
176
-
177
- describe("Async/Await Combinations", () => {
178
- it("async function returning literal", () => {
179
- const results = runTest(`
180
- // @nudo:case "async-literal" ()
181
- async function getValue() {
182
- return 42;
183
- }
184
- `);
185
- expect(results[0].result).toBe("Promise<42>");
186
- });
187
-
188
- it("async function returning Promise", () => {
189
- const results = runTest(`
190
- // @nudo:case "async-promise" ()
191
- async function getValue() {
192
- return Promise.resolve(42);
193
- }
194
- `);
195
- expect(results[0].result).toBe("Promise<42>");
196
- });
197
-
198
- it("async function with await", () => {
199
- const results = runTest(`
200
- // @nudo:case "async-await" ()
201
- async function getValue() {
202
- const result = await Promise.resolve(42);
203
- return result;
204
- }
205
- `);
206
- expect(results[0].result).toBe("Promise<42>");
207
- });
208
-
209
- it("async function with try/catch", () => {
210
- const results = runTest(`
211
- // @nudo:case "async-try-catch" ()
212
- async function safeOperation() {
213
- try {
214
- const result = await Promise.resolve("success");
215
- return { success: true, data: result };
216
- } catch (e) {
217
- return { success: false, error: "failed" };
218
- }
219
- }
220
- `);
221
- expect(results[0].result).toContain("Promise");
222
- expect(results[0].result).toContain("success");
223
- });
224
-
225
- it("async function with multiple awaits", () => {
226
- const results = runTest(`
227
- // @nudo:case "async-multi-await" ()
228
- async function fetchAll() {
229
- const a = await Promise.resolve(1);
230
- const b = await Promise.resolve(2);
231
- return [a, b];
232
- }
233
- `);
234
- expect(results[0].result).toBe("Promise<[1, 2]>");
235
- });
236
- });
237
-
238
- describe("Destructuring Patterns", () => {
239
- it("object destructuring in parameters", () => {
240
- const results = runTest(`
241
- // @nudo:case "destructure-obj" ({ name: "Alice", age: 30 })
242
- function greet({ name, age }) {
243
- return name + " is " + age;
244
- }
245
- `);
246
- expect(results[0].result).toBe('"Alice is 30"');
247
- });
248
-
249
- it("array destructuring in parameters", () => {
250
- const results = runTest(`
251
- // @nudo:case "destructure-arr" ([1, 2, 3])
252
- function sum([a, b, c]) {
253
- return a + b + c;
254
- }
255
- `);
256
- expect(results[0].result).toBe("6");
257
- });
258
-
259
- it("nested destructuring", () => {
260
- const results = runTest(`
261
- // @nudo:case "destructure-nested" ({ user: { name: "Alice", address: { city: "NYC" } } })
262
- function getCity({ user: { address: { city } } }) {
263
- return city;
264
- }
265
- `);
266
- expect(results[0].result).toBe('"NYC"');
267
- });
268
-
269
- it("destructuring with defaults", () => {
270
- const results = runTest(`
271
- // @nudo:case "destructure-default" ({ name: "Alice" })
272
- function greet({ name, greeting = "Hello" }) {
273
- return greeting + ", " + name;
274
- }
275
- `);
276
- expect(results[0].result).toBe('"Hello, Alice"');
277
- });
278
- });
279
-
280
- describe("Template Literals", () => {
281
- it("basic template literal", () => {
282
- const results = runTest(`
283
- // @nudo:case "template" ("World")
284
- function greet(name) {
285
- return \`Hello, \${name}!\`;
286
- }
287
- `);
288
- expect(results[0].result).toBe('"Hello, World!"');
289
- });
290
-
291
- it("template literal with expressions", () => {
292
- const results = runTest(`
293
- // @nudo:case "template-expr" (2, 3)
294
- function calculate(a, b) {
295
- return \`\${a} + \${b} = \${a + b}\`;
296
- }
297
- `);
298
- expect(results[0].result).toBe('"2 + 3 = 5"');
299
- });
300
- });
301
-
302
- describe("Optional Chaining", () => {
303
- it("basic optional chaining", () => {
304
- const results = runTest(`
305
- // @nudo:case "optional-chain" ({ user: { name: "Alice" } })
306
- function getName(obj) {
307
- return obj?.user?.name;
308
- }
309
- `);
310
- expect(results[0].result).toBe('"Alice"');
311
- });
312
-
313
- it("optional chaining with undefined", () => {
314
- const results = runTest(`
315
- // @nudo:case "optional-undefined" ({})
316
- function getName(obj) {
317
- return obj?.user?.name;
318
- }
319
- `);
320
- expect(results[0].result).toBe("undefined");
321
- });
322
- });
323
-
324
- describe("Nullish Coalescing", () => {
325
- it("basic nullish coalescing", () => {
326
- const results = runTest(`
327
- // @nudo:case "nullish" (null)
328
- function getValue(x) {
329
- return x ?? "default";
330
- }
331
- `);
332
- expect(results[0].result).toBe('"default"');
333
- });
334
-
335
- it("nullish with defined value", () => {
336
- const results = runTest(`
337
- // @nudo:case "nullish-defined" ("hello")
338
- function getValue(x) {
339
- return x ?? "default";
340
- }
341
- `);
342
- expect(results[0].result).toBe('"hello"');
343
- });
344
- });
345
- });
@@ -1,17 +0,0 @@
1
- import { type TypeValue, T } from "@nudojs/core";
2
-
3
- export const INTL_DATETIMEFORMAT_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
4
- format: () => T.string,
5
- };
6
-
7
- export const INTL_NUMBERFORMAT_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
8
- format: () => T.string,
9
- };
10
-
11
- export function createDateTimeFormatType(): TypeValue {
12
- return T.instanceOf("DateTimeFormat", {});
13
- }
14
-
15
- export function createNumberFormatType(): TypeValue {
16
- return T.instanceOf("NumberFormat", {});
17
- }
@@ -1,174 +0,0 @@
1
- import { type TypeValue, T, simplifyUnion, typeValueEquals } from "@nudojs/core";
2
-
3
- // Literal/instance keys recorded at construction (`new Map([['k', v]])`) or
4
- // via set() — precise enough for typeValueEquals lookup. Symbolic keys are
5
- // skipped: they cannot be definitely matched, so get() falls back to the
6
- // V | undefined approximation.
7
- export type MapEntry = { key: TypeValue; value: TypeValue };
8
-
9
- function entryKeyTrackable(key: TypeValue | undefined): boolean {
10
- return key?.kind === "literal" || key?.kind === "instance";
11
- }
12
-
13
- // Union keys distribute: every member hitting → union of values, every
14
- // member missing → undefined, mixed → values | undefined.
15
- function lookupEntries(entries: MapEntry[], key: TypeValue): TypeValue | null {
16
- if (key.kind === "union") {
17
- const results = key.members.map((m) => lookupEntries(entries, m));
18
- if (results.some((r) => r === null)) return null;
19
- return simplifyUnion(results as TypeValue[]);
20
- }
21
- if (!entryKeyTrackable(key)) return null;
22
- const hit = entries.find((e) => typeValueEquals(e.key, key));
23
- return hit ? hit.value : T.undefined;
24
- }
25
-
26
- export const MAP_INSTANCE_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
27
- get: (key: TypeValue, map?: TypeValue) => {
28
- const entries = exactMapEntries(map);
29
- if (entries) {
30
- const looked = lookupEntries(entries, key);
31
- if (looked !== null) return looked;
32
- }
33
- const typeArgs = (map as any)?._typeArgs;
34
- if (typeArgs?.V) return T.union(typeArgs.V, T.undefined);
35
- // Untyped receiver (unknown / non-Map value reaching the impl): a
36
- // definite undefined would be a false claim and poison downstream
37
- // guards (hoek isDeepEqual's `ref.name` path) into error-severity
38
- // misses. Unknown keeps it honest.
39
- return T.unknown;
40
- },
41
- set: (key: TypeValue, value: TypeValue, map?: TypeValue) => {
42
- if (map) {
43
- const typeArgs = (map as any)._typeArgs || { K: T.unknown, V: T.unknown };
44
- (map as any)._typeArgs = {
45
- K: typeArgs.K.kind === "unknown" ? key : simplifyUnion([typeArgs.K, key]),
46
- V: typeArgs.V.kind === "unknown" ? value : simplifyUnion([typeArgs.V, value]),
47
- };
48
- if (entryKeyTrackable(key)) {
49
- // An exact entry list can start on the first trackable set()
50
- // (nothing untracked came before); once partial it stays partial.
51
- if ((map as any)._entries === undefined && (map as any)._entriesExact !== false) {
52
- (map as any)._entries = [];
53
- (map as any)._entriesExact = true;
54
- }
55
- if ((map as any)._entriesExact) {
56
- const entries = (map as any)._entries as MapEntry[];
57
- const hit = entries.find((e) => typeValueEquals(e.key, key));
58
- if (hit) hit.value = value;
59
- else entries.push({ key, value });
60
- }
61
- } else {
62
- (map as any)._entriesExact = false;
63
- }
64
- }
65
- return map ?? T.unknown;
66
- },
67
- has: (key: TypeValue, map?: TypeValue) => {
68
- const entries = exactMapEntries(map);
69
- if (entries && entryKeyTrackable(key)) {
70
- return T.literal(entries.some((e) => typeValueEquals(e.key, key)));
71
- }
72
- return T.boolean;
73
- },
74
- delete: (key: TypeValue, map?: TypeValue) => {
75
- const entries = exactMapEntries(map);
76
- if (entries && entryKeyTrackable(key)) {
77
- const idx = entries.findIndex((e) => typeValueEquals(e.key, key));
78
- if (idx >= 0) {
79
- entries.splice(idx, 1);
80
- return T.literal(true);
81
- }
82
- return T.literal(false);
83
- }
84
- return T.boolean;
85
- },
86
- clear: (value?: TypeValue, map?: TypeValue) => {
87
- // m.clear() arrives as clear(receiver): the map sits in the first
88
- // param slot when the call has no arguments.
89
- const target = map ?? value;
90
- if (target && (target as any)._entriesExact) {
91
- (target as any)._entries = [];
92
- }
93
- return T.undefined;
94
- },
95
- forEach: () => T.undefined,
96
- keys: (map?: TypeValue) => {
97
- const entries = exactMapEntries(map);
98
- if (entries) return T.tuple(entries.map((e) => e.key));
99
- const typeArgs = (map as any)?._typeArgs;
100
- if (typeArgs?.K) return T.array(typeArgs.K);
101
- return T.array(T.unknown);
102
- },
103
- values: (map?: TypeValue) => {
104
- const entries = exactMapEntries(map);
105
- if (entries) return T.tuple(entries.map((e) => e.value));
106
- const typeArgs = (map as any)?._typeArgs;
107
- if (typeArgs?.V) return T.array(typeArgs.V);
108
- return T.array(T.unknown);
109
- },
110
- entries: (map?: TypeValue) => mapEntriesIterable(map),
111
- };
112
-
113
- // Exact entry side table: present only when every key seen so far
114
- // (construction pairs + set() calls) was trackable. Partial tables must
115
- // not decide get()/has()/delete()/iteration — an untracked key could map
116
- // to anything.
117
- export function exactMapEntries(map: TypeValue | undefined): MapEntry[] | undefined {
118
- if (!map || (map as any)._entriesExact !== true) return undefined;
119
- return (map as any)._entries as MapEntry[] | undefined;
120
- }
121
-
122
- // entries() keeps feeding for-of destructuring (`for (const [k, v] of m)`)
123
- // and `new Map(...)` consumers: a tuple of [key, value] pairs when the
124
- // side table is complete, else Array<[K, V]>.
125
- export function mapEntriesIterable(map: TypeValue | undefined): TypeValue {
126
- const entries = exactMapEntries(map);
127
- if (entries) return T.tuple(entries.map((e) => T.tuple([e.key, e.value])));
128
- const typeArgs = (map as any)?._typeArgs;
129
- if (typeArgs?.K && typeArgs?.V) return T.array(T.tuple([typeArgs.K, typeArgs.V]));
130
- return T.array(T.tuple([T.unknown, T.unknown]));
131
- }
132
-
133
- export function createMapType(args?: TypeValue[]): TypeValue {
134
- const obj = T.instanceOf("Map", {});
135
-
136
- if (args && args.length > 0) {
137
- const arg = args[0];
138
- if (arg.kind === "tuple" || arg.kind === "array") {
139
- const elements = arg.kind === "tuple" ? arg.elements : [arg.element];
140
- const keys: TypeValue[] = [];
141
- const values: TypeValue[] = [];
142
- const entries: MapEntry[] = [];
143
- let exact = true;
144
- for (const el of elements) {
145
- if (el.kind === "tuple" && el.elements.length >= 2) {
146
- keys.push(el.elements[0]);
147
- values.push(el.elements[1]);
148
- if (entryKeyTrackable(el.elements[0])) {
149
- entries.push({ key: el.elements[0], value: el.elements[1] });
150
- } else {
151
- exact = false;
152
- }
153
- }
154
- }
155
- if (keys.length > 0) {
156
- (obj as any)._typeArgs = { K: simplifyUnion(keys), V: simplifyUnion(values) };
157
- }
158
- // Only a fully trackable key list is exact: symbolic keys mean the
159
- // recorded entries are a subset of the real ones.
160
- if (exact && entries.length > 0) {
161
- (obj as any)._entries = entries;
162
- (obj as any)._entriesExact = true;
163
- } else if (!exact) {
164
- (obj as any)._entriesExact = false;
165
- }
166
- }
167
- }
168
-
169
- if (!(obj as any)._typeArgs) {
170
- (obj as any)._typeArgs = { K: T.unknown, V: T.unknown };
171
- }
172
-
173
- return obj;
174
- }
@@ -1,116 +0,0 @@
1
- import { type TypeValue, T, simplifyUnion } from "@nudojs/core";
2
-
3
- export const PROMISE_STATIC_METHODS: Record<string, TypeValue> = {
4
- resolve: T.unknown,
5
- reject: T.never,
6
- all: T.unknown,
7
- race: T.unknown,
8
- allSettled: T.unknown,
9
- any: T.unknown,
10
- };
11
-
12
- export function evaluatePromiseStaticMethod(
13
- methodName: string,
14
- args: TypeValue[],
15
- ): TypeValue | null {
16
- if (methodName === "resolve") {
17
- if (args.length > 0) return T.promise(args[0]);
18
- return T.promise(T.undefined);
19
- }
20
-
21
- if (methodName === "reject") {
22
- return T.promise(T.never);
23
- }
24
-
25
- if (methodName === "all") {
26
- if (args.length > 0 && args[0].kind === "tuple") {
27
- const elemTypes = args[0].elements.map((e: TypeValue) => {
28
- if (e.kind === "promise") return e.value;
29
- return T.unknown;
30
- });
31
- return T.promise(T.tuple(elemTypes));
32
- }
33
- if (args.length > 0 && args[0].kind === "array") {
34
- return T.promise(T.array(args[0].element));
35
- }
36
- return T.promise(T.array(T.unknown));
37
- }
38
-
39
- if (methodName === "race") {
40
- if (args.length > 0 && args[0].kind === "tuple") {
41
- const elemTypes = args[0].elements.map((e: TypeValue) => {
42
- if (e.kind === "promise") return e.value;
43
- return T.unknown;
44
- });
45
- return T.promise(simplifyUnion(elemTypes));
46
- }
47
- if (args.length > 0 && args[0].kind === "array") {
48
- const el = args[0].element;
49
- return T.promise(el.kind === "promise" ? el.value : T.unknown);
50
- }
51
- return T.promise(T.unknown);
52
- }
53
-
54
- if (methodName === "allSettled") {
55
- // Best effort: each slot settles to { status, value } — the fulfilled
56
- // value is the element's promise payload (unknown for non-promises).
57
- const settledOf = (e: TypeValue): TypeValue =>
58
- T.object({
59
- status: T.union(T.literal("fulfilled"), T.literal("rejected")),
60
- value: e.kind === "promise" ? e.value : T.unknown,
61
- });
62
- if (args.length > 0 && args[0].kind === "tuple") {
63
- return T.promise(T.tuple(args[0].elements.map(settledOf)));
64
- }
65
- if (args.length > 0 && args[0].kind === "array") {
66
- return T.promise(T.array(settledOf(args[0].element)));
67
- }
68
- return T.promise(T.array(T.unknown));
69
- }
70
-
71
- if (methodName === "any") {
72
- if (args.length > 0 && args[0].kind === "tuple") {
73
- const elemTypes = args[0].elements.map((e: TypeValue) => {
74
- if (e.kind === "promise") return e.value;
75
- return T.unknown;
76
- });
77
- return T.promise(simplifyUnion(elemTypes));
78
- }
79
- if (args.length > 0 && args[0].kind === "array") {
80
- const el = args[0].element;
81
- return T.promise(el.kind === "promise" ? el.value : T.unknown);
82
- }
83
- return T.promise(T.unknown);
84
- }
85
-
86
- return null;
87
- }
88
-
89
- export function evaluatePromiseInstanceMethod(
90
- promiseValue: TypeValue,
91
- methodName: string,
92
- args: TypeValue[],
93
- ): TypeValue | null {
94
- if (methodName === "then") {
95
- if (promiseValue.kind === "promise") {
96
- // A real function callback is executed by the evaluator's main call
97
- // path (applyPromiseThenCallback) before reaching here; only
98
- // non-callable handlers fall through to an unresolved value type.
99
- return T.promise(T.unknown);
100
- }
101
- }
102
-
103
- if (methodName === "catch") {
104
- if (promiseValue.kind === "promise") {
105
- return promiseValue; // catch returns same promise type
106
- }
107
- }
108
-
109
- if (methodName === "finally") {
110
- if (promiseValue.kind === "promise") {
111
- return promiseValue; // finally returns same promise type
112
- }
113
- }
114
-
115
- return null;
116
- }
@@ -1,30 +0,0 @@
1
- import { type TypeValue, T } from "@nudojs/core";
2
-
3
- export const REFLECT_METHODS: Record<string, (...args: TypeValue[]) => TypeValue> = {
4
- has: () => T.boolean,
5
- get: () => T.unknown,
6
- set: () => T.boolean,
7
- deleteProperty: () => T.boolean,
8
- apply: () => T.unknown,
9
- construct: () => T.object({}),
10
- // Shape-aware like Object.keys: known receivers list their declared
11
- // own-property names (hoek's Utils.keys → clone/flatten key loops then
12
- // iterate concrete keys instead of a symbolic string), arrays add the
13
- // non-enumerable "length" own key. Unknown shapes keep the approximation.
14
- ownKeys: (target?: TypeValue) => {
15
- let base = target;
16
- while (base?.kind === "refined") base = base.base;
17
- if (base && (base.kind === "object" || base.kind === "instance")) {
18
- return T.tuple(Object.keys(base.properties).map((k) => T.literal(k)));
19
- }
20
- if (base?.kind === "tuple") {
21
- return T.tuple([
22
- ...base.elements.map((_, i) => T.literal(String(i))),
23
- T.literal("length"),
24
- ]);
25
- }
26
- return T.array(T.string);
27
- },
28
- getPrototypeOf: () => T.union(T.object({}), T.null),
29
- getOwnPropertyDescriptor: () => T.union(T.object({}), T.undefined),
30
- };