@nudojs/core 0.2.0 → 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.
package/dist/index.js CHANGED
@@ -1,3 +1,260 @@
1
+ import {
2
+ $add,
3
+ $arr,
4
+ $async,
5
+ $asyncReturn,
6
+ $await,
7
+ $call,
8
+ $callNamed,
9
+ $catchVal,
10
+ $class,
11
+ $concat,
12
+ $div,
13
+ $elems,
14
+ $eq,
15
+ $fnVal,
16
+ $for,
17
+ $forIter,
18
+ $forOf,
19
+ $fork,
20
+ $ge,
21
+ $gen,
22
+ $get,
23
+ $gt,
24
+ $idx,
25
+ $idxSet,
26
+ $invoke,
27
+ $invokeSuper,
28
+ $join,
29
+ $le,
30
+ $len,
31
+ $lit,
32
+ $lt,
33
+ $mod,
34
+ $mul,
35
+ $ne,
36
+ $neg,
37
+ $new,
38
+ $not,
39
+ $obj,
40
+ $optionalGet,
41
+ $optionalInvoke,
42
+ $orDefault,
43
+ $set,
44
+ $setKey,
45
+ $spread,
46
+ $staticInvoke,
47
+ $sub,
48
+ $super,
49
+ $switch,
50
+ $thisGet,
51
+ $thisSet,
52
+ $throw,
53
+ $typeof,
54
+ $while,
55
+ $whileSeq,
56
+ $yield,
57
+ DEFAULT_MAX_LOOP_ITERS,
58
+ MAX_CALL_DEPTH,
59
+ MAX_TOTAL_CALLS,
60
+ NudoThrow,
61
+ abs,
62
+ absFunction,
63
+ absToString,
64
+ add,
65
+ alphaOf,
66
+ analyzeFn,
67
+ and,
68
+ anyVar,
69
+ app,
70
+ applyAbsFn,
71
+ applyCallbackAbs,
72
+ asAbs,
73
+ asAbsVal,
74
+ attachFnImpl,
75
+ awaitAbs,
76
+ betaOf,
77
+ bindImports,
78
+ bool,
79
+ boolLit,
80
+ callAbsMethod,
81
+ callFunction,
82
+ callTranspiledExport,
83
+ callTranspiledExportFull,
84
+ classFromMethods,
85
+ clearBClasses,
86
+ cmp,
87
+ coerceAsyncReturn,
88
+ collapseToOptional,
89
+ collectAbsExports,
90
+ collectAbsNodeTypes,
91
+ concatString,
92
+ confJoin,
93
+ createHofCollectCtx,
94
+ createTemplateAbs,
95
+ currentExecPhi,
96
+ defaultLeakBudget,
97
+ defineClass,
98
+ definitelyNotNullishShape,
99
+ div,
100
+ emptyEnv,
101
+ emptyPhi,
102
+ eq,
103
+ evalArrayStatic,
104
+ evalBuiltinInstanceMethod,
105
+ evalBuiltinNew,
106
+ evalDateCtor,
107
+ evalDateMethod,
108
+ evalDateStatic,
109
+ evalGlobalFn,
110
+ evalJsonMethod,
111
+ evalMathMethod,
112
+ evalMethodBody,
113
+ evalNamespaceCall,
114
+ evalNode,
115
+ evalNumberStatic,
116
+ evalObjectMethod,
117
+ evalProgramAbs,
118
+ evalPromiseCtor,
119
+ evalPromiseStatic,
120
+ evalRegExpCtor,
121
+ evalRegExpMethod,
122
+ evalSource,
123
+ exceedsBudget,
124
+ falseConstraint,
125
+ findAbsAtPosition,
126
+ fnOf,
127
+ ge,
128
+ geNum,
129
+ getAbsOrigin,
130
+ getAbsProperty,
131
+ getBCallCollector,
132
+ getBClass,
133
+ getClass,
134
+ getClassChain,
135
+ getFnImpl,
136
+ getParseSourceCacheSize,
137
+ gt,
138
+ gtNum,
139
+ implies,
140
+ instanceOf,
141
+ instantiateClass,
142
+ instantiateReturn,
143
+ isDefinitelyFalse,
144
+ isDefinitelyTrue,
145
+ isExactLit,
146
+ isNudoThrow,
147
+ isNullishLitAbs,
148
+ isNumPrim,
149
+ isObj,
150
+ isRelFn,
151
+ isStrPrim,
152
+ isTemplateLike,
153
+ joinAbs,
154
+ joinFunctions,
155
+ joinObjects,
156
+ joinValues,
157
+ le,
158
+ leNum,
159
+ leakIfNeeded,
160
+ leqAbs,
161
+ lit,
162
+ litValue,
163
+ lookupMethod,
164
+ lookupMethodWithOwner,
165
+ lookupSuperMethod,
166
+ lt,
167
+ ltNum,
168
+ makeSum,
169
+ mapElementFallback,
170
+ maybeLeak,
171
+ mod,
172
+ mul,
173
+ ne,
174
+ negAbs,
175
+ never,
176
+ not,
177
+ notAbs,
178
+ noteMemberDispatchMiss,
179
+ notePrimMemberMissing,
180
+ noteUnknownMemberMissing,
181
+ num,
182
+ numLit,
183
+ numVar,
184
+ numericBounds,
185
+ obj,
186
+ objOf,
187
+ or,
188
+ pFalse,
189
+ pTrue,
190
+ parseSource,
191
+ phiAnd,
192
+ predEquals,
193
+ predToString,
194
+ predVars,
195
+ projectBrand,
196
+ projectFlatMapResult,
197
+ promoteParamShape,
198
+ ptypeof,
199
+ recordMemberDiag,
200
+ registerBClass,
201
+ relationFingerprint,
202
+ relationFn,
203
+ resetAbsCallBudget,
204
+ resetLeakCounter,
205
+ resetParseSourceCache,
206
+ runTranspiled,
207
+ setAbsAssignCollector,
208
+ setAbsCallCollector,
209
+ setAbsNodeCollector,
210
+ setAbsTruncationCollector,
211
+ setApplyCallbackHost,
212
+ setBCallCollector,
213
+ setMemberDiagCollector,
214
+ shapeOfTerm,
215
+ shapeOnlyFn,
216
+ shapeToString,
217
+ simplifyTerm,
218
+ snapshotAbs,
219
+ spread,
220
+ str,
221
+ strLit,
222
+ strictEqAbs,
223
+ stripTypes,
224
+ sub,
225
+ substAbs,
226
+ substPred,
227
+ substPredAbs,
228
+ superNameOf,
229
+ tagAbsOrigin,
230
+ templatePartsOf,
231
+ termDepth,
232
+ termEquals,
233
+ termNodes,
234
+ termToString,
235
+ transpile,
236
+ transpileExpression,
237
+ transpileFile,
238
+ transpileSource,
239
+ trueConstraint,
240
+ tryPromoteDirectCall,
241
+ tryPromoteForOfIteratee,
242
+ tryPromoteHofCallback,
243
+ tryPromoteReceiverAsArr,
244
+ typeofAbs,
245
+ undefAbs,
246
+ unknown,
247
+ v,
248
+ withExecPhi,
249
+ withVar,
250
+ wrapPromise
251
+ } from "./chunk-BU4A6XJ3.js";
252
+
253
+ // src/refinements/template-predicates.ts
254
+ function isTemplate(tv) {
255
+ return tv.kind === "refined" && Array.isArray(tv.refinement.meta.parts);
256
+ }
257
+
1
258
  // src/type-value.ts
2
259
  function createUnion(...members) {
3
260
  return simplifyUnion(members);
@@ -37,7 +294,17 @@ var T = {
37
294
  kind: "refined",
38
295
  base,
39
296
  refinement
40
- })
297
+ }),
298
+ fnSig: (paramTypes, returnType, throwsType = { kind: "never" }, impl) => {
299
+ const dummy = {
300
+ kind: "function",
301
+ params: paramTypes.map((_p, i) => `_arg${i}`),
302
+ body: { type: "BlockStatement", body: [], directives: [] },
303
+ closure: null
304
+ };
305
+ dummy._signature = { paramTypes, returnType, throwsType, impl };
306
+ return dummy;
307
+ }
41
308
  };
42
309
  function typeValueEquals(a, b) {
43
310
  if (a.kind !== b.kind) return false;
@@ -60,6 +327,23 @@ function typeValueEquals(a, b) {
60
327
  return a === b;
61
328
  }
62
329
  function simplifyUnion(members) {
330
+ if (members.length === 0) return T.never;
331
+ if (members.length === 1) return members[0].kind === "never" ? T.never : members[0];
332
+ if (members.length === 2) {
333
+ const a = members[0];
334
+ const b = members[1];
335
+ if (a.kind !== "union" && b.kind !== "union") {
336
+ if (a.kind === "never") return b.kind === "never" ? T.never : b;
337
+ if (b.kind === "never") return a;
338
+ if (typeValueEquals(a, b)) return a;
339
+ if (a.kind === "unknown" || b.kind === "unknown") return T.unknown;
340
+ const aBase = absorbablePrimitiveBase(a);
341
+ if (aBase !== void 0 && typeValueEquals(aBase, b)) return b;
342
+ const bBase = absorbablePrimitiveBase(b);
343
+ if (bBase !== void 0 && typeValueEquals(bBase, a)) return a;
344
+ return { kind: "union", members: [a, b] };
345
+ }
346
+ }
63
347
  const flat = [];
64
348
  for (const m of members) {
65
349
  if (m.kind === "never") continue;
@@ -75,30 +359,54 @@ function simplifyUnion(members) {
75
359
  deduped.push(m);
76
360
  }
77
361
  }
78
- if (deduped.length === 0) return T.never;
79
- if (deduped.length === 1) return deduped[0];
80
- if (deduped.some((m) => m.kind === "unknown")) return T.unknown;
81
- return { kind: "union", members: deduped };
362
+ const primitives = deduped.filter((m) => m.kind === "primitive");
363
+ const absorbed = primitives.length > 0 ? deduped.filter((m) => {
364
+ const base = absorbablePrimitiveBase(m);
365
+ return base === void 0 || !primitives.some((p) => typeValueEquals(p, base));
366
+ }) : deduped;
367
+ if (absorbed.length === 0) return T.never;
368
+ if (absorbed.length === 1) return absorbed[0];
369
+ if (absorbed.some((m) => m.kind === "unknown")) return T.unknown;
370
+ return { kind: "union", members: absorbed };
371
+ }
372
+ function absorbablePrimitiveBase(tv) {
373
+ if (tv.kind === "literal") {
374
+ const widened = widenLiteral(tv);
375
+ return widened.kind === "primitive" ? widened : void 0;
376
+ }
377
+ if (isTemplate(tv)) return T.string;
378
+ return void 0;
82
379
  }
83
380
  function widenLiteral(tv) {
84
381
  if (tv.kind !== "literal") return tv;
85
- const v = tv.value;
86
- if (typeof v === "number") return T.number;
87
- if (typeof v === "string") return T.string;
88
- if (typeof v === "boolean") return T.boolean;
89
- if (v === null) return T.null;
90
- if (v === void 0) return T.undefined;
382
+ const v2 = tv.value;
383
+ if (typeof v2 === "number") return T.number;
384
+ if (typeof v2 === "string") return T.string;
385
+ if (typeof v2 === "boolean") return T.boolean;
386
+ if (typeof v2 === "bigint") return T.bigint;
387
+ if (v2 === null) return T.null;
388
+ if (v2 === void 0) return T.undefined;
91
389
  return T.unknown;
92
390
  }
391
+ function collapseLiteralUnion(tv, maxLiterals) {
392
+ if (tv.kind !== "union") return tv;
393
+ if (tv.members.length <= maxLiterals) return tv;
394
+ const simplified = simplifyUnion(tv.members);
395
+ if (simplified.kind !== "union") return simplified;
396
+ if (!simplified.members.every((m) => m.kind === "literal")) return simplified;
397
+ const first = widenLiteral(simplified.members[0]);
398
+ if (!simplified.members.every((m) => typeValueEquals(widenLiteral(m), first))) return simplified;
399
+ return first;
400
+ }
93
401
  function isSubtypeOf(a, b) {
94
402
  if (b.kind === "unknown") return true;
95
403
  if (a.kind === "never") return true;
96
404
  if (typeValueEquals(a, b)) return true;
97
405
  if (a.kind === "literal" && b.kind === "primitive") {
98
- const v = a.value;
99
- if (b.type === "number" && typeof v === "number") return true;
100
- if (b.type === "string" && typeof v === "string") return true;
101
- if (b.type === "boolean" && typeof v === "boolean") return true;
406
+ const v2 = a.value;
407
+ if (b.type === "number" && typeof v2 === "number") return true;
408
+ if (b.type === "string" && typeof v2 === "string") return true;
409
+ if (b.type === "boolean" && typeof v2 === "boolean") return true;
102
410
  return false;
103
411
  }
104
412
  if (a.kind === "literal" && b.kind === "refined") {
@@ -161,8 +469,8 @@ function deepCloneTypeValue(tv, idMap) {
161
469
  map.set(tv.id, newId);
162
470
  }
163
471
  const newProps = {};
164
- for (const [k, v] of Object.entries(tv.properties)) {
165
- newProps[k] = deepCloneTypeValue(v, map);
472
+ for (const [k, v2] of Object.entries(tv.properties)) {
473
+ newProps[k] = deepCloneTypeValue(v2, map);
166
474
  }
167
475
  return { kind: "object", properties: newProps, id: newId };
168
476
  }
@@ -177,8 +485,8 @@ function deepCloneTypeValue(tv, idMap) {
177
485
  }
178
486
  if (tv.kind === "instance") {
179
487
  const newProps = {};
180
- for (const [k, v] of Object.entries(tv.properties)) {
181
- newProps[k] = deepCloneTypeValue(v, map);
488
+ for (const [k, v2] of Object.entries(tv.properties)) {
489
+ newProps[k] = deepCloneTypeValue(v2, map);
182
490
  }
183
491
  return { kind: "instance", className: tv.className, properties: newProps };
184
492
  }
@@ -205,13 +513,27 @@ function mergeObjectProperties(a, b) {
205
513
  return { kind: "object", properties: merged, id: a.id };
206
514
  }
207
515
  function typeValueToString(tv) {
516
+ return typeValueToStringInner(tv, /* @__PURE__ */ new Set());
517
+ }
518
+ function typeValueToStringInner(tv, seen, depth = 0) {
519
+ if (depth > 48) return "\u2026";
520
+ const recur = (inner) => {
521
+ if (inner && typeof inner === "object") {
522
+ if (seen.has(inner)) return "\u2026";
523
+ seen.add(inner);
524
+ const out = typeValueToStringInner(inner, seen, depth + 1);
525
+ seen.delete(inner);
526
+ return out;
527
+ }
528
+ return typeValueToStringInner(inner, seen, depth + 1);
529
+ };
208
530
  switch (tv.kind) {
209
531
  case "literal": {
210
- const v = tv.value;
211
- if (v === null) return "null";
212
- if (v === void 0) return "undefined";
213
- if (typeof v === "string") return JSON.stringify(v);
214
- return String(v);
532
+ const v2 = tv.value;
533
+ if (v2 === null) return "null";
534
+ if (v2 === void 0) return "undefined";
535
+ if (typeof v2 === "string") return JSON.stringify(v2);
536
+ return String(v2);
215
537
  }
216
538
  case "primitive":
217
539
  return tv.type;
@@ -220,29 +542,34 @@ function typeValueToString(tv) {
220
542
  case "object": {
221
543
  const entries = Object.entries(tv.properties);
222
544
  if (entries.length === 0) return "{}";
223
- const inner = entries.map(([k, v]) => `${k}: ${typeValueToString(v)}`).join(", ");
545
+ const inner = entries.map(([k, v2]) => `${k}: ${recur(v2)}`).join(", ");
224
546
  return `{ ${inner} }`;
225
547
  }
226
548
  case "array":
227
- return `${typeValueToString(tv.element)}[]`;
549
+ return `${recur(tv.element)}[]`;
228
550
  case "tuple": {
229
- const inner = tv.elements.map(typeValueToString).join(", ");
551
+ const inner = tv.elements.map(recur).join(", ");
230
552
  return `[${inner}]`;
231
553
  }
232
554
  case "function": {
555
+ const sig = getFnSig(tv);
556
+ if (sig) {
557
+ const params2 = sig.paramTypes.map((p, i) => `${tv.params[i]}: ${recur(p)}`).join(", ");
558
+ return `(${params2}) => ${recur(sig.returnType)}`;
559
+ }
233
560
  const params = tv.params.join(", ");
234
561
  return `(${params}) => ...`;
235
562
  }
236
563
  case "promise":
237
- return `Promise<${typeValueToString(tv.value)}>`;
564
+ return `Promise<${recur(tv.value)}>`;
238
565
  case "instance": {
239
566
  const entries = Object.entries(tv.properties);
240
567
  if (entries.length === 0) return tv.className;
241
- const inner = entries.map(([k, v]) => `${k}: ${typeValueToString(v)}`).join(", ");
568
+ const inner = entries.map(([k, v2]) => `${k}: ${recur(v2)}`).join(", ");
242
569
  return `${tv.className} { ${inner} }`;
243
570
  }
244
571
  case "union": {
245
- return tv.members.map(typeValueToString).join(" | ");
572
+ return tv.members.map(recur).join(" | ");
246
573
  }
247
574
  case "never":
248
575
  return "never";
@@ -261,9 +588,9 @@ function subtractType(tv, predicate) {
261
588
  }
262
589
  function getPrimitiveTypeOf(tv) {
263
590
  if (tv.kind === "literal") {
264
- const v = tv.value;
265
- if (v === null) return "object";
266
- return typeof v;
591
+ const v2 = tv.value;
592
+ if (v2 === null) return "object";
593
+ return typeof v2;
267
594
  }
268
595
  if (tv.kind === "primitive") return tv.type;
269
596
  if (tv.kind === "refined") return getPrimitiveTypeOf(tv.base);
@@ -277,6 +604,15 @@ function getPrimitiveTypeOf(tv) {
277
604
  function getRefinedBase(tv) {
278
605
  return tv.kind === "refined" ? getRefinedBase(tv.base) : tv;
279
606
  }
607
+ function isFnSig(tv) {
608
+ return tv.kind === "function" && "_signature" in tv;
609
+ }
610
+ function getFnSig(tv) {
611
+ if (tv.kind === "function" && "_signature" in tv) {
612
+ return tv._signature;
613
+ }
614
+ return void 0;
615
+ }
280
616
 
281
617
  // src/refinements/range.ts
282
618
  function formatRangeName(meta) {
@@ -491,9 +827,6 @@ function createTemplate(parts) {
491
827
  }
492
828
  return T.refine(T.string, createTemplateRefinement(normalized));
493
829
  }
494
- function isTemplate(tv) {
495
- return tv.kind === "refined" && Array.isArray(tv.refinement.meta.parts);
496
- }
497
830
  function getTemplateParts(tv) {
498
831
  if (tv.kind === "refined" && Array.isArray(tv.refinement.meta.parts)) {
499
832
  return tv.refinement.meta.parts;
@@ -513,11 +846,34 @@ function bothLiteral(l, r) {
513
846
  }
514
847
  return null;
515
848
  }
849
+ function isNullishLiteral(tv) {
850
+ return tv.kind === "literal" && (tv.value === null || tv.value === void 0);
851
+ }
852
+ function definitelyNotNullish(tv) {
853
+ switch (tv.kind) {
854
+ case "literal":
855
+ return tv.value !== null && tv.value !== void 0;
856
+ case "primitive":
857
+ case "object":
858
+ case "array":
859
+ case "tuple":
860
+ case "function":
861
+ case "instance":
862
+ case "promise":
863
+ return true;
864
+ case "refined":
865
+ return definitelyNotNullish(tv.base);
866
+ case "union":
867
+ return tv.members.every(definitelyNotNullish);
868
+ default:
869
+ return false;
870
+ }
871
+ }
516
872
  var Ops = {
517
873
  add(left, right) {
518
- const lit = bothLiteral(left, right);
519
- if (lit) {
520
- return T.literal(lit.lv + lit.rv);
874
+ const lit2 = bothLiteral(left, right);
875
+ if (lit2) {
876
+ return T.literal(lit2.lv + lit2.rv);
521
877
  }
522
878
  const leftIsString = isSubtypeOf(left, T.string) || isTemplate(left);
523
879
  const rightIsString = isSubtypeOf(right, T.string) || isTemplate(right);
@@ -533,97 +889,49 @@ var Ops = {
533
889
  }
534
890
  return T.union(T.number, T.string);
535
891
  },
536
- sub(left, right) {
537
- const lit = bothLiteral(left, right);
538
- if (lit && typeof lit.lv === "number" && typeof lit.rv === "number") {
539
- return T.literal(lit.lv - lit.rv);
540
- }
541
- return T.number;
542
- },
543
- mul(left, right) {
544
- const lit = bothLiteral(left, right);
545
- if (lit && typeof lit.lv === "number" && typeof lit.rv === "number") {
546
- return T.literal(lit.lv * lit.rv);
547
- }
548
- return T.number;
549
- },
550
- div(left, right) {
551
- const lit = bothLiteral(left, right);
552
- if (lit && typeof lit.lv === "number" && typeof lit.rv === "number") {
553
- return T.literal(lit.lv / lit.rv);
554
- }
555
- return T.number;
556
- },
557
- mod(left, right) {
558
- const lit = bothLiteral(left, right);
559
- if (lit && typeof lit.lv === "number" && typeof lit.rv === "number") {
560
- return T.literal(lit.lv % lit.rv);
561
- }
562
- return T.number;
563
- },
564
892
  strictEq(left, right) {
565
- const lit = bothLiteral(left, right);
566
- if (lit) return T.literal(lit.lv === lit.rv);
893
+ const lit2 = bothLiteral(left, right);
894
+ if (lit2) return T.literal(lit2.lv === lit2.rv);
895
+ if (isNullishLiteral(right) && definitelyNotNullish(left) || isNullishLiteral(left) && definitelyNotNullish(right)) {
896
+ return T.literal(false);
897
+ }
567
898
  return T.boolean;
568
899
  },
569
900
  strictNeq(left, right) {
570
- const lit = bothLiteral(left, right);
571
- if (lit) return T.literal(lit.lv !== lit.rv);
901
+ const lit2 = bothLiteral(left, right);
902
+ if (lit2) return T.literal(lit2.lv !== lit2.rv);
903
+ if (isNullishLiteral(right) && definitelyNotNullish(left) || isNullishLiteral(left) && definitelyNotNullish(right)) {
904
+ return T.literal(true);
905
+ }
572
906
  return T.boolean;
573
907
  },
574
908
  gt(left, right) {
575
- const lit = bothLiteral(left, right);
576
- if (lit) return T.literal(lit.lv > lit.rv);
909
+ const lit2 = bothLiteral(left, right);
910
+ if (lit2) return T.literal(lit2.lv > lit2.rv);
577
911
  return T.boolean;
578
912
  },
579
913
  lt(left, right) {
580
- const lit = bothLiteral(left, right);
581
- if (lit) return T.literal(lit.lv < lit.rv);
914
+ const lit2 = bothLiteral(left, right);
915
+ if (lit2) return T.literal(lit2.lv < lit2.rv);
582
916
  return T.boolean;
583
917
  },
584
918
  gte(left, right) {
585
- const lit = bothLiteral(left, right);
586
- if (lit) return T.literal(lit.lv >= lit.rv);
919
+ const lit2 = bothLiteral(left, right);
920
+ if (lit2) return T.literal(lit2.lv >= lit2.rv);
587
921
  return T.boolean;
588
922
  },
589
923
  lte(left, right) {
590
- const lit = bothLiteral(left, right);
591
- if (lit) return T.literal(lit.lv <= lit.rv);
924
+ const lit2 = bothLiteral(left, right);
925
+ if (lit2) return T.literal(lit2.lv <= lit2.rv);
592
926
  return T.boolean;
593
927
  },
594
- typeof_(operand) {
595
- if (operand.kind === "literal") {
596
- const v = operand.value;
597
- if (v === null) return T.literal("object");
598
- return T.literal(typeof v);
599
- }
600
- if (operand.kind === "primitive") return T.literal(operand.type);
601
- if (operand.kind === "refined") return Ops.typeof_(getRefinedBase(operand));
602
- if (operand.kind === "object") return T.literal("object");
603
- if (operand.kind === "array" || operand.kind === "tuple")
604
- return T.literal("object");
605
- if (operand.kind === "function") return T.literal("function");
606
- if (operand.kind === "promise") return T.literal("object");
607
- if (operand.kind === "instance") return T.literal("object");
608
- return T.string;
609
- },
610
928
  not(operand) {
611
929
  if (operand.kind === "literal") return T.literal(!operand.value);
612
930
  return T.boolean;
613
- },
614
- neg(operand) {
615
- if (operand.kind === "literal" && typeof operand.value === "number") {
616
- return T.literal(-operand.value);
617
- }
618
- return T.number;
619
931
  }
620
932
  };
621
933
  var binaryOpMap = {
622
934
  "+": Ops.add,
623
- "-": Ops.sub,
624
- "*": Ops.mul,
625
- "/": Ops.div,
626
- "%": Ops.mod,
627
935
  "===": Ops.strictEq,
628
936
  "!==": Ops.strictNeq,
629
937
  ">": Ops.gt,
@@ -697,11 +1005,14 @@ function createEnvironment(parent, bindings = /* @__PURE__ */ new Map()) {
697
1005
  },
698
1006
  extend(newBindings) {
699
1007
  const childMap = /* @__PURE__ */ new Map();
700
- for (const [k, v] of Object.entries(newBindings)) {
701
- childMap.set(k, v);
1008
+ for (const [k, v2] of Object.entries(newBindings)) {
1009
+ childMap.set(k, v2);
702
1010
  }
703
1011
  return createEnvironment(env, childMap);
704
1012
  },
1013
+ fork() {
1014
+ return createEnvironment(env);
1015
+ },
705
1016
  has(name) {
706
1017
  return store.has(name) || (parent?.has(name) ?? false);
707
1018
  },
@@ -712,40 +1023,4108 @@ function createEnvironment(parent, bindings = /* @__PURE__ */ new Map()) {
712
1023
  },
713
1024
  getOwnBindings() {
714
1025
  const result = {};
715
- for (const [k, v] of store) {
716
- result[k] = v;
1026
+ for (const [k, v2] of store) {
1027
+ result[k] = v2;
717
1028
  }
718
1029
  return result;
719
1030
  }
720
1031
  };
721
1032
  return env;
722
1033
  }
1034
+
1035
+ // src/mock-helpers.ts
1036
+ function stub() {
1037
+ return { kind: "mock-helper" };
1038
+ }
1039
+ stub.returns = function(value) {
1040
+ return { kind: "mock-helper", returnValue: value };
1041
+ };
1042
+ stub.resolves = function(value) {
1043
+ return { kind: "mock-helper", resolvedValue: value };
1044
+ };
1045
+ stub.rejects = function(value) {
1046
+ return { kind: "mock-helper", rejectedValue: value };
1047
+ };
1048
+ stub.onFirstCall = function(value) {
1049
+ return { kind: "mock-helper", onFirstCallValue: value };
1050
+ };
1051
+ stub.onSecondCall = function(value) {
1052
+ return { kind: "mock-helper", onSecondCallValue: value };
1053
+ };
1054
+ stub.withArgs = function(...args) {
1055
+ return { kind: "mock-helper", withArgsCases: [{ args, returnValue: T.unknown }] };
1056
+ };
1057
+ stub.callsFake = function(fn) {
1058
+ return { kind: "mock-helper", callsFakeImpl: fn };
1059
+ };
1060
+ function spy() {
1061
+ return { kind: "mock-helper" };
1062
+ }
1063
+ spy.returns = function(value) {
1064
+ return { kind: "mock-helper", returnValue: value };
1065
+ };
1066
+ function mock() {
1067
+ return { kind: "mock-helper" };
1068
+ }
1069
+ function mockArgMatches(declared, actual) {
1070
+ if (actual === void 0) return false;
1071
+ if (typeValueEquals(declared, actual)) return true;
1072
+ if (declared.kind === "primitive" && actual.kind === "literal") {
1073
+ const t = typeof actual.value;
1074
+ return declared.type === "number" && t === "number" || declared.type === "string" && t === "string" || declared.type === "boolean" && t === "boolean" || declared.type === "bigint" && t === "bigint" || declared.type === "symbol" && t === "symbol";
1075
+ }
1076
+ return false;
1077
+ }
1078
+ function mockHelperToTypeValue(helper, env) {
1079
+ if (helper.callsFakeImpl) {
1080
+ if (helper.callsFakeImpl.kind === "function") {
1081
+ return helper.callsFakeImpl;
1082
+ }
1083
+ const plain = T.fn(["...args"], { type: "BlockStatement", body: [] }, env);
1084
+ plain._directReturn = helper.callsFakeImpl;
1085
+ return plain;
1086
+ }
1087
+ let defaultReturn;
1088
+ if (helper.resolvedValue) {
1089
+ defaultReturn = T.promise(helper.resolvedValue);
1090
+ } else if (helper.rejectedValue) {
1091
+ defaultReturn = T.never;
1092
+ } else if (helper.returnValue) {
1093
+ defaultReturn = helper.returnValue;
1094
+ } else if (helper.onFirstCallValue) {
1095
+ defaultReturn = helper.onFirstCallValue;
1096
+ } else {
1097
+ defaultReturn = T.unknown;
1098
+ }
1099
+ if (helper.withArgsCases?.length) {
1100
+ const cases = helper.withArgsCases;
1101
+ return T.fnSig(
1102
+ cases[0].args.map(() => T.unknown),
1103
+ T.union(...cases.map((c) => c.returnValue), defaultReturn),
1104
+ T.never,
1105
+ (args) => {
1106
+ for (const c of cases) {
1107
+ if (c.args.every((a, i) => mockArgMatches(a, args[i]))) {
1108
+ return c.returnValue;
1109
+ }
1110
+ }
1111
+ return defaultReturn;
1112
+ }
1113
+ );
1114
+ }
1115
+ const body = { type: "BlockStatement", body: [] };
1116
+ const fn = T.fn(["...args"], body, env);
1117
+ fn._directReturn = defaultReturn;
1118
+ return fn;
1119
+ }
1120
+
1121
+ // src/algebra/phi.ts
1122
+ var phiStack = [pTrue];
1123
+ function currentPhi() {
1124
+ return phiStack[phiStack.length - 1] ?? pTrue;
1125
+ }
1126
+ function pushPhi(p) {
1127
+ phiStack.push(p);
1128
+ }
1129
+ function popPhi() {
1130
+ if (phiStack.length > 1) phiStack.pop();
1131
+ }
1132
+ function resetPhi() {
1133
+ phiStack = [pTrue];
1134
+ }
1135
+ function withPhiConstraint(extra, body) {
1136
+ pushPhi(extra);
1137
+ try {
1138
+ body();
1139
+ } finally {
1140
+ popPhi();
1141
+ }
1142
+ }
1143
+ function describePhi() {
1144
+ const p = currentPhi();
1145
+ return p.op === "true" ? "\u22A4" : "(phi)";
1146
+ }
1147
+
1148
+ // src/algebra/format.ts
1149
+ function formatAbs(a, opts = {}) {
1150
+ const showTerm = opts.showTerm !== false;
1151
+ const showPred = opts.showPred !== false;
1152
+ const parts = [];
1153
+ parts.push(formatShape(a));
1154
+ if (showTerm && a.term && a.term.op !== "lit") {
1155
+ parts.push(`= ${termToString(a.term)}`);
1156
+ }
1157
+ if (showPred && a.pred && a.pred.op !== "true") {
1158
+ parts.push(`where ${predToString(a.pred)}`);
1159
+ }
1160
+ parts.push(`#${a.conf}`);
1161
+ return parts.join(" ");
1162
+ }
1163
+ function formatShapeSlot(a) {
1164
+ const base = formatShape(a);
1165
+ if (!a.term || a.term.op === "lit") return base;
1166
+ if (a.shape.k === "fn" || a.shape.k === "arr") return base;
1167
+ if (a.shape.k === "any" && a.term.op === "var") return termToString(a.term);
1168
+ return `${base} = ${termToString(a.term)}`;
1169
+ }
1170
+ function formatShape(a) {
1171
+ const s = a.shape;
1172
+ switch (s.k) {
1173
+ case "never":
1174
+ return "never";
1175
+ case "any":
1176
+ return "any";
1177
+ case "unknown":
1178
+ return "unknown";
1179
+ case "prim": {
1180
+ const lv = litValue(a);
1181
+ if (lv !== void 0) return JSON.stringify(lv);
1182
+ return s.type;
1183
+ }
1184
+ case "obj": {
1185
+ const entries = Object.entries(s.slots).map(([k, slot]) => {
1186
+ const opt = slot.optional ? "?" : "";
1187
+ return `${k}${opt}: ${formatShape(slot.value)}`;
1188
+ });
1189
+ return `{ ${entries.join(", ")} }`;
1190
+ }
1191
+ case "arr": {
1192
+ if (s.element.shape.k === "any" && s.element.term?.op === "var") {
1193
+ return `arr(${formatShapeSlot(s.element)})`;
1194
+ }
1195
+ return `${formatShape(s.element)}[]`;
1196
+ }
1197
+ case "tuple":
1198
+ return `[${s.elements.map(formatShape).join(", ")}]`;
1199
+ case "fn": {
1200
+ if (s.paramTypes && s.paramTypes.length > 0) {
1201
+ const ps = s.paramTypes.map((p) => formatShapeSlot(p));
1202
+ const ret2 = s.returnType !== void 0 ? formatShapeSlot(s.returnType) : "?";
1203
+ return `(${ps.join(", ")}) => ${ret2}`;
1204
+ }
1205
+ const ret = s.returnType !== void 0 ? formatShapeSlot(s.returnType) : "?";
1206
+ return `(${s.params.join(", ")}) => ${ret}`;
1207
+ }
1208
+ case "brand":
1209
+ return `${s.name}`;
1210
+ case "eff":
1211
+ return `${s.eff}<${formatShape(s.inner)}>`;
1212
+ case "sum":
1213
+ return s.members.map(formatShape).join(" | ");
1214
+ default:
1215
+ return "\xB7";
1216
+ }
1217
+ }
1218
+ function formatAbsMultiline(a, label) {
1219
+ const lines = [];
1220
+ if (label) lines.push(label);
1221
+ lines.push(` ${formatShape(a)}`);
1222
+ if (a.term && a.term.op !== "lit") {
1223
+ lines.push(` term: ${termToString(a.term)}`);
1224
+ }
1225
+ if (a.pred && a.pred.op !== "true") {
1226
+ lines.push(` pred: ${predToString(a.pred)}`);
1227
+ }
1228
+ lines.push(` conf: ${a.conf}`);
1229
+ return lines.join("\n");
1230
+ }
1231
+
1232
+ // src/algebra/constraint.ts
1233
+ var SELF = "__nudo_self__";
1234
+ function selfTerm() {
1235
+ return v(SELF);
1236
+ }
1237
+ function getTerm(obj2, key) {
1238
+ return app("get", [obj2, lit(key)]);
1239
+ }
1240
+ function lenTerm(t) {
1241
+ return app("length", [t]);
1242
+ }
1243
+ function isConstraint(x) {
1244
+ return !!x && typeof x === "object" && x.__nudoConstraint === true;
1245
+ }
1246
+ function isNudoConstraint(x) {
1247
+ return isConstraint(x);
1248
+ }
1249
+ function makeBuilder(prim, preds, extra) {
1250
+ const fields = extra?.fields;
1251
+ const element = extra?.element;
1252
+ const isInt = extra?.int;
1253
+ const optional = extra?.optional;
1254
+ const base = {
1255
+ __nudoConstraint: true,
1256
+ ...prim ? { prim } : {},
1257
+ preds: [...preds],
1258
+ ...fields ? { fields } : {},
1259
+ ...element ? { element } : {},
1260
+ ...isInt ? { int: true } : {},
1261
+ ...optional ? { isOptional: true } : {}
1262
+ };
1263
+ const add2 = (p) => makeBuilder(prim, [...preds, p], extra);
1264
+ return Object.assign(/* @__PURE__ */ Object.create(null), base, {
1265
+ gt: (n) => add2(gt(selfTerm(), lit(n))),
1266
+ ge: (n) => add2(ge(selfTerm(), lit(n))),
1267
+ lt: (n) => add2(lt(selfTerm(), lit(n))),
1268
+ le: (n) => add2(le(selfTerm(), lit(n))),
1269
+ int: () => makeBuilder(prim ?? "number", preds, { ...extra, int: true }),
1270
+ min: (n) => add2(ge(lenTerm(selfTerm()), lit(n))),
1271
+ max: (n) => add2(le(lenTerm(selfTerm()), lit(n))),
1272
+ length: (n) => add2(and(ge(lenTerm(selfTerm()), lit(n)), le(lenTerm(selfTerm()), lit(n)))),
1273
+ optional: () => makeBuilder(prim, preds, { ...extra, optional: true })
1274
+ });
1275
+ }
1276
+ function number() {
1277
+ return makeBuilder("number", []);
1278
+ }
1279
+ function string() {
1280
+ return makeBuilder("string", []);
1281
+ }
1282
+ function boolean() {
1283
+ return makeBuilder("boolean", []);
1284
+ }
1285
+ function array(item) {
1286
+ if (!isConstraint(item)) return makeBuilder(void 0, []);
1287
+ return makeBuilder(void 0, [], { element: item });
1288
+ }
1289
+ function shape(fields) {
1290
+ const mapped = {};
1291
+ for (const [k, v2] of Object.entries(fields)) {
1292
+ if (!isConstraint(v2)) continue;
1293
+ mapped[k] = {
1294
+ constraint: v2,
1295
+ ...v2.isOptional ? { optional: true } : {}
1296
+ };
1297
+ }
1298
+ return makeBuilder(void 0, [], { fields: mapped });
1299
+ }
1300
+ function substTerm(t, paramName) {
1301
+ if (t.op === "var" && t.id === SELF) return v(paramName);
1302
+ if (t.op === "app" && t.fn === "get" && t.args.length === 2) {
1303
+ return getTerm(substTerm(t.args[0], paramName), String(
1304
+ t.args[1].op === "lit" ? t.args[1].value : ""
1305
+ ));
1306
+ }
1307
+ return t;
1308
+ }
1309
+ function substPred2(p, paramName) {
1310
+ switch (p.op) {
1311
+ case "gt":
1312
+ case "ge":
1313
+ case "lt":
1314
+ case "le":
1315
+ case "eq":
1316
+ case "ne": {
1317
+ return { op: p.op, a: substTerm(p.a, paramName), b: substTerm(p.b, paramName) };
1318
+ }
1319
+ case "typeof": {
1320
+ return { op: "typeof", t: substTerm(p.t, paramName), type: p.type };
1321
+ }
1322
+ case "and":
1323
+ return and(...p.args.map((x) => substPred2(x, paramName)));
1324
+ default:
1325
+ return p;
1326
+ }
1327
+ }
1328
+ function instantiateConstraint(c, paramName) {
1329
+ if (c.fields) {
1330
+ const parts = [];
1331
+ for (const [key, field] of Object.entries(c.fields)) {
1332
+ const fieldTerm = getTerm(v(paramName), key);
1333
+ parts.push(instantiateOnTerm(field.constraint, fieldTerm));
1334
+ }
1335
+ if (c.prim) parts.push(ptypeof(v(paramName), c.prim));
1336
+ if (parts.length === 0) return { op: "true" };
1337
+ return parts.length === 1 ? parts[0] : and(...parts);
1338
+ }
1339
+ const preds = c.preds.map((p) => substPred2(p, paramName));
1340
+ if (c.prim && c.preds.length === 0) {
1341
+ return ptypeof(v(paramName), c.prim);
1342
+ }
1343
+ return preds.length === 0 ? { op: "true" } : preds.length === 1 ? preds[0] : and(...preds);
1344
+ }
1345
+ function instantiateOnTerm(c, t) {
1346
+ if (c.fields) {
1347
+ const parts = [];
1348
+ for (const [key, field] of Object.entries(c.fields)) {
1349
+ parts.push(instantiateOnTerm(field.constraint, getTerm(t, key)));
1350
+ }
1351
+ if (parts.length === 0) return { op: "true" };
1352
+ return parts.length === 1 ? parts[0] : and(...parts);
1353
+ }
1354
+ const subst = (p) => {
1355
+ switch (p.op) {
1356
+ case "gt":
1357
+ case "ge":
1358
+ case "lt":
1359
+ case "le":
1360
+ case "eq":
1361
+ case "ne": {
1362
+ const a = p.a.op === "var" && p.a.id === SELF ? t : p.a;
1363
+ const b = p.b.op === "var" && p.b.id === SELF ? t : p.b;
1364
+ return { op: p.op, a, b };
1365
+ }
1366
+ case "typeof": {
1367
+ const tt = p.t.op === "var" && p.t.id === SELF ? t : p.t;
1368
+ return { op: "typeof", t: tt, type: p.type };
1369
+ }
1370
+ case "and":
1371
+ return and(...p.args.map(subst));
1372
+ default:
1373
+ return p;
1374
+ }
1375
+ };
1376
+ const preds = c.preds.map(subst);
1377
+ if (c.prim && c.preds.length === 0) return ptypeof(t, c.prim);
1378
+ return preds.length === 0 ? { op: "true" } : preds.length === 1 ? preds[0] : and(...preds);
1379
+ }
1380
+ function constraintToEntryAbs(c, paramName) {
1381
+ const t = v(paramName);
1382
+ if (c.fields) {
1383
+ const slots = {};
1384
+ for (const [key, field] of Object.entries(c.fields)) {
1385
+ const fieldTerm = getTerm(t, key);
1386
+ slots[key] = {
1387
+ value: constraintOnTermAbs(field.constraint, fieldTerm),
1388
+ ...field.optional || field.constraint.isOptional ? { optional: true } : {}
1389
+ };
1390
+ }
1391
+ return abs({ k: "obj", slots }, t, void 0, "path");
1392
+ }
1393
+ return constraintOnTermAbs(c, t);
1394
+ }
1395
+ function constraintOnTermAbs(c, t) {
1396
+ if (c.fields) {
1397
+ const slots = {};
1398
+ for (const [key, field] of Object.entries(c.fields)) {
1399
+ slots[key] = {
1400
+ value: constraintOnTermAbs(field.constraint, getTerm(t, key)),
1401
+ ...field.optional || field.constraint.isOptional ? { optional: true } : {}
1402
+ };
1403
+ }
1404
+ return abs({ k: "obj", slots }, t, void 0, "path");
1405
+ }
1406
+ if (c.element) {
1407
+ const elem = constraintOnTermAbs(c.element, v("x[]"));
1408
+ return abs({ k: "arr", element: elem }, t, void 0, "path");
1409
+ }
1410
+ const pred = instantiateOnTerm(c, t);
1411
+ const predOut = pred.op === "true" ? void 0 : pred;
1412
+ if (c.prim) {
1413
+ return abs({ k: "prim", type: c.prim }, t, predOut, "path");
1414
+ }
1415
+ if (c.preds.length > 0) {
1416
+ return abs({ k: "prim", type: "number" }, t, predOut, "path");
1417
+ }
1418
+ return abs({ k: "any" }, t, void 0, "path");
1419
+ }
1420
+
1421
+ // src/algebra/refine.ts
1422
+ function extractNudoImports(source) {
1423
+ const out = [];
1424
+ const named = /@nudo:import\s*\{([^}]+)\}\s*from\s*["']([^"']+)["']/g;
1425
+ let m;
1426
+ while (m = named.exec(source)) {
1427
+ const names = m[1].split(",").map((s) => s.trim()).filter(Boolean).map((s) => s.split(/\s+as\s+/).pop().trim());
1428
+ out.push({ names, spec: m[2] });
1429
+ }
1430
+ const ns = /@nudo:import\s+\*\s+as\s+(\w+)\s+from\s*["']([^"']+)["']/g;
1431
+ while (m = ns.exec(source)) {
1432
+ out.push({ names: [`*${m[1]}`], spec: m[2] });
1433
+ }
1434
+ return out;
1435
+ }
1436
+ function execNudoModule(src) {
1437
+ const names = [...src.matchAll(/export\s+const\s+(\w+)/g)].map((m) => m[1]);
1438
+ let body = src.replace(/export\s+const\b/g, "const");
1439
+ body = body.replace(/^\s*import\s*\{[^}]*\}\s*from\s*["'][^"']+["'];?\s*$/gm, "");
1440
+ body = body.replace(/^\s*import\s+\*\s+as\s+\w+\s+from\s*["'][^"']+["'];?\s*$/gm, "");
1441
+ body += `
1442
+ return { ${names.join(", ")} };`;
1443
+ const fn = new Function("number", "string", "boolean", "shape", "array", body);
1444
+ return fn(number, string, boolean, shape, array);
1445
+ }
1446
+ var nudoModuleExecCache = /* @__PURE__ */ new Map();
1447
+ var MAX_NUDO_MODULE_EXEC = 64;
1448
+ function execNudoModuleCached(src) {
1449
+ const hit = nudoModuleExecCache.get(src);
1450
+ if (hit !== void 0) {
1451
+ nudoModuleExecCache.delete(src);
1452
+ nudoModuleExecCache.set(src, hit);
1453
+ return hit;
1454
+ }
1455
+ const out = execNudoModule(src);
1456
+ if (nudoModuleExecCache.size >= MAX_NUDO_MODULE_EXEC) {
1457
+ const oldest = nudoModuleExecCache.keys().next().value;
1458
+ if (oldest !== void 0) nudoModuleExecCache.delete(oldest);
1459
+ }
1460
+ nudoModuleExecCache.set(src, out);
1461
+ return out;
1462
+ }
1463
+ function resetNudoModuleExecCache() {
1464
+ nudoModuleExecCache.clear();
1465
+ }
1466
+ function collectConstraints(source, opts) {
1467
+ const map = /* @__PURE__ */ new Map();
1468
+ const imports = extractNudoImports(source);
1469
+ for (const imp of imports) {
1470
+ if (!opts.loadModule || !opts.fromFile) continue;
1471
+ const src = opts.loadModule(imp.spec, opts.fromFile);
1472
+ if (!src) continue;
1473
+ let exports;
1474
+ try {
1475
+ exports = execNudoModuleCached(src);
1476
+ } catch {
1477
+ continue;
1478
+ }
1479
+ for (const name of imp.names) {
1480
+ if (name.startsWith("*")) continue;
1481
+ const v2 = exports[name];
1482
+ if (isNudoConstraint(v2)) map.set(name, v2);
1483
+ }
1484
+ }
1485
+ return map;
1486
+ }
1487
+ function extractRefineLines(source, fnName) {
1488
+ const fnRe = new RegExp(
1489
+ `(?:export\\s+default\\s+)?(?:function\\s+${fnName}\\b|const\\s+${fnName}\\s*=)`
1490
+ );
1491
+ const m = source.match(fnRe);
1492
+ if (!m || m.index === void 0) return [];
1493
+ const before = source.slice(0, m.index);
1494
+ const lines = before.split("\n");
1495
+ const reqs = [];
1496
+ for (let i = lines.length - 1; i >= 0; i--) {
1497
+ const line = lines[i].trim();
1498
+ if (line === "" || line === "*/") continue;
1499
+ if (line.startsWith("*") || line.startsWith("/*") || line.startsWith("//")) {
1500
+ const rm = line.match(/@nudo:refine\s+(.+)$/);
1501
+ if (rm) reqs.unshift(rm[1].trim().replace(/\*\/$/, "").trim());
1502
+ continue;
1503
+ }
1504
+ break;
1505
+ }
1506
+ return reqs;
1507
+ }
1508
+ function extractRefinesFromSource(source, fnName, opts = {}) {
1509
+ if (!source.includes("@nudo:refine")) return [];
1510
+ const constraints = collectConstraints(source, opts);
1511
+ const out = [];
1512
+ for (const line of extractRefineLines(source, fnName)) {
1513
+ const parts = line.split(/&&|,/).map((s) => s.trim()).filter(Boolean);
1514
+ for (const part of parts) {
1515
+ const m = part.match(/^(\w+)\s+(\w+)$/);
1516
+ if (!m) continue;
1517
+ const [, param, cName] = m;
1518
+ if (param === "return") continue;
1519
+ const c = constraints.get(cName);
1520
+ if (!c) continue;
1521
+ out.push({
1522
+ param,
1523
+ pred: instantiateConstraint(c, param),
1524
+ constraint: c
1525
+ });
1526
+ }
1527
+ }
1528
+ return out;
1529
+ }
1530
+ function refineToIndexedFull(source, fnName, paramNames, opts = {}) {
1531
+ const raw = extractRefinesFromSource(source, fnName, opts);
1532
+ const out = [];
1533
+ for (const item of raw) {
1534
+ const idx = paramNames.indexOf(item.param);
1535
+ if (idx >= 0) out.push([idx, item]);
1536
+ }
1537
+ return out;
1538
+ }
1539
+ function extractRefineReturnFromSource(source, fnName, opts = {}) {
1540
+ if (!source.includes("@nudo:refine")) return void 0;
1541
+ const constraints = collectConstraints(source, opts);
1542
+ for (const line of extractRefineLines(source, fnName)) {
1543
+ const parts = line.split(/&&|,/).map((s) => s.trim()).filter(Boolean);
1544
+ for (const part of parts) {
1545
+ const m = part.match(/^return\s+(\w+)$/);
1546
+ if (!m) continue;
1547
+ const cName = m[1];
1548
+ const c = constraints.get(cName);
1549
+ if (!c) continue;
1550
+ return { name: cName, constraint: c };
1551
+ }
1552
+ }
1553
+ return void 0;
1554
+ }
1555
+
1556
+ // src/algebra/hash-source.ts
1557
+ var lastHashSource;
1558
+ var lastHashOut;
1559
+ function hashSource(s) {
1560
+ if (s === lastHashSource && lastHashOut !== void 0) return lastHashOut;
1561
+ let h1 = 2166136261;
1562
+ let h2 = 2654435769;
1563
+ for (let i = 0; i < s.length; i++) {
1564
+ const c = s.charCodeAt(i);
1565
+ h1 ^= c;
1566
+ h1 = Math.imul(h1, 16777619);
1567
+ h2 = Math.imul(h2 ^ c, 16777619);
1568
+ }
1569
+ lastHashSource = s;
1570
+ lastHashOut = `${(h1 >>> 0).toString(36)}-${(h2 >>> 0).toString(36)}_${s.length.toString(36)}`;
1571
+ return lastHashOut;
1572
+ }
1573
+ function resetHashSourceCache() {
1574
+ lastHashSource = void 0;
1575
+ lastHashOut = void 0;
1576
+ }
1577
+
1578
+ // src/algebra/fn-fp.ts
1579
+ var fnFpCache = /* @__PURE__ */ new Map();
1580
+ var MAX_FN_FP_CACHE = 24;
1581
+ var MAX_FN_FP_SOURCE_CHARS = 1e6;
1582
+ function resetFnFpCache() {
1583
+ fnFpCache.clear();
1584
+ }
1585
+ function getFnNameAndBodies(decl) {
1586
+ const out = [];
1587
+ if (decl.type === "FunctionDeclaration" && decl.id) {
1588
+ out.push({ name: decl.id.name, body: decl.body, fnNode: decl });
1589
+ return out;
1590
+ }
1591
+ if (decl.type === "VariableDeclaration") {
1592
+ for (const d of decl.declarations) {
1593
+ if (d.id.type === "Identifier" && d.init && (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")) {
1594
+ const comments = d.leadingComments;
1595
+ const first = comments?.[0];
1596
+ out.push({
1597
+ name: d.id.name,
1598
+ body: d.init.body,
1599
+ fnNode: d.init,
1600
+ declaratorStart: d.start ?? void 0,
1601
+ declaratorLeadStart: typeof first?.start === "number" ? first.start : void 0
1602
+ });
1603
+ }
1604
+ }
1605
+ }
1606
+ return out;
1607
+ }
1608
+ function leadingSliceStart(stmt, decl) {
1609
+ const comments = stmt.leadingComments ?? decl.leadingComments;
1610
+ const first = comments?.[0];
1611
+ if (first && typeof first.start === "number") return first.start;
1612
+ return stmt.start ?? decl.start ?? 0;
1613
+ }
1614
+ function collectSiblingRefs(node, known, out) {
1615
+ if (!node || typeof node !== "object") return;
1616
+ const obj2 = node;
1617
+ if (obj2.type === "Identifier" && typeof obj2.name === "string" && known.has(obj2.name)) {
1618
+ out.add(obj2.name);
1619
+ }
1620
+ for (const key of Object.keys(obj2)) {
1621
+ if (key === "loc" || key === "start" || key === "end" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") {
1622
+ continue;
1623
+ }
1624
+ if ((key === "key" || key === "property") && (obj2.type === "MemberExpression" || obj2.type === "ObjectProperty" || obj2.type === "ObjectMethod" || obj2.type === "ClassMethod" || obj2.type === "ClassProperty") && obj2.computed !== true) {
1625
+ continue;
1626
+ }
1627
+ if (key === "id" && (obj2.type === "FunctionDeclaration" || obj2.type === "FunctionExpression" || obj2.type === "ClassDeclaration" || obj2.type === "ClassExpression")) {
1628
+ continue;
1629
+ }
1630
+ const v2 = obj2[key];
1631
+ if (Array.isArray(v2)) {
1632
+ for (const x of v2) collectSiblingRefs(x, known, out);
1633
+ } else if (v2 && typeof v2 === "object") {
1634
+ collectSiblingRefs(v2, known, out);
1635
+ }
1636
+ }
1637
+ }
1638
+ function computeFnFingerprints(source, file) {
1639
+ const top = [];
1640
+ const contextParts = [];
1641
+ for (const stmt of file.program.body) {
1642
+ let decl = stmt;
1643
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
1644
+ decl = stmt.declaration;
1645
+ } else if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration) {
1646
+ decl = stmt.declaration;
1647
+ }
1648
+ const fnInfos = getFnNameAndBodies(decl);
1649
+ if (fnInfos.length > 0) {
1650
+ const lead = leadingSliceStart(stmt, decl);
1651
+ for (let i = 0; i < fnInfos.length; i++) {
1652
+ const info = fnInfos[i];
1653
+ const sliceStart = i === 0 ? lead : info.declaratorLeadStart ?? info.declaratorStart ?? info.fnNode.start ?? lead;
1654
+ const end = info.fnNode.end ?? info.declaratorStart ?? decl.end ?? stmt.end ?? sliceStart;
1655
+ top.push({
1656
+ name: info.name,
1657
+ slice: source.slice(sliceStart, Math.max(end, sliceStart)),
1658
+ fnNode: info.fnNode
1659
+ });
1660
+ }
1661
+ } else if (typeof stmt.start === "number" && typeof stmt.end === "number") {
1662
+ contextParts.push(source.slice(stmt.start, stmt.end));
1663
+ } else {
1664
+ contextParts.push(stmt.type);
1665
+ }
1666
+ }
1667
+ const context = hashSource(contextParts.join("\n "));
1668
+ const names = new Set(top.map((t) => t.name));
1669
+ const own = /* @__PURE__ */ new Map();
1670
+ for (const t of top) own.set(t.name, hashSource(t.slice));
1671
+ const edges = /* @__PURE__ */ new Map();
1672
+ for (const t of top) {
1673
+ const refs = /* @__PURE__ */ new Set();
1674
+ collectSiblingRefs(t.fnNode, names, refs);
1675
+ edges.set(t.name, refs);
1676
+ }
1677
+ const result = /* @__PURE__ */ new Map();
1678
+ for (const t of top) {
1679
+ const seen = /* @__PURE__ */ new Set();
1680
+ const stack = [...edges.get(t.name) ?? []];
1681
+ const depParts = [];
1682
+ while (stack.length > 0) {
1683
+ const cur = stack.pop();
1684
+ if (seen.has(cur)) continue;
1685
+ seen.add(cur);
1686
+ depParts.push(`${cur}=${own.get(cur) ?? "?"}`);
1687
+ for (const next of edges.get(cur) ?? []) {
1688
+ if (!seen.has(next)) stack.push(next);
1689
+ }
1690
+ }
1691
+ depParts.sort();
1692
+ result.set(t.name, {
1693
+ own: own.get(t.name),
1694
+ deps: hashSource(`${depParts.join(",")} ${context}`),
1695
+ nRefs: seen.size
1696
+ });
1697
+ }
1698
+ return result;
1699
+ }
1700
+ function fnFingerprints(source, file) {
1701
+ if (source.length > MAX_FN_FP_SOURCE_CHARS) {
1702
+ return computeFnFingerprints(source, file);
1703
+ }
1704
+ const hit = fnFpCache.get(source);
1705
+ if (hit !== void 0) {
1706
+ fnFpCache.delete(source);
1707
+ fnFpCache.set(source, hit);
1708
+ return hit;
1709
+ }
1710
+ const fp = computeFnFingerprints(source, file);
1711
+ if (fnFpCache.size >= MAX_FN_FP_CACHE) {
1712
+ const oldest = fnFpCache.keys().next().value;
1713
+ if (oldest !== void 0) fnFpCache.delete(oldest);
1714
+ }
1715
+ fnFpCache.set(source, fp);
1716
+ return fp;
1717
+ }
1718
+ function generalizeSourceKeyPart(source, fnName, file) {
1719
+ if (!file) return `w:${hashSource(source)}`;
1720
+ const fp = fnFingerprints(source, file).get(fnName);
1721
+ if (fp) return `f:${fp.own}:${fp.deps}`;
1722
+ return `u:${hashSource(source)}`;
1723
+ }
1724
+ function hasAnyCallLike(node, depth = 0) {
1725
+ if (!node || typeof node !== "object") return false;
1726
+ if (depth > 80) return true;
1727
+ const obj2 = node;
1728
+ if (obj2.type === "CallExpression" || obj2.type === "NewExpression" || obj2.type === "OptionalCallExpression" || obj2.type === "ImportExpression") {
1729
+ return true;
1730
+ }
1731
+ for (const key of Object.keys(obj2)) {
1732
+ if (key === "loc" || key === "start" || key === "end" || key === "leadingComments" || key === "trailingComments" || key === "innerComments") {
1733
+ continue;
1734
+ }
1735
+ const v2 = obj2[key];
1736
+ if (Array.isArray(v2)) {
1737
+ for (const x of v2) if (hasAnyCallLike(x, depth + 1)) return true;
1738
+ } else if (v2 && typeof v2 === "object") {
1739
+ if (hasAnyCallLike(v2, depth + 1)) return true;
1740
+ }
1741
+ }
1742
+ return false;
1743
+ }
1744
+ function hasModuleSyntax(file) {
1745
+ for (const stmt of file.program.body) {
1746
+ if (stmt.type === "ImportDeclaration") return true;
1747
+ if (stmt.type === "ExportAllDeclaration") return true;
1748
+ if (stmt.type === "ExportNamedDeclaration" && stmt.source) return true;
1749
+ }
1750
+ return false;
1751
+ }
1752
+ function canSkipLiteralCallScan(source, file) {
1753
+ if (source.includes("@nudo:refine")) return false;
1754
+ if (hasModuleSyntax(file)) return false;
1755
+ if (hasAnyCallLike(file)) return false;
1756
+ const fps = fnFingerprints(source, file);
1757
+ for (const fp of fps.values()) {
1758
+ if (fp.nRefs > 0) return false;
1759
+ }
1760
+ return true;
1761
+ }
1762
+
1763
+ // src/algebra/load-deps-fp.ts
1764
+ var MAX_LOAD_DEP_NODES = 64;
1765
+ function normPath(p) {
1766
+ return p.replace(/\\/g, "/");
1767
+ }
1768
+ function resolveDepPath(fromFile, spec) {
1769
+ const s = normPath(spec);
1770
+ if (!s.startsWith(".")) return s;
1771
+ const from = normPath(fromFile);
1772
+ const i = from.lastIndexOf("/");
1773
+ const base = i >= 0 ? from.slice(0, i) : "";
1774
+ const parts = base ? base.split("/") : [];
1775
+ for (const seg of s.split("/")) {
1776
+ if (seg === "" || seg === ".") continue;
1777
+ if (seg === "..") parts.pop();
1778
+ else parts.push(seg);
1779
+ }
1780
+ return parts.join("/");
1781
+ }
1782
+ function extractAllLoadSpecs(source) {
1783
+ const specs = /* @__PURE__ */ new Set();
1784
+ for (const imp of extractNudoImports(source)) specs.add(imp.spec);
1785
+ const patterns = [
1786
+ /\bfrom\s*['"]([^'"]+)['"]/g,
1787
+ /\brequire\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
1788
+ /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g
1789
+ ];
1790
+ for (const re of patterns) {
1791
+ let m;
1792
+ while (m = re.exec(source)) specs.add(m[1]);
1793
+ }
1794
+ return [...specs];
1795
+ }
1796
+ function loadModuleDepsFingerprint(source, loadModule, fromFile) {
1797
+ const parts = [];
1798
+ const paths = [];
1799
+ const seen = /* @__PURE__ */ new Set();
1800
+ const queue = extractAllLoadSpecs(source).map(
1801
+ (spec) => ({ spec, from: fromFile })
1802
+ );
1803
+ let n = 0;
1804
+ while (queue.length > 0) {
1805
+ if (n >= MAX_LOAD_DEP_NODES) {
1806
+ parts.sort();
1807
+ return { fp: `trunc:${parts.join(",")}`, paths, truncated: true };
1808
+ }
1809
+ const cur = queue.shift();
1810
+ const path = resolveDepPath(cur.from, cur.spec);
1811
+ if (seen.has(path)) continue;
1812
+ seen.add(path);
1813
+ n++;
1814
+ const src = loadModule(cur.spec, cur.from);
1815
+ parts.push(`${path}=${src === void 0 ? "miss" : hashSource(src)}`);
1816
+ paths.push(path);
1817
+ if (src === void 0) continue;
1818
+ for (const next of extractAllLoadSpecs(src)) {
1819
+ const nextPath = resolveDepPath(path, next);
1820
+ if (!seen.has(nextPath)) queue.push({ spec: next, from: path });
1821
+ }
1822
+ }
1823
+ parts.sort();
1824
+ return { fp: parts.join(","), paths, truncated: false };
1825
+ }
1826
+
1827
+ // src/algebra/generalize.ts
1828
+ var generalizeMemo = /* @__PURE__ */ new Map();
1829
+ var memoKeyDeps = /* @__PURE__ */ new Map();
1830
+ var memoDepIndex = /* @__PURE__ */ new Map();
1831
+ var loadModuleIds = /* @__PURE__ */ new WeakMap();
1832
+ var nextLoadModuleId = 1;
1833
+ var MAX_GENERALIZE_MEMO = 1024;
1834
+ function resetGeneralizeMemo() {
1835
+ generalizeMemo.clear();
1836
+ memoKeyDeps.clear();
1837
+ memoDepIndex.clear();
1838
+ resetFnFpCache();
1839
+ resetHashSourceCache();
1840
+ }
1841
+ function getGeneralizeMemoSize() {
1842
+ return generalizeMemo.size;
1843
+ }
1844
+ function unindexMemoKey(key) {
1845
+ const deps = memoKeyDeps.get(key);
1846
+ if (!deps) return;
1847
+ for (const p of deps) {
1848
+ const set = memoDepIndex.get(p);
1849
+ if (!set) continue;
1850
+ set.delete(key);
1851
+ if (set.size === 0) memoDepIndex.delete(p);
1852
+ }
1853
+ memoKeyDeps.delete(key);
1854
+ }
1855
+ function evictGeneralizeMemoForPaths(paths) {
1856
+ let n = 0;
1857
+ for (const raw of paths) {
1858
+ const p = normPath(raw);
1859
+ const keys = memoDepIndex.get(p);
1860
+ if (!keys) continue;
1861
+ for (const key of [...keys]) {
1862
+ generalizeMemo.delete(key);
1863
+ unindexMemoKey(key);
1864
+ n++;
1865
+ }
1866
+ }
1867
+ return n;
1868
+ }
1869
+ function loadModuleId(fn) {
1870
+ if (!fn) return 0;
1871
+ let id = loadModuleIds.get(fn);
1872
+ if (id === void 0) {
1873
+ id = nextLoadModuleId++;
1874
+ loadModuleIds.set(fn, id);
1875
+ }
1876
+ return id;
1877
+ }
1878
+ function refineDepsFingerprint(source, refine) {
1879
+ if (!refine?.loadModule || !refine.fromFile) {
1880
+ return { fp: "-", paths: [], truncated: false };
1881
+ }
1882
+ return loadModuleDepsFingerprint(source, refine.loadModule, refine.fromFile);
1883
+ }
1884
+ function generalizeMemoKey(fnName, source, opts) {
1885
+ const r = opts.refine;
1886
+ const budget = opts.budget ?? defaultLeakBudget;
1887
+ const deps = opts.depsFp ?? (r ? refineDepsFingerprint(source, r) : { fp: "-", paths: [], truncated: false });
1888
+ const srcPart = generalizeSourceKeyPart(source, fnName, opts.file);
1889
+ const key = [
1890
+ srcPart,
1891
+ fnName,
1892
+ opts.label ?? "A",
1893
+ r ? `${loadModuleId(r.loadModule)}:${r.fromFile ?? ""}` : "-",
1894
+ deps.fp,
1895
+ `${budget.maxDepth}/${budget.maxNodes}`
1896
+ ].join("|");
1897
+ return { key, depPaths: deps.paths, truncated: deps.truncated };
1898
+ }
1899
+ function generalizeMemoGet(key) {
1900
+ if (!generalizeMemo.has(key)) return null;
1901
+ const v2 = generalizeMemo.get(key);
1902
+ generalizeMemo.delete(key);
1903
+ generalizeMemo.set(key, v2);
1904
+ return v2;
1905
+ }
1906
+ function generalizeMemoSet(key, value, depPaths) {
1907
+ if (generalizeMemo.size >= MAX_GENERALIZE_MEMO) {
1908
+ const oldest = generalizeMemo.keys().next().value;
1909
+ if (oldest !== void 0) {
1910
+ generalizeMemo.delete(oldest);
1911
+ unindexMemoKey(oldest);
1912
+ }
1913
+ }
1914
+ generalizeMemo.set(key, value);
1915
+ if (depPaths.length > 0) {
1916
+ memoKeyDeps.set(key, depPaths);
1917
+ for (const p of depPaths) {
1918
+ let set = memoDepIndex.get(p);
1919
+ if (!set) {
1920
+ set = /* @__PURE__ */ new Set();
1921
+ memoDepIndex.set(p, set);
1922
+ }
1923
+ set.add(key);
1924
+ }
1925
+ }
1926
+ }
1927
+ function isCacheableAbs(a) {
1928
+ return a.conf === "exact" || a.conf === "path" || a.conf === "widened" || a.conf === "mock";
1929
+ }
1930
+ function termKey(t, rename) {
1931
+ switch (t.op) {
1932
+ case "lit":
1933
+ return `L:${typeof t.value}:${String(t.value)}`;
1934
+ case "var":
1935
+ return `V:${rename?.get(t.id) ?? t.id}`;
1936
+ case "app":
1937
+ return `A:${t.fn}(${t.args.map((a) => termKey(a, rename)).join(",")})`;
1938
+ }
1939
+ }
1940
+ function predKey(p, rename) {
1941
+ switch (p.op) {
1942
+ case "true":
1943
+ return "T";
1944
+ case "false":
1945
+ return "F";
1946
+ case "eq":
1947
+ case "ne":
1948
+ case "lt":
1949
+ case "le":
1950
+ case "gt":
1951
+ case "ge":
1952
+ return `${p.op}(${termKey(p.a, rename)},${termKey(p.b, rename)})`;
1953
+ case "and":
1954
+ case "or": {
1955
+ const keys = p.args.map((a) => predKey(a, rename)).sort();
1956
+ return `${p.op}(${keys.join(",")})`;
1957
+ }
1958
+ case "not":
1959
+ return `not(${predKey(p.arg, rename)})`;
1960
+ case "typeof":
1961
+ return `typeof(${termKey(p.t, rename)},${p.type})`;
1962
+ }
1963
+ }
1964
+ function shapeKey(s, seen, rename) {
1965
+ switch (s.k) {
1966
+ case "never":
1967
+ case "any":
1968
+ case "unknown":
1969
+ return s.k;
1970
+ case "prim":
1971
+ return `p:${s.type}`;
1972
+ case "brand":
1973
+ return `b:${s.name}(${absKeyInner(s.shape, seen, rename)})`;
1974
+ case "eff":
1975
+ return `e:${s.eff}<${absKeyInner(s.inner, seen, rename)}>`;
1976
+ case "arr":
1977
+ return `arr(${absKeyInner(s.element, seen, rename)})`;
1978
+ case "tuple": {
1979
+ const els = s.elements.map((e) => absKeyInner(e, seen, rename)).join(",");
1980
+ const rest = s.rest ? `...${absKeyInner(s.rest, seen, rename)}` : "";
1981
+ return `tup[${els}${rest}]`;
1982
+ }
1983
+ case "fn": {
1984
+ const pts = (s.paramTypes ?? []).map((t) => absKeyInner(t, seen, rename)).join(",");
1985
+ const ret = s.returnType ? absKeyInner(s.returnType, seen, rename) : "?";
1986
+ const name = s.name ? `#${s.name}` : "";
1987
+ return `fn${name}(${s.params.join(",")}|${pts})=>${ret}`;
1988
+ }
1989
+ case "sum":
1990
+ return `sum(${s.members.map((m) => absKeyInner(m, seen, rename)).join("|")})`;
1991
+ case "obj": {
1992
+ const slots = Object.keys(s.slots).sort().map((k) => {
1993
+ const slot = s.slots[k];
1994
+ const flags = (slot.optional ? "?" : "") + (slot.readonly ? "r" : "");
1995
+ return `${k}${flags}:${absKeyInner(slot.value, seen, rename)}`;
1996
+ }).join(",");
1997
+ const idx = s.index ? `idx(${absKeyInner(s.index.key, seen, rename)}\u2192${absKeyInner(s.index.value, seen, rename)})` : "";
1998
+ const open = s.open ? "open" : "";
1999
+ return `obj{${slots}}${idx}${open}`;
2000
+ }
2001
+ }
2002
+ }
2003
+ function absKeyInner(a, seen, rename) {
2004
+ if (seen.has(a)) return "cycle";
2005
+ seen.add(a);
2006
+ const t = a.term ? `=${termKey(a.term, rename)}` : "";
2007
+ const p = a.pred ? `@${predKey(a.pred, rename)}` : "";
2008
+ return `${shapeKey(a.shape, seen, rename)}${t}${p}`;
2009
+ }
2010
+ function collectTermVars(t, acc) {
2011
+ if (t.op === "var") acc.add(t.id);
2012
+ else if (t.op === "app") for (const a of t.args) collectTermVars(a, acc);
2013
+ }
2014
+ function collectPredVars(p, acc) {
2015
+ switch (p.op) {
2016
+ case "true":
2017
+ case "false":
2018
+ return;
2019
+ case "eq":
2020
+ case "ne":
2021
+ case "lt":
2022
+ case "le":
2023
+ case "gt":
2024
+ case "ge":
2025
+ collectTermVars(p.a, acc);
2026
+ collectTermVars(p.b, acc);
2027
+ return;
2028
+ case "and":
2029
+ case "or":
2030
+ for (const a of p.args) collectPredVars(a, acc);
2031
+ return;
2032
+ case "not":
2033
+ collectPredVars(p.arg, acc);
2034
+ return;
2035
+ case "typeof":
2036
+ collectTermVars(p.t, acc);
2037
+ return;
2038
+ }
2039
+ }
2040
+ function collectAbsVars(a, acc, seen) {
2041
+ if (seen.has(a)) return;
2042
+ seen.add(a);
2043
+ if (a.term) collectTermVars(a.term, acc);
2044
+ if (a.pred) collectPredVars(a.pred, acc);
2045
+ const s = a.shape;
2046
+ switch (s.k) {
2047
+ case "brand":
2048
+ collectAbsVars(s.shape, acc, seen);
2049
+ return;
2050
+ case "eff":
2051
+ collectAbsVars(s.inner, acc, seen);
2052
+ return;
2053
+ case "arr":
2054
+ collectAbsVars(s.element, acc, seen);
2055
+ return;
2056
+ case "tuple":
2057
+ for (const e of s.elements) collectAbsVars(e, acc, seen);
2058
+ if (s.rest) collectAbsVars(s.rest, acc, seen);
2059
+ return;
2060
+ case "fn":
2061
+ for (const t of s.paramTypes ?? []) collectAbsVars(t, acc, seen);
2062
+ if (s.returnType) collectAbsVars(s.returnType, acc, seen);
2063
+ return;
2064
+ case "sum":
2065
+ for (const m of s.members) collectAbsVars(m, acc, seen);
2066
+ return;
2067
+ case "obj":
2068
+ for (const slot of Object.values(s.slots)) collectAbsVars(slot.value, acc, seen);
2069
+ if (s.index) {
2070
+ collectAbsVars(s.index.key, acc, seen);
2071
+ collectAbsVars(s.index.value, acc, seen);
2072
+ }
2073
+ return;
2074
+ default:
2075
+ return;
2076
+ }
2077
+ }
2078
+ function renameTerm(t, map) {
2079
+ if (t.op === "var") {
2080
+ const to = map.get(t.id);
2081
+ return to === void 0 ? t : v(to);
2082
+ }
2083
+ if (t.op === "app") {
2084
+ return { op: "app", fn: t.fn, args: t.args.map((a) => renameTerm(a, map)) };
2085
+ }
2086
+ return t;
2087
+ }
2088
+ function renamePred(p, map) {
2089
+ switch (p.op) {
2090
+ case "true":
2091
+ case "false":
2092
+ return p;
2093
+ case "eq":
2094
+ case "ne":
2095
+ case "lt":
2096
+ case "le":
2097
+ case "gt":
2098
+ case "ge":
2099
+ return { op: p.op, a: renameTerm(p.a, map), b: renameTerm(p.b, map) };
2100
+ case "and":
2101
+ case "or":
2102
+ return { op: p.op, args: p.args.map((a) => renamePred(a, map)) };
2103
+ case "not":
2104
+ return { op: "not", arg: renamePred(p.arg, map) };
2105
+ case "typeof":
2106
+ return { op: "typeof", t: renameTerm(p.t, map), type: p.type };
2107
+ }
2108
+ }
2109
+ function renameAbs(a, map) {
2110
+ const out = {
2111
+ shape: renameShape(a.shape, map),
2112
+ conf: a.conf
2113
+ };
2114
+ if (a.term) out.term = renameTerm(a.term, map);
2115
+ if (a.pred) out.pred = renamePred(a.pred, map);
2116
+ return out;
2117
+ }
2118
+ function renameShape(s, map) {
2119
+ switch (s.k) {
2120
+ case "never":
2121
+ case "any":
2122
+ case "unknown":
2123
+ case "prim":
2124
+ return s;
2125
+ case "brand":
2126
+ return { k: "brand", name: s.name, shape: renameAbs(s.shape, map) };
2127
+ case "eff":
2128
+ return { k: "eff", eff: s.eff, inner: renameAbs(s.inner, map) };
2129
+ case "arr":
2130
+ return { k: "arr", element: renameAbs(s.element, map) };
2131
+ case "tuple": {
2132
+ const out = {
2133
+ k: "tuple",
2134
+ elements: s.elements.map((e) => renameAbs(e, map))
2135
+ };
2136
+ if (s.rest) out.rest = renameAbs(s.rest, map);
2137
+ return out;
2138
+ }
2139
+ case "fn": {
2140
+ const out = { k: "fn", params: s.params };
2141
+ if (s.name !== void 0) out.name = s.name;
2142
+ if (s.paramTypes) out.paramTypes = s.paramTypes.map((t) => renameAbs(t, map));
2143
+ if (s.returnType) out.returnType = renameAbs(s.returnType, map);
2144
+ return out;
2145
+ }
2146
+ case "sum":
2147
+ return { k: "sum", members: s.members.map((m) => renameAbs(m, map)) };
2148
+ case "obj": {
2149
+ const slots = {};
2150
+ for (const [k, slot] of Object.entries(s.slots)) {
2151
+ slots[k] = {
2152
+ value: renameAbs(slot.value, map),
2153
+ ...slot.optional ? { optional: true } : {},
2154
+ ...slot.readonly ? { readonly: true } : {}
2155
+ };
2156
+ }
2157
+ const out = { k: "obj", slots };
2158
+ if (s.index) {
2159
+ out.index = { key: renameAbs(s.index.key, map), value: renameAbs(s.index.value, map) };
2160
+ }
2161
+ if (s.open) out.open = true;
2162
+ return out;
2163
+ }
2164
+ }
2165
+ }
2166
+ function instantiateMemoKey(args, phi) {
2167
+ const acc = /* @__PURE__ */ new Set();
2168
+ for (const a of args) collectAbsVars(a, acc, /* @__PURE__ */ new Set());
2169
+ collectPredVars(phi, acc);
2170
+ const varOrder = [...acc].sort();
2171
+ const rename = new Map(varOrder.map((id, i) => [id, `\u03B1${i}`]));
2172
+ const key = `${args.map((a) => absKeyInner(a, /* @__PURE__ */ new Set(), rename)).join(";")}#${predKey(phi, rename)}`;
2173
+ return { key, varOrder };
2174
+ }
2175
+ function alphaRenameResult(result, fromOrder, toOrder) {
2176
+ if (fromOrder.length !== toOrder.length) return result;
2177
+ let same = true;
2178
+ for (let i = 0; i < fromOrder.length; i++) {
2179
+ if (fromOrder[i] !== toOrder[i]) {
2180
+ same = false;
2181
+ break;
2182
+ }
2183
+ }
2184
+ if (same) return result;
2185
+ const map = /* @__PURE__ */ new Map();
2186
+ for (let i = 0; i < fromOrder.length; i++) {
2187
+ map.set(fromOrder[i], toOrder[i]);
2188
+ }
2189
+ return renameAbs(result, map);
2190
+ }
2191
+ function extractFn(source, fnName, fileAst) {
2192
+ const file = fileAst ?? parseSource(source);
2193
+ const env = emptyEnv();
2194
+ for (const stmt of file.program.body) {
2195
+ let decl = stmt;
2196
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
2197
+ decl = stmt.declaration;
2198
+ }
2199
+ if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration) {
2200
+ decl = stmt.declaration;
2201
+ }
2202
+ if (decl.type === "FunctionDeclaration" && decl.id) {
2203
+ env.fns.set(decl.id.name, {
2204
+ params: decl.params.map((p) => p.type === "Identifier" ? p.name : "_"),
2205
+ body: decl.body,
2206
+ async: decl.async === true
2207
+ });
2208
+ }
2209
+ if (decl.type === "VariableDeclaration") {
2210
+ for (const d of decl.declarations) {
2211
+ if (d.id.type === "Identifier" && d.init && (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")) {
2212
+ const init = d.init;
2213
+ env.fns.set(d.id.name, {
2214
+ params: init.params.map(
2215
+ (p) => p.type === "Identifier" ? p.name ?? "_" : "_"
2216
+ ),
2217
+ body: init.body,
2218
+ async: init.async === true
2219
+ });
2220
+ }
2221
+ }
2222
+ }
2223
+ }
2224
+ const fn = env.fns.get(fnName);
2225
+ if (!fn) return void 0;
2226
+ return { params: fn.params, body: fn.body, env };
2227
+ }
2228
+ function generalizeFromAst(fnName, source, opts = {}) {
2229
+ const { key, depPaths, truncated } = generalizeMemoKey(fnName, source, opts);
2230
+ if (!truncated) {
2231
+ const cached = generalizeMemoGet(key);
2232
+ if (cached !== null) {
2233
+ return cached;
2234
+ }
2235
+ }
2236
+ const result = generalizeFromAstUncached(fnName, source, opts);
2237
+ if (!truncated) {
2238
+ generalizeMemoSet(key, result, depPaths);
2239
+ }
2240
+ return result;
2241
+ }
2242
+ function generalizeFromAstUncached(fnName, source, opts = {}) {
2243
+ const extracted = extractFn(source, fnName, opts.file);
2244
+ if (!extracted) return void 0;
2245
+ const { params, body, env } = extracted;
2246
+ const budget = opts.budget ?? defaultLeakBudget;
2247
+ const label = opts.label ?? "A";
2248
+ const typeParams = params.map((p, i) => ({
2249
+ id: `${label}${i + 1}`,
2250
+ // 无约束参数 = any(任意 JS 值),不是 unknown(分析无信息)
2251
+ value: abs({ k: "any" }, v(`${label}${i + 1}`), pTrue, "path")
2252
+ }));
2253
+ let entryReqs;
2254
+ const refineEntryShapes = /* @__PURE__ */ new Map();
2255
+ if (opts.refine) {
2256
+ try {
2257
+ const reqs = extractRefinesFromSource(source, fnName, opts.refine);
2258
+ if (reqs.length > 0) {
2259
+ entryReqs = reqs.map((r) => ({ param: r.param, pred: r.pred }));
2260
+ for (const r of reqs) {
2261
+ const idx = params.indexOf(r.param);
2262
+ if (idx >= 0) {
2263
+ const entryAbs = constraintToEntryAbs(r.constraint, r.param);
2264
+ typeParams[idx] = {
2265
+ id: typeParams[idx].id,
2266
+ value: entryAbs
2267
+ };
2268
+ refineEntryShapes.set(r.param, {
2269
+ abs: snapshotAbs(entryAbs),
2270
+ source: "refine"
2271
+ });
2272
+ }
2273
+ }
2274
+ }
2275
+ } catch {
2276
+ }
2277
+ }
2278
+ const instMemo = /* @__PURE__ */ new Map();
2279
+ const paramNames = new Set(params);
2280
+ const alphaIds = typeParams.map((t) => t.id);
2281
+ const run = (args, phi = pTrue, collector) => {
2282
+ const { key, varOrder } = instantiateMemoKey(args, phi);
2283
+ const hit = instMemo.get(key);
2284
+ if (hit !== void 0) {
2285
+ return alphaRenameResult(hit.result, hit.varOrder, varOrder);
2286
+ }
2287
+ const hc = collector ?? createHofCollectCtx(paramNames, alphaIds);
2288
+ const local = {
2289
+ vars: new Map(env.vars),
2290
+ fns: env.fns,
2291
+ hofCollect: hc
2292
+ };
2293
+ params.forEach((p, i) => {
2294
+ local.vars.set(p, args[i] ?? unknown);
2295
+ });
2296
+ const result = evalNode(body, local, phi, budget).value;
2297
+ if (isCacheableAbs(result)) {
2298
+ instMemo.set(key, { result, varOrder });
2299
+ }
2300
+ return result;
2301
+ };
2302
+ const hofCollector = createHofCollectCtx(paramNames, alphaIds);
2303
+ const symbolic = run(
2304
+ typeParams.map((t) => t.value),
2305
+ // 入口契约进 Φ,让 body 内的单调性可传播
2306
+ entryReqs && entryReqs.length > 0 ? entryReqs.length === 1 ? entryReqs[0].pred : { op: "and", args: entryReqs.map((r) => r.pred) } : pTrue,
2307
+ hofCollector
2308
+ );
2309
+ let fnRels;
2310
+ let entryShapes;
2311
+ let hofSites;
2312
+ if (symbolic.conf !== "opaque") {
2313
+ if (refineEntryShapes.size > 0) {
2314
+ entryShapes = new Map(refineEntryShapes);
2315
+ for (const [param, rec] of refineEntryShapes) {
2316
+ if (rec.abs.shape.k !== "fn") continue;
2317
+ if (!fnRels) fnRels = /* @__PURE__ */ new Map();
2318
+ fnRels.set(param, { abs: snapshotAbs(rec.abs), source: rec.source });
2319
+ }
2320
+ }
2321
+ for (const [param, rec] of hofCollector.fnRels) {
2322
+ if (refineEntryShapes.has(param)) continue;
2323
+ if (!fnRels) fnRels = /* @__PURE__ */ new Map();
2324
+ fnRels.set(param, { abs: snapshotAbs(rec.abs), source: rec.source });
2325
+ }
2326
+ for (const [param, rec] of hofCollector.entryShapes) {
2327
+ if (refineEntryShapes.has(param)) continue;
2328
+ if (!entryShapes) entryShapes = /* @__PURE__ */ new Map();
2329
+ entryShapes.set(param, { abs: snapshotAbs(rec.abs), source: rec.source });
2330
+ }
2331
+ if (hofCollector.sites.length > 0) {
2332
+ hofSites = hofCollector.sites.map((s) => ({
2333
+ ...s,
2334
+ argTerms: [...s.argTerms],
2335
+ result: snapshotAbs(s.result)
2336
+ }));
2337
+ }
2338
+ }
2339
+ return {
2340
+ name: fnName,
2341
+ params,
2342
+ typeParams,
2343
+ symbolic,
2344
+ instantiate: (args, phi) => run(args, phi ?? pTrue),
2345
+ display: formatPoly(
2346
+ fnName,
2347
+ params,
2348
+ typeParams,
2349
+ symbolic,
2350
+ entryReqs,
2351
+ entryShapes,
2352
+ fnRels
2353
+ ),
2354
+ ...entryReqs ? { entryReqs } : {},
2355
+ ...fnRels ? { fnRels } : {},
2356
+ ...entryShapes ? { entryShapes } : {},
2357
+ ...hofSites ? { hofSites } : {}
2358
+ };
2359
+ }
2360
+ function formatPoly(name, params, typeParams, symbolic, entryReqs, entryShapes, fnRels) {
2361
+ const reqByParam = new Map((entryReqs ?? []).map((r) => [r.param, r.pred]));
2362
+ const ps = params.map((p, i) => {
2363
+ const id = typeParams[i]?.id ?? "unknown";
2364
+ const pred = reqByParam.get(p);
2365
+ const promoted = entryShapes?.get(p)?.abs ?? fnRels?.get(p)?.abs;
2366
+ if (promoted) {
2367
+ const slot = formatShapeSlot(promoted);
2368
+ if (pred && pred.op !== "true") {
2369
+ return `${p}: ${slot} where ${predToString(pred)}`;
2370
+ }
2371
+ return `${p}: ${slot}`;
2372
+ }
2373
+ if (pred && pred.op !== "true") {
2374
+ return `${p}: ${id} where ${predToString(pred)}`;
2375
+ }
2376
+ return `${p}: ${id}`;
2377
+ }).join(", ");
2378
+ const ret = formatShapeSlot(symbolic);
2379
+ const termPart = symbolic.term && symbolic.term.op !== "lit" ? ` = ${termToString(symbolic.term)}` : "";
2380
+ const predPart = symbolic.pred && symbolic.pred.op !== "true" ? ` where ${predToString(symbolic.pred)}` : "";
2381
+ return `${name}: (${ps}) => ${ret}${termPart}${predPart}`;
2382
+ }
2383
+ function generalizeAll(source, opts = {}) {
2384
+ const file = parseSource(source);
2385
+ const names = [];
2386
+ for (const stmt of file.program.body) {
2387
+ if (stmt.type === "FunctionDeclaration" && stmt.id) names.push(stmt.id.name);
2388
+ if (stmt.type === "VariableDeclaration") {
2389
+ for (const d of stmt.declarations) {
2390
+ if (d.id.type === "Identifier" && d.init && (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")) {
2391
+ names.push(d.id.name);
2392
+ }
2393
+ }
2394
+ }
2395
+ }
2396
+ const out = [];
2397
+ for (const n of names) {
2398
+ const g = generalizeFromAst(n, source, opts);
2399
+ if (g) out.push(g);
2400
+ }
2401
+ return out;
2402
+ }
2403
+ function listFunctionNames(source) {
2404
+ const file = parseSource(source);
2405
+ const names = [];
2406
+ for (const stmt of file.program.body) {
2407
+ if (stmt.type === "FunctionDeclaration" && stmt.id) names.push(stmt.id.name);
2408
+ if (stmt.type === "VariableDeclaration") {
2409
+ for (const d of stmt.declarations) {
2410
+ if (d.id.type === "Identifier" && d.init && (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")) {
2411
+ names.push(d.id.name);
2412
+ }
2413
+ }
2414
+ }
2415
+ }
2416
+ return names;
2417
+ }
2418
+ function buildArgsFromAssume(source, fnName, assumeIds) {
2419
+ const extracted = extractFn(source, fnName);
2420
+ if (!extracted) return [];
2421
+ return extracted.params.map((p) => {
2422
+ if (assumeIds.has(p)) {
2423
+ return abs(
2424
+ { k: "prim", type: "number" },
2425
+ v(p),
2426
+ { op: "gt", a: v(p), b: { op: "lit", value: 0 } },
2427
+ "path"
2428
+ );
2429
+ }
2430
+ return abs({ k: "unknown" }, void 0, void 0, "partial");
2431
+ });
2432
+ }
2433
+
2434
+ // src/algebra/diagnostics.ts
2435
+ function checkArg(arg, expect, phi = pTrue) {
2436
+ if (!expect || expect.op === "true") return void 0;
2437
+ if (arg.shape.k === "unknown" && !arg.term) {
2438
+ return {
2439
+ severity: "warning",
2440
+ code: "nudo:arg-opaque",
2441
+ message: `\u5B9E\u53C2\u7C7B\u578B unknown\uFF0C\u65E0\u6CD5\u9A8C\u8BC1\u7EA6\u675F ${predToString(expect)}`,
2442
+ suggestion: "\u8865\u5145\u8C03\u7528\u70B9\u3001@nudo:case\uFF0C\u6216 --assume \u63D0\u4F9B\u524D\u7F6E\u6761\u4EF6"
2443
+ };
2444
+ }
2445
+ const combined = arg.pred && arg.pred.op !== "true" ? phi.op === "true" ? arg.pred : { op: "and", args: [phi, arg.pred] } : phi;
2446
+ if (implies(combined, expect)) return void 0;
2447
+ const lv = litValue(arg);
2448
+ if (lv !== void 0 && (expect.op === "gt" || expect.op === "ge" || expect.op === "lt" || expect.op === "le")) {
2449
+ const ok = decideLitCmp(lv, expect);
2450
+ if (ok === true) return void 0;
2451
+ if (ok === false) {
2452
+ return {
2453
+ severity: "error",
2454
+ code: "nudo:constraint-violated",
2455
+ message: `\u5B9E\u53C2 ${JSON.stringify(lv)} \u4E0D\u6EE1\u8DB3 ${predToString(expect)}`,
2456
+ suggestion: `\u6539\u7528\u6EE1\u8DB3\u7EA6\u675F\u7684\u503C\uFF0C\u6216\u653E\u5BBD\u51FD\u6570\u524D\u7F6E\u6761\u4EF6`
2457
+ };
2458
+ }
2459
+ }
2460
+ return {
2461
+ severity: "warning",
2462
+ code: "nudo:constraint-unproven",
2463
+ message: `\u65E0\u6CD5\u8BC1\u660E\u5B9E\u53C2\u6EE1\u8DB3 ${predToString(expect)}`,
2464
+ suggestion: `\u5DF2\u77E5\u4FE1\u606F\u4E0D\u8DB3\uFF1B\u53EF --assume \u6216\u8865 case`
2465
+ };
2466
+ }
2467
+ function decideLitCmp(lv, p) {
2468
+ if (typeof lv !== "number" || p.b.op !== "lit" || typeof p.b.value !== "number") {
2469
+ return void 0;
2470
+ }
2471
+ const n = p.b.value;
2472
+ switch (p.op) {
2473
+ case "gt":
2474
+ return lv > n;
2475
+ case "ge":
2476
+ return lv >= n;
2477
+ case "lt":
2478
+ return lv < n;
2479
+ case "le":
2480
+ return lv <= n;
2481
+ default:
2482
+ return void 0;
2483
+ }
2484
+ }
2485
+ function checkCall(source, fnName, args, phi = pTrue) {
2486
+ const diags = [];
2487
+ const g = generalizeFromAst(fnName, source);
2488
+ if (!g) {
2489
+ diags.push({
2490
+ severity: "error",
2491
+ code: "nudo:fn-not-found",
2492
+ message: `\u672A\u627E\u5230\u51FD\u6570 ${fnName}`
2493
+ });
2494
+ return diags;
2495
+ }
2496
+ if (args.length !== g.params.length) {
2497
+ diags.push({
2498
+ severity: "error",
2499
+ code: "nudo:arg-count",
2500
+ message: `${fnName} \u671F\u671B ${g.params.length} \u4E2A\u53C2\u6570\uFF0C\u5B9E\u9645 ${args.length}`,
2501
+ fn: fnName
2502
+ });
2503
+ return diags;
2504
+ }
2505
+ const required = extractParamRequirements(g);
2506
+ args.forEach((arg, i) => {
2507
+ const req = required.get(i);
2508
+ const d = checkArg(arg, req, phi);
2509
+ if (d) diags.push({ ...d, fn: fnName, argIndex: i });
2510
+ });
2511
+ try {
2512
+ const result = analyzeFn(source, fnName, args, phi);
2513
+ if (result.conf === "partial" || result.conf === "opaque") {
2514
+ diags.push({
2515
+ severity: "info",
2516
+ code: "nudo:partial-result",
2517
+ message: `${fnName}(...) \u7ED3\u679C\u7F6E\u4FE1\u5EA6 ${result.conf}`,
2518
+ suggestion: "\u8865\u5145\u8C03\u7528\u70B9\u6216\u7EA6\u675F\u53EF\u63D0\u9AD8\u7CBE\u5EA6",
2519
+ fn: fnName
2520
+ });
2521
+ }
2522
+ } catch (e) {
2523
+ diags.push({
2524
+ severity: "error",
2525
+ code: "nudo:eval-error",
2526
+ message: `\u6C42\u503C\u5931\u8D25: ${e.message}`,
2527
+ fn: fnName
2528
+ });
2529
+ }
2530
+ return diags;
2531
+ }
2532
+ function extractParamRequirements(g) {
2533
+ const map = /* @__PURE__ */ new Map();
2534
+ const pred = g.symbolic.pred;
2535
+ if (!pred || pred.op === "true") return map;
2536
+ const paramIndex = /* @__PURE__ */ new Map();
2537
+ g.typeParams.forEach((t, i) => paramIndex.set(t.id, i));
2538
+ const consider = (p) => {
2539
+ if (p.op === "and") {
2540
+ p.args.forEach(consider);
2541
+ return;
2542
+ }
2543
+ if ((p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le") && p.a.op === "var" && paramIndex.has(p.a.id) && p.b.op === "lit") {
2544
+ map.set(paramIndex.get(p.a.id), p);
2545
+ }
2546
+ };
2547
+ consider(pred);
2548
+ return map;
2549
+ }
2550
+ function formatDiagnostics(diags) {
2551
+ if (diags.length === 0) return "No issues found.";
2552
+ return diags.map((d) => {
2553
+ const loc = d.fn ? `${d.fn}${d.argIndex !== void 0 ? `[${d.argIndex}]` : ""}: ` : "";
2554
+ let s = `[${d.severity}] ${loc}${d.message} (${d.code})`;
2555
+ if (d.suggestion) s += `
2556
+ \u2192 ${d.suggestion}`;
2557
+ return s;
2558
+ }).join("\n");
2559
+ }
2560
+
2561
+ // src/algebra/stable-source-key.ts
2562
+ function stableAnalyzeKeySource(source) {
2563
+ let end = source.length;
2564
+ while (end > 0) {
2565
+ const ch = source.charCodeAt(end - 1);
2566
+ if (ch === 10 || ch === 13 || ch === 32 || ch === 9) {
2567
+ end--;
2568
+ continue;
2569
+ }
2570
+ break;
2571
+ }
2572
+ const lineStart = source.lastIndexOf("\n", end - 1) + 1;
2573
+ const lastLine = source.slice(lineStart, end);
2574
+ const trimmedLast = lastLine.trim();
2575
+ if (trimmedLast !== "" && !trimmedLast.startsWith("//") && !trimmedLast.startsWith("/*")) {
2576
+ let body2 = source.slice(0, end);
2577
+ if (body2.endsWith("*/")) {
2578
+ body2 = stripTrailingBlockComments(body2);
2579
+ return body2 + "\n";
2580
+ }
2581
+ const after = source.slice(end);
2582
+ if (after === "" || after === "\n") return source;
2583
+ return source.slice(0, end) + "\n";
2584
+ }
2585
+ const lines = source.split("\n");
2586
+ while (lines.length > 0) {
2587
+ const last = lines[lines.length - 1];
2588
+ if (last.trim() === "") {
2589
+ lines.pop();
2590
+ continue;
2591
+ }
2592
+ if (last.trimStart().startsWith("//") && !last.includes("@nudo")) {
2593
+ lines.pop();
2594
+ continue;
2595
+ }
2596
+ if (last.trim() === "*/" || last.trimStart().startsWith("/*")) {
2597
+ const joined = stripTrailingBlockComments(lines.join("\n"));
2598
+ const stripped = joined.split("\n");
2599
+ if (stripped.length < lines.length) {
2600
+ lines.length = 0;
2601
+ lines.push(...stripped);
2602
+ continue;
2603
+ }
2604
+ }
2605
+ break;
2606
+ }
2607
+ let body = lines.join("\n").replace(/\s+$/, "");
2608
+ body = stripTrailingBlockComments(body);
2609
+ return body + "\n";
2610
+ }
2611
+ function stripTrailingBlockComments(body) {
2612
+ let t = body.replace(/\s+$/, "");
2613
+ while (t.endsWith("*/")) {
2614
+ const start = t.lastIndexOf("/*");
2615
+ if (start < 0) break;
2616
+ const block = t.slice(start);
2617
+ if (block.includes("@nudo")) break;
2618
+ const before = t.slice(0, start);
2619
+ const lineStart = before.lastIndexOf("\n") + 1;
2620
+ if (before.slice(lineStart).trim() !== "") break;
2621
+ t = before.replace(/\s+$/, "");
2622
+ }
2623
+ return t;
2624
+ }
2625
+
2626
+ // src/algebra/check.ts
2627
+ function hofFnArgOk(src, tgt) {
2628
+ if (src.shape.k !== "fn") return false;
2629
+ const t = tgt.shape;
2630
+ if (t.k !== "fn") return false;
2631
+ if (src.shape.params.length < t.params.length) return false;
2632
+ return true;
2633
+ }
2634
+ var checkReportMemo = /* @__PURE__ */ new Map();
2635
+ var checkKeyDeps = /* @__PURE__ */ new Map();
2636
+ var checkDepIndex = /* @__PURE__ */ new Map();
2637
+ var loadModuleIds2 = /* @__PURE__ */ new WeakMap();
2638
+ var nextLoadModuleId2 = 1;
2639
+ var MAX_CHECK_MEMO = 256;
2640
+ function resetCheckSourceMemo() {
2641
+ checkReportMemo.clear();
2642
+ checkKeyDeps.clear();
2643
+ checkDepIndex.clear();
2644
+ resetHashSourceCache();
2645
+ }
2646
+ function getCheckSourceMemoSize() {
2647
+ return checkReportMemo.size;
2648
+ }
2649
+ function loadModuleId2(fn) {
2650
+ if (!fn) return 0;
2651
+ let id = loadModuleIds2.get(fn);
2652
+ if (id === void 0) {
2653
+ id = nextLoadModuleId2++;
2654
+ loadModuleIds2.set(fn, id);
2655
+ }
2656
+ return id;
2657
+ }
2658
+ function checkDepsFingerprint(source, opts) {
2659
+ if (!opts.loadModule || !opts.fromFile) {
2660
+ return { fp: "-", paths: [], truncated: false };
2661
+ }
2662
+ return loadModuleDepsFingerprint(source, opts.loadModule, opts.fromFile);
2663
+ }
2664
+ function unindexCheckKey(key) {
2665
+ const deps = checkKeyDeps.get(key);
2666
+ if (!deps) return;
2667
+ for (const p of deps) {
2668
+ const set = checkDepIndex.get(p);
2669
+ if (!set) continue;
2670
+ set.delete(key);
2671
+ if (set.size === 0) checkDepIndex.delete(p);
2672
+ }
2673
+ checkKeyDeps.delete(key);
2674
+ }
2675
+ function evictCheckSourceMemoForPaths(paths) {
2676
+ let n = 0;
2677
+ for (const raw of paths) {
2678
+ const p = normPath(raw);
2679
+ const keys = checkDepIndex.get(p);
2680
+ if (!keys) continue;
2681
+ for (const key of [...keys]) {
2682
+ checkReportMemo.delete(key);
2683
+ unindexCheckKey(key);
2684
+ n++;
2685
+ }
2686
+ }
2687
+ return n;
2688
+ }
2689
+ function cloneCheckReport(r) {
2690
+ return {
2691
+ file: r.file,
2692
+ issues: r.issues.map((i) => ({ ...i })),
2693
+ ok: r.ok,
2694
+ signatures: r.signatures.map((s) => ({
2695
+ ...s,
2696
+ params: [...s.params]
2697
+ })),
2698
+ summary: { ...r.summary }
2699
+ };
2700
+ }
2701
+ function checkMemoKey(filePath, source, identityOpts, deps) {
2702
+ return [
2703
+ hashSource(source),
2704
+ filePath,
2705
+ `${loadModuleId2(identityOpts.loadModule)}:${identityOpts.fromFile ?? ""}`,
2706
+ deps.fp
2707
+ ].join("|");
2708
+ }
2709
+ function checkMemoGet(key) {
2710
+ if (!checkReportMemo.has(key)) return null;
2711
+ const v2 = checkReportMemo.get(key);
2712
+ checkReportMemo.delete(key);
2713
+ checkReportMemo.set(key, v2);
2714
+ return v2;
2715
+ }
2716
+ function checkMemoSet(key, value, depPaths) {
2717
+ if (checkReportMemo.size >= MAX_CHECK_MEMO) {
2718
+ const oldest = checkReportMemo.keys().next().value;
2719
+ if (oldest !== void 0) {
2720
+ checkReportMemo.delete(oldest);
2721
+ unindexCheckKey(oldest);
2722
+ }
2723
+ }
2724
+ checkReportMemo.set(key, value);
2725
+ if (depPaths.length > 0) {
2726
+ checkKeyDeps.set(key, depPaths);
2727
+ for (const p of depPaths) {
2728
+ let set = checkDepIndex.get(p);
2729
+ if (!set) {
2730
+ set = /* @__PURE__ */ new Set();
2731
+ checkDepIndex.set(p, set);
2732
+ }
2733
+ set.add(key);
2734
+ }
2735
+ }
2736
+ }
2737
+ function listTopFunctions(source, file) {
2738
+ const f = file ?? parseSource(source);
2739
+ const names = [];
2740
+ for (const stmt of f.program.body) {
2741
+ let decl = stmt;
2742
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
2743
+ decl = stmt.declaration;
2744
+ }
2745
+ if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration) {
2746
+ decl = stmt.declaration;
2747
+ }
2748
+ if (decl.type === "FunctionDeclaration" && decl.id) names.push(decl.id.name);
2749
+ if (decl.type === "VariableDeclaration") {
2750
+ for (const d of decl.declarations) {
2751
+ if (d.id.type === "Identifier" && d.init && (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")) {
2752
+ names.push(d.id.name);
2753
+ }
2754
+ }
2755
+ }
2756
+ }
2757
+ return names;
2758
+ }
2759
+ function checkSource(filePath, source, phi = pTrue, opts = {}) {
2760
+ let callOpts = opts;
2761
+ if (opts.loadModule && opts.fromFile) {
2762
+ const loadCache = /* @__PURE__ */ new Map();
2763
+ const raw = opts.loadModule;
2764
+ const fromFile = opts.fromFile;
2765
+ callOpts = {
2766
+ ...opts,
2767
+ loadModule: (spec, from) => {
2768
+ const k = `${from}\0${spec}`;
2769
+ if (!loadCache.has(k)) loadCache.set(k, raw(spec, from));
2770
+ return loadCache.get(k);
2771
+ }
2772
+ };
2773
+ }
2774
+ const useMemo = phi.op === "true";
2775
+ let memoKey;
2776
+ const stable = stableAnalyzeKeySource(source);
2777
+ const depsFp = checkDepsFingerprint(stable, callOpts);
2778
+ const allowMemo = useMemo && !depsFp.truncated;
2779
+ if (allowMemo) {
2780
+ memoKey = checkMemoKey(filePath, stable, opts, depsFp);
2781
+ const hit = checkMemoGet(memoKey);
2782
+ if (hit) return cloneCheckReport(hit);
2783
+ }
2784
+ const issues = [];
2785
+ const signatures = [];
2786
+ const file = parseSource(source);
2787
+ const names = listTopFunctions(source, file);
2788
+ const truncated = /* @__PURE__ */ new Set();
2789
+ resetAbsCallBudget();
2790
+ setAbsTruncationCollector((label) => truncated.add(label));
2791
+ try {
2792
+ const report = checkSourceInner(
2793
+ filePath,
2794
+ source,
2795
+ file,
2796
+ phi,
2797
+ callOpts,
2798
+ issues,
2799
+ signatures,
2800
+ names,
2801
+ truncated,
2802
+ opts,
2803
+ depsFp
2804
+ );
2805
+ if (memoKey) checkMemoSet(memoKey, report, depsFp.paths);
2806
+ return cloneCheckReport(report);
2807
+ } finally {
2808
+ setAbsTruncationCollector(null);
2809
+ }
2810
+ }
2811
+ function checkSourceInner(filePath, source, file, phi, opts, issues, signatures, names, truncated, identityOpts = opts, depsFp) {
2812
+ const hasRefineDirective = source.includes("@nudo:refine");
2813
+ const refineLoad = identityOpts.loadModule ?? opts.loadModule;
2814
+ const refineFrom = identityOpts.fromFile ?? opts.fromFile ?? filePath;
2815
+ for (const name of names) {
2816
+ const g = generalizeFromAst(name, source, {
2817
+ file,
2818
+ refine: {
2819
+ loadModule: refineLoad,
2820
+ fromFile: refineFrom
2821
+ },
2822
+ depsFp
2823
+ });
2824
+ if (!g) {
2825
+ issues.push({
2826
+ severity: "warning",
2827
+ code: "nudo:no-signature",
2828
+ message: `${name}: \u65E0\u6CD5\u5F52\u7EB3\u7B26\u53F7 Abs`,
2829
+ suggestion: "\u8865 @nudo:case \u6216\u8BA9\u51FD\u6570\u4F53\u53EF\u4EE3\u6570\u6C42\u503C",
2830
+ fn: name
2831
+ });
2832
+ continue;
2833
+ }
2834
+ const fmt = formatSigCached(g.symbolic, name);
2835
+ signatures.push({
2836
+ name,
2837
+ params: g.params,
2838
+ abs: g.symbolic,
2839
+ display: fmt.display,
2840
+ detail: fmt.detail,
2841
+ conf: g.symbolic.conf
2842
+ });
2843
+ if (hasRefineDirective) {
2844
+ const ret = extractRefineReturnFromSource(source, name, {
2845
+ loadModule: refineLoad,
2846
+ fromFile: refineFrom
2847
+ });
2848
+ if (ret) {
2849
+ issues.push(
2850
+ ...checkReturnConstraint(name, ret.name, ret.constraint, g.symbolic)
2851
+ );
2852
+ }
2853
+ }
2854
+ if (g.symbolic.conf === "opaque" || g.symbolic.conf === "partial") {
2855
+ const entryArgs = g.typeParams.map((t) => t.value);
2856
+ try {
2857
+ const r = analyzeFn(source, name, entryArgs, phi, void 0, file);
2858
+ if (r.conf === "opaque" && !truncated.has(name)) {
2859
+ issues.push({
2860
+ severity: "info",
2861
+ code: "nudo:opaque-result",
2862
+ message: `${name}(...): conf=opaque\uFF08\u8DEF\u5F84\u672A\u8986\u76D6\u6216 native\uFF09`,
2863
+ suggestion: "\u8865 @nudo:case \u6216\u8C03\u7528\u70B9",
2864
+ fn: name
2865
+ });
2866
+ }
2867
+ } catch (e) {
2868
+ issues.push({
2869
+ severity: "error",
2870
+ code: "nudo:eval-error",
2871
+ message: `${name}: \u6C42\u503C\u5931\u8D25 \u2014 ${e.message}`,
2872
+ fn: name
2873
+ });
2874
+ }
2875
+ }
2876
+ }
2877
+ for (const label of truncated) {
2878
+ issues.push({
2879
+ severity: "warning",
2880
+ code: "nudo:recursion-truncated",
2881
+ message: `Recursive evaluation of '${label}' was truncated (depth/size budget); result widened to unknown`,
2882
+ suggestion: "\u6536\u7A84\u9012\u5F52\u57FA\u4F8B\u6216\u6539\u7528\u663E\u5F0F @nudo:refine return \u5951\u7EA6",
2883
+ fn: label
2884
+ });
2885
+ }
2886
+ const records = [];
2887
+ const varAbs = /* @__PURE__ */ new Map();
2888
+ setAbsAssignCollector((r) => records.push(r));
2889
+ try {
2890
+ const { env } = evalProgramAbs(source, { file });
2891
+ for (const [k, v2] of env.vars) varAbs.set(k, v2);
2892
+ } catch {
2893
+ } finally {
2894
+ setAbsAssignCollector(null);
2895
+ }
2896
+ const callIssues = canSkipLiteralCallScan(source, file) ? [] : scanLiteralCalls(source, names, phi, {
2897
+ loadModule: opts.loadModule,
2898
+ fromFile: filePath,
2899
+ file,
2900
+ varAbs
2901
+ });
2902
+ issues.push(...callIssues);
2903
+ issues.push(
2904
+ ...scanCaseInconsistency(source, names, {
2905
+ loadModule: opts.loadModule,
2906
+ fromFile: filePath,
2907
+ file
2908
+ })
2909
+ );
2910
+ issues.push(...structuralAssignIssues(records));
2911
+ const errors = issues.filter((i) => i.severity === "error").length;
2912
+ const warnings = issues.filter((i) => i.severity === "warning").length;
2913
+ const infos = issues.filter((i) => i.severity === "info").length;
2914
+ return {
2915
+ file: filePath,
2916
+ issues,
2917
+ ok: errors === 0,
2918
+ signatures,
2919
+ summary: { errors, warnings, infos, functions: signatures.length }
2920
+ };
2921
+ }
2922
+ function absUnknown() {
2923
+ return { shape: { k: "unknown" }, conf: "partial" };
2924
+ }
2925
+ var sigFormatCache = /* @__PURE__ */ new WeakMap();
2926
+ function formatSigCached(absVal, name) {
2927
+ const hit = sigFormatCache.get(absVal);
2928
+ if (hit) return hit;
2929
+ const out = {
2930
+ display: formatAbs(absVal),
2931
+ detail: formatAbsMultiline(absVal, name)
2932
+ };
2933
+ sigFormatCache.set(absVal, out);
2934
+ return out;
2935
+ }
2936
+ function checkReturnConstraint(fnName, cName, constraint, ret) {
2937
+ const out = [];
2938
+ if (ret.shape.k === "unknown" && !ret.term) return out;
2939
+ if (ret.shape.k === "any") return out;
2940
+ const push = (actual, expected, suggestion) => {
2941
+ out.push({
2942
+ severity: "error",
2943
+ code: "nudo:constraint-violated",
2944
+ message: `${fnName}: \u8FD4\u56DE\u503C \u22AD @nudo:refine return ${cName}`,
2945
+ actual,
2946
+ expected,
2947
+ suggestion,
2948
+ fn: fnName
2949
+ });
2950
+ };
2951
+ if (constraint.fields) {
2952
+ const slots = ret.shape.k === "obj" ? ret.shape.slots : void 0;
2953
+ if (!slots) {
2954
+ if (ret.shape.k !== "never") {
2955
+ push(formatAbs(ret), `object shape (${cName})`, `\u8FD4\u56DE\u6EE1\u8DB3 ${cName} \u5F62\u72B6\u7684 object`);
2956
+ }
2957
+ return out;
2958
+ }
2959
+ for (const [key, field] of Object.entries(constraint.fields)) {
2960
+ const slot = slots[key];
2961
+ if (!slot) {
2962
+ if (!field.optional && !field.constraint.isOptional) {
2963
+ push(formatAbs(ret), `missing field ${key}`, `\u8FD4\u56DE\u503C\u8865\u5168\u5B57\u6BB5 ${key}`);
2964
+ }
2965
+ continue;
2966
+ }
2967
+ if (field.constraint.prim && slot.value.shape.k === "prim") {
2968
+ const actualPrim = slot.value.shape.type;
2969
+ if (actualPrim !== field.constraint.prim) {
2970
+ push(
2971
+ formatAbs(slot.value),
2972
+ `typeof ${key} = "${field.constraint.prim}"`,
2973
+ `\u628A\u8FD4\u56DE\u503C\u7684 ${key} \u6539\u6210 ${field.constraint.prim}`
2974
+ );
2975
+ continue;
2976
+ }
2977
+ }
2978
+ const lv2 = litValue(slot.value);
2979
+ if (lv2 !== void 0 && typeof lv2 === "number") {
2980
+ for (const p of field.constraint.preds) {
2981
+ const flat = p.op === "and" ? p.args : [p];
2982
+ for (const atom of flat) {
2983
+ if ((atom.op === "gt" || atom.op === "ge" || atom.op === "lt" || atom.op === "le") && atom.b.op === "lit" && typeof atom.b.value === "number") {
2984
+ const n = atom.b.value;
2985
+ let ok = true;
2986
+ if (atom.op === "gt") ok = lv2 > n;
2987
+ if (atom.op === "ge") ok = lv2 >= n;
2988
+ if (atom.op === "lt") ok = lv2 < n;
2989
+ if (atom.op === "le") ok = lv2 <= n;
2990
+ if (!ok) {
2991
+ const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" }[atom.op];
2992
+ push(
2993
+ formatAbs(slot.value),
2994
+ `${key} ${opSym} ${n}`,
2995
+ `\u8FD4\u56DE\u503C\u7684 ${key} \u5E94\u6EE1\u8DB3 ${key} ${opSym} ${n}`
2996
+ );
2997
+ }
2998
+ }
2999
+ }
3000
+ }
3001
+ }
3002
+ }
3003
+ return out;
3004
+ }
3005
+ if (constraint.prim && ret.shape.k === "prim") {
3006
+ const actualPrim = ret.shape.type;
3007
+ if (actualPrim !== constraint.prim) {
3008
+ push(formatAbs(ret), `typeof return = "${constraint.prim}"`, `\u8FD4\u56DE ${constraint.prim}`);
3009
+ return out;
3010
+ }
3011
+ }
3012
+ const lv = litValue(ret);
3013
+ if (lv !== void 0 && typeof lv === "number") {
3014
+ for (const p of constraint.preds) {
3015
+ const flat = p.op === "and" ? p.args : [p];
3016
+ for (const atom of flat) {
3017
+ if ((atom.op === "gt" || atom.op === "ge" || atom.op === "lt" || atom.op === "le") && atom.b.op === "lit" && typeof atom.b.value === "number") {
3018
+ const n = atom.b.value;
3019
+ let ok = true;
3020
+ if (atom.op === "gt") ok = lv > n;
3021
+ if (atom.op === "ge") ok = lv >= n;
3022
+ if (atom.op === "lt") ok = lv < n;
3023
+ if (atom.op === "le") ok = lv <= n;
3024
+ if (!ok) {
3025
+ const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" }[atom.op];
3026
+ push(formatAbs(ret), `return ${opSym} ${n}`, `\u8FD4\u56DE\u6EE1\u8DB3 ${opSym} ${n} \u7684\u503C`);
3027
+ }
3028
+ }
3029
+ }
3030
+ }
3031
+ }
3032
+ return out;
3033
+ }
3034
+ function structuralAssignIssues(records) {
3035
+ const out = [];
3036
+ for (const r of records) {
3037
+ if (!r.prev) continue;
3038
+ if (r.next.shape.k === "unknown" && !r.next.term) continue;
3039
+ if (r.prev.shape.k === "unknown" && !r.prev.term) continue;
3040
+ const leq = leqAbs(r.next, r.prev);
3041
+ if (!leq.ok) {
3042
+ out.push({
3043
+ severity: "error",
3044
+ code: "nudo:assign-mismatch",
3045
+ message: `${r.name}: \u8D4B\u503C \u22AD \u539F\u6709\u5F62\u72B6`,
3046
+ actual: formatAbs(r.next),
3047
+ expected: formatAbs(r.prev),
3048
+ suggestion: leq.reason ?? "\u6539\u7528\u517C\u5BB9\u7684\u503C\uFF0C\u6216\u653E\u5BBD\u7ED1\u5B9A\u7C7B\u578B",
3049
+ fn: r.name,
3050
+ line: r.line,
3051
+ column: r.column
3052
+ });
3053
+ }
3054
+ }
3055
+ return out;
3056
+ }
3057
+ function scanCaseInconsistency(source, knownFns, opts) {
3058
+ const out = [];
3059
+ if (!source.includes("@nudo:case")) return out;
3060
+ if (!source.includes("@nudo:refine")) return out;
3061
+ const file = opts.file ?? parseSource(source);
3062
+ const parseLitArg = (s) => {
3063
+ const t = s.trim();
3064
+ if (t === "") return void 0;
3065
+ if (t === "true") return { shape: { k: "prim", type: "boolean" }, term: { op: "lit", value: true }, conf: "exact" };
3066
+ if (t === "false") return { shape: { k: "prim", type: "boolean" }, term: { op: "lit", value: false }, conf: "exact" };
3067
+ if (t === "null") return { shape: { k: "unknown" }, term: { op: "lit", value: null }, conf: "exact" };
3068
+ if (t === "undefined") return { shape: { k: "unknown" }, term: { op: "lit", value: void 0 }, conf: "exact" };
3069
+ if (/^-?\d+(\.\d+)?$/.test(t)) return numLit(Number(t));
3070
+ const str2 = t.match(/^(['"])([\s\S]*)\1$/);
3071
+ if (str2) {
3072
+ return {
3073
+ shape: { k: "prim", type: "string" },
3074
+ term: { op: "lit", value: str2[2] },
3075
+ conf: "exact"
3076
+ };
3077
+ }
3078
+ return void 0;
3079
+ };
3080
+ const parseCaseArgs = (raw) => {
3081
+ const m = raw.match(/@nudo:case\s+"[^"]+"\s*\(([\s\S]*)\)/);
3082
+ if (!m) return void 0;
3083
+ const inner = m[1].trim();
3084
+ if (inner === "") return [];
3085
+ const parts = [];
3086
+ let depth = 0;
3087
+ let cur = "";
3088
+ let quote = null;
3089
+ for (let i = 0; i < inner.length; i++) {
3090
+ const ch = inner[i];
3091
+ if (quote) {
3092
+ cur += ch;
3093
+ if (ch === quote && inner[i - 1] !== "\\") quote = null;
3094
+ continue;
3095
+ }
3096
+ if (ch === '"' || ch === "'") {
3097
+ quote = ch;
3098
+ cur += ch;
3099
+ continue;
3100
+ }
3101
+ if (ch === "(" || ch === "[" || ch === "{") depth++;
3102
+ if (ch === ")" || ch === "]" || ch === "}") depth--;
3103
+ if (ch === "," && depth === 0) {
3104
+ parts.push(cur);
3105
+ cur = "";
3106
+ continue;
3107
+ }
3108
+ cur += ch;
3109
+ }
3110
+ if (cur.trim()) parts.push(cur);
3111
+ return parts;
3112
+ };
3113
+ const checkCaseAgainstReqs = (fnName, caseName, args, line) => {
3114
+ const g = generalizeFromAst(fnName, source, file ? { file } : {});
3115
+ if (!g) return;
3116
+ const paramNames = g.params;
3117
+ const reqs = refineToIndexedFull(source, fnName, paramNames, {
3118
+ loadModule: opts.loadModule,
3119
+ fromFile: opts.fromFile ?? ""
3120
+ });
3121
+ if (reqs.length === 0) return;
3122
+ const absArgs = args.map((a) => parseLitArg(a) ?? absUnknown());
3123
+ for (const [idx, entry] of reqs) {
3124
+ if (entry.constraint.fields) continue;
3125
+ const arg = absArgs[idx];
3126
+ if (!arg) continue;
3127
+ const lv = litValue(arg);
3128
+ if (lv === void 0 || typeof lv !== "number") continue;
3129
+ const flatten = (p) => p.op === "and" ? p.args.flatMap(flatten) : p.op === "true" ? [] : [p];
3130
+ for (const p of flatten(entry.pred)) {
3131
+ if ((p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le") && p.b.op === "lit" && typeof p.b.value === "number") {
3132
+ const n = p.b.value;
3133
+ let ok = true;
3134
+ if (p.op === "gt") ok = lv > n;
3135
+ if (p.op === "ge") ok = lv >= n;
3136
+ if (p.op === "lt") ok = lv < n;
3137
+ if (p.op === "le") ok = lv <= n;
3138
+ if (!ok) {
3139
+ const paramName = entry.param || paramNames[idx] || `arg${idx}`;
3140
+ out.push({
3141
+ severity: "error",
3142
+ code: "nudo:case-inconsistency",
3143
+ message: `${fnName} case "${caseName}": \u89C1\u8BC1 \u22AD \u5951\u7EA6`,
3144
+ actual: formatAbs(arg),
3145
+ expected: predToString(p),
3146
+ suggestion: `\u6539 case \u5B9E\u53C2\uFF0C\u6216\u653E\u5BBD ${paramName} \u7684 refine`,
3147
+ fn: fnName,
3148
+ line
3149
+ });
3150
+ }
3151
+ }
3152
+ }
3153
+ }
3154
+ };
3155
+ const visit = (n) => {
3156
+ if (!n || typeof n !== "object") return;
3157
+ const obj2 = n;
3158
+ let decl = obj2;
3159
+ if (obj2.type === "ExportNamedDeclaration" || obj2.type === "ExportDefaultDeclaration") {
3160
+ decl = obj2.declaration;
3161
+ }
3162
+ if (decl && (decl.type === "FunctionDeclaration" || decl.type === "VariableDeclaration" && (decl.declarations ?? [])[0]?.init && ["ArrowFunctionExpression", "FunctionExpression"].includes(
3163
+ String(
3164
+ decl.declarations[0].init.type
3165
+ )
3166
+ ))) {
3167
+ const id = decl.type === "FunctionDeclaration" ? decl.id?.name : decl.declarations[0]?.id?.name;
3168
+ if (id && knownFns.includes(id)) {
3169
+ for (const c of obj2.leadingComments ?? []) {
3170
+ const caseArgs = parseCaseArgs(c.value);
3171
+ if (!caseArgs) continue;
3172
+ const caseName = /@nudo:case\s+"([^"]+)"/.exec(c.value)?.[1] ?? "?";
3173
+ checkCaseAgainstReqs(id, caseName, caseArgs, c.loc?.start.line);
3174
+ }
3175
+ }
3176
+ }
3177
+ for (const key of Object.keys(obj2)) {
3178
+ if (key === "loc" || key === "start" || key === "end" || key === "leadingComments") continue;
3179
+ const val = obj2[key];
3180
+ if (Array.isArray(val)) val.forEach(visit);
3181
+ else if (val && typeof val === "object") visit(val);
3182
+ }
3183
+ };
3184
+ visit(file);
3185
+ return out;
3186
+ }
3187
+ function collectParamStructReqs(source, fnName, fileAst) {
3188
+ const reqs = /* @__PURE__ */ new Map();
3189
+ const extracted = extractFn(source, fnName, fileAst);
3190
+ if (!extracted) return reqs;
3191
+ const params = new Set(extracted.params);
3192
+ const body = extracted.body;
3193
+ const BUILTIN_METHODS = /* @__PURE__ */ new Set([
3194
+ "map",
3195
+ "filter",
3196
+ "reduce",
3197
+ "flatMap",
3198
+ "forEach",
3199
+ "some",
3200
+ "every",
3201
+ "find",
3202
+ "findIndex",
3203
+ "includes",
3204
+ "indexOf",
3205
+ "lastIndexOf",
3206
+ "join",
3207
+ "slice",
3208
+ "splice",
3209
+ "push",
3210
+ "pop",
3211
+ "shift",
3212
+ "unshift",
3213
+ "sort",
3214
+ "reverse",
3215
+ "concat",
3216
+ "at",
3217
+ "replace",
3218
+ "replaceAll",
3219
+ "split",
3220
+ "trim",
3221
+ "toLowerCase",
3222
+ "toUpperCase",
3223
+ "startsWith",
3224
+ "endsWith",
3225
+ "charAt",
3226
+ "charCodeAt",
3227
+ "padStart",
3228
+ "padEnd",
3229
+ "repeat",
3230
+ "toString",
3231
+ "valueOf",
3232
+ "substring",
3233
+ "match",
3234
+ "search",
3235
+ "hasOwnProperty",
3236
+ "keys",
3237
+ "values",
3238
+ "entries",
3239
+ "then",
3240
+ "catch",
3241
+ "finally"
3242
+ ]);
3243
+ const visit = (n, isMethodCallee = false) => {
3244
+ if (!n || typeof n !== "object") return;
3245
+ const obj2 = n;
3246
+ if (obj2.type === "MemberExpression" && !obj2.computed && !isMethodCallee) {
3247
+ const o = obj2.object;
3248
+ const p = obj2.property;
3249
+ if (o?.type === "Identifier" && o.name && params.has(o.name) && p?.type === "Identifier" && p.name) {
3250
+ if (BUILTIN_METHODS.has(p.name)) return;
3251
+ let set = reqs.get(o.name);
3252
+ if (!set) {
3253
+ set = /* @__PURE__ */ new Set();
3254
+ reqs.set(o.name, set);
3255
+ }
3256
+ set.add(p.name);
3257
+ }
3258
+ }
3259
+ if (obj2.type === "CallExpression") {
3260
+ visit(obj2.callee, true);
3261
+ for (const key of Object.keys(obj2)) {
3262
+ if (key === "loc" || key === "start" || key === "end" || key === "callee") continue;
3263
+ const val = obj2[key];
3264
+ if (Array.isArray(val)) val.forEach((v2) => visit(v2, false));
3265
+ else if (val && typeof val === "object") visit(val, false);
3266
+ }
3267
+ return;
3268
+ }
3269
+ for (const key of Object.keys(obj2)) {
3270
+ if (key === "loc" || key === "start" || key === "end") continue;
3271
+ const val = obj2[key];
3272
+ if (Array.isArray(val)) val.forEach((v2) => visit(v2, isMethodCallee));
3273
+ else if (val && typeof val === "object") visit(val, isMethodCallee);
3274
+ }
3275
+ };
3276
+ visit(body);
3277
+ return reqs;
3278
+ }
3279
+ function evalArgAbs(node, lookupVar) {
3280
+ if (node.type === "Identifier" && typeof node.name === "string" && lookupVar) {
3281
+ return lookupVar(node.name);
3282
+ }
3283
+ try {
3284
+ const env = emptyEnv();
3285
+ if (lookupVar) {
3286
+ const rawGet = env.vars.get.bind(env.vars);
3287
+ env.vars.get = ((name) => {
3288
+ const hit = rawGet(name);
3289
+ if (hit !== void 0) return hit;
3290
+ return lookupVar(name);
3291
+ });
3292
+ }
3293
+ return evalNode(node, env, pTrue, defaultLeakBudget).value;
3294
+ } catch {
3295
+ return void 0;
3296
+ }
3297
+ }
3298
+ function requireSpecOf(init) {
3299
+ if (init.type === "CallExpression") {
3300
+ const callee = init.callee;
3301
+ const args = init.arguments;
3302
+ if (callee?.type === "Identifier" && callee.name === "require" && args?.[0]?.type === "StringLiteral") {
3303
+ return String(args[0].value);
3304
+ }
3305
+ }
3306
+ if (init.type === "MemberExpression") {
3307
+ const obj2 = init.object;
3308
+ if (obj2) return requireSpecOf(obj2);
3309
+ }
3310
+ return void 0;
3311
+ }
3312
+ function requireExportName(init) {
3313
+ if (init.type === "MemberExpression" && !init.computed) {
3314
+ const prop = init.property;
3315
+ if (prop?.type === "Identifier") return prop.name;
3316
+ }
3317
+ return void 0;
3318
+ }
3319
+ function dynamicImportSpec(node) {
3320
+ let n = node;
3321
+ if (n?.type === "AwaitExpression") {
3322
+ n = n.argument;
3323
+ }
3324
+ if (n?.type !== "CallExpression") return void 0;
3325
+ const callee = n.callee;
3326
+ if (callee?.type !== "Import") return void 0;
3327
+ const args = n.arguments;
3328
+ if (args?.[0]?.type === "StringLiteral") return String(args[0].value);
3329
+ return void 0;
3330
+ }
3331
+ function resolveExportSource(modSrc, fnName, loadSpec, depth = 0) {
3332
+ if (depth > 3) return modSrc;
3333
+ try {
3334
+ if (listTopFunctions(modSrc).includes(fnName)) return modSrc;
3335
+ } catch {
3336
+ return modSrc;
3337
+ }
3338
+ const file = parseSource(modSrc);
3339
+ let nextSpec;
3340
+ for (const stmt of file.program.body) {
3341
+ if (stmt.type !== "ExportNamedDeclaration" && stmt.type !== "ExportAllDeclaration") continue;
3342
+ const src = stmt.source;
3343
+ if (src?.type !== "StringLiteral" || typeof src.value !== "string") continue;
3344
+ if (stmt.type === "ExportAllDeclaration") {
3345
+ nextSpec = String(src.value);
3346
+ break;
3347
+ }
3348
+ const clause = stmt.specifiers ?? [];
3349
+ for (const sp of clause) {
3350
+ if (sp.type !== "ExportSpecifier") continue;
3351
+ const local = sp.local;
3352
+ if (local?.type === "Identifier" && local.name === fnName) {
3353
+ nextSpec = String(src.value);
3354
+ break;
3355
+ }
3356
+ }
3357
+ if (nextSpec) break;
3358
+ }
3359
+ if (!nextSpec) return modSrc;
3360
+ const next = loadSpec(nextSpec);
3361
+ if (!next) return modSrc;
3362
+ return resolveExportSource(next, fnName, loadSpec, depth + 1);
3363
+ }
3364
+ var STMT_CONTAINER = /* @__PURE__ */ new Set([
3365
+ "File",
3366
+ "Program",
3367
+ "BlockStatement",
3368
+ "FunctionDeclaration",
3369
+ "FunctionExpression",
3370
+ "ArrowFunctionExpression",
3371
+ "IfStatement",
3372
+ "ForStatement",
3373
+ "ForInStatement",
3374
+ "ForOfStatement",
3375
+ "WhileStatement",
3376
+ "DoWhileStatement",
3377
+ "SwitchStatement",
3378
+ "SwitchCase",
3379
+ "TryStatement",
3380
+ "CatchClause",
3381
+ "LabeledStatement",
3382
+ "ExportNamedDeclaration",
3383
+ "ExportDefaultDeclaration",
3384
+ "ExportAllDeclaration",
3385
+ "ClassDeclaration",
3386
+ "ClassBody",
3387
+ "ClassMethod",
3388
+ "StaticBlock",
3389
+ "ObjectMethod"
3390
+ ]);
3391
+ function walkStatements(n, onStmt) {
3392
+ if (!n || typeof n !== "object") return;
3393
+ const obj2 = n;
3394
+ if (typeof obj2.type === "string") onStmt(obj2);
3395
+ if (!STMT_CONTAINER.has(String(obj2.type))) return;
3396
+ for (const key of Object.keys(obj2)) {
3397
+ if (key === "loc" || key === "start" || key === "end" || key === "leadingComments") continue;
3398
+ const val = obj2[key];
3399
+ if (Array.isArray(val)) val.forEach((x) => walkStatements(x, onStmt));
3400
+ else if (val && typeof val === "object") walkStatements(val, onStmt);
3401
+ }
3402
+ }
3403
+ function collectCallResolvers(source, knownFns, opts) {
3404
+ const knownSet = new Set(knownFns);
3405
+ const aliasToFn = /* @__PURE__ */ new Map();
3406
+ const memberToFn = /* @__PURE__ */ new Map();
3407
+ const externalFn = /* @__PURE__ */ new Map();
3408
+ const externalMember = /* @__PURE__ */ new Map();
3409
+ const file = opts?.file ?? parseSource(source);
3410
+ const load = opts?.loadModule;
3411
+ const fromFile = opts?.fromFile ?? "";
3412
+ const modCache = /* @__PURE__ */ new Map();
3413
+ const loadSpec = (spec) => {
3414
+ if (!load) return void 0;
3415
+ if (!modCache.has(spec)) modCache.set(spec, load(spec, fromFile));
3416
+ return modCache.get(spec);
3417
+ };
3418
+ const bindExternal = (local, modSrc, fnName) => {
3419
+ externalFn.set(local, {
3420
+ source: resolveExportSource(modSrc, fnName, loadSpec),
3421
+ fnName
3422
+ });
3423
+ };
3424
+ const visit = (n) => {
3425
+ if (!n || typeof n !== "object") return;
3426
+ const obj2 = n;
3427
+ if (obj2.type === "ImportDeclaration") {
3428
+ const spec = obj2.source;
3429
+ if (spec?.type === "StringLiteral" && typeof spec.value === "string") {
3430
+ const modSrc = loadSpec(String(spec.value));
3431
+ if (modSrc) {
3432
+ for (const sp of obj2.specifiers ?? []) {
3433
+ if (sp.type === "ImportSpecifier") {
3434
+ const imported = sp.imported;
3435
+ const local = sp.local;
3436
+ const exportName = imported?.type === "Identifier" ? imported.name : imported?.type === "StringLiteral" ? String(imported.value) : void 0;
3437
+ if (exportName && local?.name) {
3438
+ bindExternal(local.name, modSrc, exportName);
3439
+ }
3440
+ } else if (sp.type === "ImportNamespaceSpecifier") {
3441
+ const local = sp.local;
3442
+ if (local?.name) {
3443
+ externalMember.set(`${local.name}.__module__`, { source: modSrc, fnName: "" });
3444
+ }
3445
+ }
3446
+ }
3447
+ }
3448
+ }
3449
+ }
3450
+ if (obj2.type === "VariableDeclaration") {
3451
+ for (const d of obj2.declarations ?? []) {
3452
+ const id = d.id;
3453
+ const init = d.init;
3454
+ if (!id || !init) continue;
3455
+ const dynSpec = dynamicImportSpec(init);
3456
+ if (dynSpec) {
3457
+ const modSrc = loadSpec(dynSpec);
3458
+ if (modSrc && id.type === "ObjectPattern") {
3459
+ for (const p of id.properties ?? []) {
3460
+ const key = p.key;
3461
+ const val = p.value;
3462
+ const exported = key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? String(key.value) : void 0;
3463
+ const local = val?.type === "Identifier" ? val.name : exported;
3464
+ if (exported && local) bindExternal(local, modSrc, exported);
3465
+ }
3466
+ }
3467
+ if (modSrc && id.type === "Identifier" && id.name) {
3468
+ externalMember.set(`${id.name}.__module__`, { source: modSrc, fnName: "" });
3469
+ }
3470
+ }
3471
+ const spec = requireSpecOf(init);
3472
+ if (spec) {
3473
+ const modSrc = loadSpec(spec);
3474
+ if (id.type === "ObjectPattern" && modSrc) {
3475
+ for (const p of id.properties ?? []) {
3476
+ const key = p.key;
3477
+ const val = p.value;
3478
+ const exported = key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? String(key.value) : void 0;
3479
+ const local = val?.type === "Identifier" ? val.name : exported;
3480
+ if (exported && local) {
3481
+ bindExternal(local, modSrc, exported);
3482
+ }
3483
+ }
3484
+ }
3485
+ if (id.type === "Identifier" && id.name && modSrc) {
3486
+ const exportName = requireExportName(init);
3487
+ if (exportName) {
3488
+ bindExternal(id.name, modSrc, exportName);
3489
+ } else {
3490
+ externalMember.set(`${id.name}.__module__`, { source: modSrc, fnName: "" });
3491
+ }
3492
+ }
3493
+ }
3494
+ if (id.type !== "Identifier" || !id.name) continue;
3495
+ if (init.type === "Identifier" && typeof init.name === "string" && knownSet.has(init.name)) {
3496
+ aliasToFn.set(id.name, init.name);
3497
+ }
3498
+ if (init.type === "ObjectExpression") {
3499
+ for (const p of init.properties ?? []) {
3500
+ if (p.type !== "ObjectProperty") continue;
3501
+ const key = p.key;
3502
+ const value = p.value;
3503
+ if (value?.type === "Identifier" && value.name && knownSet.has(value.name)) {
3504
+ const propKey = key?.type === "Identifier" ? key.name : key?.type === "StringLiteral" ? String(key.value) : void 0;
3505
+ if (propKey) memberToFn.set(`${id.name}.${propKey}`, value.name);
3506
+ }
3507
+ }
3508
+ }
3509
+ }
3510
+ }
3511
+ };
3512
+ walkStatements(file, visit);
3513
+ return { aliasToFn, memberToFn, externalFn, externalMember };
3514
+ }
3515
+ function resolveCalleeFn(callee, resolve, knownFns) {
3516
+ if (callee.type === "Identifier" && typeof callee.name === "string") {
3517
+ const ext = resolve.externalFn.get(callee.name);
3518
+ if (ext) return { external: ext };
3519
+ const aliased = resolve.aliasToFn.get(callee.name);
3520
+ if (aliased) return aliased;
3521
+ if (knownFns.has(callee.name)) return callee.name;
3522
+ return void 0;
3523
+ }
3524
+ if (callee.type === "MemberExpression") {
3525
+ const obj2 = callee.object;
3526
+ const prop = callee.property;
3527
+ if (!callee.computed && obj2?.type === "Identifier" && obj2.name && prop?.type === "Identifier" && prop.name) {
3528
+ const key = `${obj2.name}.${prop.name}`;
3529
+ const extM = resolve.externalMember.get(key);
3530
+ if (extM) return { external: extM };
3531
+ const mod2 = resolve.externalMember.get(`${obj2.name}.__module__`);
3532
+ if (mod2?.source) {
3533
+ return { external: { source: mod2.source, fnName: prop.name } };
3534
+ }
3535
+ const local = resolve.memberToFn.get(key);
3536
+ if (local) return local;
3537
+ }
3538
+ }
3539
+ return void 0;
3540
+ }
3541
+ function collectForwarders(source, knownFns, resolve, fileAst) {
3542
+ const forwards = /* @__PURE__ */ new Map();
3543
+ const file = fileAst ?? parseSource(source);
3544
+ const tryFn = (name, params, body) => {
3545
+ if (!name || !params.length) return;
3546
+ const paramNames = params.map((p) => p?.type === "Identifier" ? p.name : void 0);
3547
+ if (paramNames.some((n) => !n)) return;
3548
+ let call;
3549
+ if (body?.type === "BlockStatement") {
3550
+ const stmts = body.body ?? [];
3551
+ if (stmts.length !== 1 || stmts[0].type !== "ReturnStatement") return;
3552
+ const arg = stmts[0].argument;
3553
+ if (arg?.type !== "CallExpression") return;
3554
+ call = arg;
3555
+ } else if (body?.type === "CallExpression") {
3556
+ call = body;
3557
+ }
3558
+ if (!call) return;
3559
+ const resolved = resolveCalleeFn(call.callee, resolve, knownFns);
3560
+ if (!resolved || typeof resolved !== "string") return;
3561
+ if (!knownFns.has(resolved) || resolved === name) return;
3562
+ const args = call.arguments ?? [];
3563
+ if (args.length === 0) return;
3564
+ const map = [];
3565
+ for (const a of args) {
3566
+ if (a.type !== "Identifier" || typeof a.name !== "string") return;
3567
+ const idx = paramNames.indexOf(a.name);
3568
+ if (idx < 0) return;
3569
+ map.push(idx);
3570
+ }
3571
+ forwards.set(name, { target: resolved, map });
3572
+ };
3573
+ walkStatements(file, (obj2) => {
3574
+ if (obj2.type === "FunctionDeclaration") {
3575
+ const id = obj2.id;
3576
+ tryFn(
3577
+ id?.name ?? "",
3578
+ obj2.params ?? [],
3579
+ obj2.body
3580
+ );
3581
+ }
3582
+ if (obj2.type === "VariableDeclaration") {
3583
+ for (const d of obj2.declarations ?? []) {
3584
+ const id = d.id;
3585
+ const init = d.init;
3586
+ if (id?.type === "Identifier" && id.name && init && (init.type === "ArrowFunctionExpression" || init.type === "FunctionExpression")) {
3587
+ tryFn(
3588
+ id.name,
3589
+ init.params ?? [],
3590
+ init.body
3591
+ );
3592
+ }
3593
+ }
3594
+ }
3595
+ });
3596
+ return forwards;
3597
+ }
3598
+ function scanLiteralCalls(source, knownFns, phi, opts) {
3599
+ const out = [];
3600
+ const file = opts?.file ?? parseSource(source);
3601
+ const knownSet = new Set(knownFns);
3602
+ const resolve = collectCallResolvers(source, knownFns, opts);
3603
+ const forwards = collectForwarders(source, knownSet, resolve, file);
3604
+ const varAbs = opts?.varAbs ?? /* @__PURE__ */ new Map();
3605
+ const flattenPred = (p) => p.op === "and" ? p.args.flatMap(flattenPred) : p.op === "true" ? [] : [p];
3606
+ const checkReqs = (displayName, reqs, paramNames, absArgs, argIndexOf, loc) => {
3607
+ for (const [idx, pred] of reqs) {
3608
+ const argIdx = argIndexOf(idx);
3609
+ if (argIdx === void 0) continue;
3610
+ const arg = absArgs[argIdx];
3611
+ if (!arg) continue;
3612
+ const lv = litValue(arg);
3613
+ const isStr = arg.shape.k === "prim" && arg.shape.type === "string";
3614
+ const strLen = typeof lv === "string" ? lv.length : void 0;
3615
+ const paramName = paramNames[idx] ?? `arg${idx}`;
3616
+ for (const p of flattenPred(pred)) {
3617
+ if (p.op === "typeof") {
3618
+ if (p.t.op !== "var") continue;
3619
+ const expected = p.type;
3620
+ const actualPrim = arg.shape.k === "prim" ? arg.shape.type : arg.shape.k === "obj" || arg.shape.k === "arr" || arg.shape.k === "tuple" ? "object" : arg.shape.k === "fn" ? "function" : void 0;
3621
+ if (actualPrim !== void 0 && actualPrim !== expected) {
3622
+ out.push({
3623
+ severity: "error",
3624
+ code: "nudo:constraint-violated",
3625
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3626
+ actual: formatAbs(arg),
3627
+ expected: `typeof ${paramName} = "${expected}"`,
3628
+ suggestion: `\u6539\u7528 ${expected} \u7C7B\u578B\u7684\u503C\uFF0C\u6216\u653E\u5BBD ${paramName} \u7684 refine`,
3629
+ fn: displayName,
3630
+ line: loc?.start.line,
3631
+ column: loc?.start.column
3632
+ });
3633
+ }
3634
+ continue;
3635
+ }
3636
+ if (lv === void 0) continue;
3637
+ if ((p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le") && p.b.op === "lit" && typeof p.b.value === "number") {
3638
+ const n = p.b.value;
3639
+ const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" }[p.op];
3640
+ if (p.a.op === "app" && p.a.fn === "length" && strLen !== void 0) {
3641
+ let ok2 = true;
3642
+ if (p.op === "gt") ok2 = strLen > n;
3643
+ if (p.op === "ge") ok2 = strLen >= n;
3644
+ if (p.op === "lt") ok2 = strLen < n;
3645
+ if (p.op === "le") ok2 = strLen <= n;
3646
+ if (!ok2) {
3647
+ const paramName2 = paramNames[idx] ?? `arg${idx}`;
3648
+ out.push({
3649
+ severity: "error",
3650
+ code: "nudo:constraint-violated",
3651
+ message: `${displayName}[${paramName2}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3652
+ actual: formatAbs(arg),
3653
+ expected: `length(${paramName2}) ${opSym} ${n}`,
3654
+ suggestion: `\u6539\u7528\u6EE1\u8DB3\u957F\u5EA6 ${opSym} ${n} \u7684\u503C\uFF0C\u6216\u653E\u5BBD ${paramName2} \u7684\u524D\u7F6E`,
3655
+ fn: displayName,
3656
+ line: loc?.start.line,
3657
+ column: loc?.start.column
3658
+ });
3659
+ }
3660
+ continue;
3661
+ }
3662
+ if (isStr || typeof lv !== "number") continue;
3663
+ let ok = true;
3664
+ if (p.op === "gt") ok = lv > n;
3665
+ if (p.op === "ge") ok = lv >= n;
3666
+ if (p.op === "lt") ok = lv < n;
3667
+ if (p.op === "le") ok = lv <= n;
3668
+ if (!ok) {
3669
+ const paramName2 = paramNames[idx] ?? `arg${idx}`;
3670
+ out.push({
3671
+ severity: "error",
3672
+ code: "nudo:constraint-violated",
3673
+ message: `${displayName}[${paramName2}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3674
+ actual: formatAbs(arg),
3675
+ expected: predToString(p),
3676
+ suggestion: `\u6539\u7528\u6EE1\u8DB3 ${predToString(p)} \u7684\u503C\uFF0C\u6216\u653E\u5BBD ${paramName2} \u7684\u524D\u7F6E`,
3677
+ fn: displayName,
3678
+ line: loc?.start.line,
3679
+ column: loc?.start.column
3680
+ });
3681
+ }
3682
+ }
3683
+ }
3684
+ }
3685
+ };
3686
+ const checkShapeAgainstAbs = (displayName, paramName, constraint, absArg, path, loc) => {
3687
+ if (!constraint.fields) return;
3688
+ if (absArg.shape.k === "unknown" && !absArg.term) return;
3689
+ const slots = absArg.shape.k === "obj" ? absArg.shape.slots : void 0;
3690
+ if (!slots) {
3691
+ if (absArg.shape.k !== "unknown" && absArg.shape.k !== "never") {
3692
+ out.push({
3693
+ severity: "error",
3694
+ code: "nudo:constraint-violated",
3695
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3696
+ actual: formatAbs(absArg),
3697
+ expected: `object shape at ${path}`,
3698
+ suggestion: `\u6539\u7528\u6EE1\u8DB3 ${path} \u5F62\u72B6\u7EA6\u675F\u7684 object`,
3699
+ fn: displayName,
3700
+ line: loc?.start.line,
3701
+ column: loc?.start.column
3702
+ });
3703
+ }
3704
+ return;
3705
+ }
3706
+ for (const [key, field] of Object.entries(constraint.fields)) {
3707
+ const slot = slots[key];
3708
+ const fieldPath = path === paramName ? `${paramName}.${key}` : `${path}.${key}`;
3709
+ if (!slot) {
3710
+ if (!field.optional && !field.constraint.isOptional) {
3711
+ out.push({
3712
+ severity: "error",
3713
+ code: "nudo:constraint-violated",
3714
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3715
+ actual: formatAbs(absArg),
3716
+ expected: `missing field ${fieldPath}`,
3717
+ suggestion: `\u8865\u5168\u5B57\u6BB5 ${fieldPath}`,
3718
+ fn: displayName,
3719
+ line: loc?.start.line,
3720
+ column: loc?.start.column
3721
+ });
3722
+ }
3723
+ continue;
3724
+ }
3725
+ checkFieldConstraint(displayName, paramName, field.constraint, slot.value, fieldPath, loc);
3726
+ }
3727
+ };
3728
+ const checkFieldConstraint = (displayName, paramName, constraint, fieldAbs, fieldPath, loc) => {
3729
+ if (fieldAbs.shape.k === "unknown" && !fieldAbs.term) return;
3730
+ if (constraint.prim && fieldAbs.shape.k === "prim") {
3731
+ const actualPrim = fieldAbs.shape.type;
3732
+ if (actualPrim !== constraint.prim) {
3733
+ out.push({
3734
+ severity: "error",
3735
+ code: "nudo:constraint-violated",
3736
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3737
+ actual: formatAbs(fieldAbs),
3738
+ expected: `typeof ${fieldPath} = "${constraint.prim}"`,
3739
+ suggestion: `\u628A ${fieldPath} \u6539\u6210 ${constraint.prim}`,
3740
+ fn: displayName,
3741
+ line: loc?.start.line,
3742
+ column: loc?.start.column
3743
+ });
3744
+ return;
3745
+ }
3746
+ }
3747
+ if (constraint.int) {
3748
+ const iv = litValue(fieldAbs);
3749
+ if (typeof iv === "number" && !Number.isInteger(iv)) {
3750
+ out.push({
3751
+ severity: "error",
3752
+ code: "nudo:constraint-violated",
3753
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3754
+ actual: formatAbs(fieldAbs),
3755
+ expected: `${fieldPath} is int`,
3756
+ suggestion: `\u628A ${fieldPath} \u6539\u6210\u6574\u6570`,
3757
+ fn: displayName,
3758
+ line: loc?.start.line,
3759
+ column: loc?.start.column
3760
+ });
3761
+ }
3762
+ }
3763
+ if (constraint.fields) {
3764
+ checkShapeAgainstAbs(displayName, paramName, constraint, fieldAbs, fieldPath, loc);
3765
+ }
3766
+ if (constraint.element) {
3767
+ if (fieldAbs.shape.k === "arr") {
3768
+ checkFieldConstraint(
3769
+ displayName,
3770
+ paramName,
3771
+ constraint.element,
3772
+ fieldAbs.shape.element,
3773
+ `${fieldPath}[]`,
3774
+ loc
3775
+ );
3776
+ } else if (fieldAbs.shape.k === "tuple") {
3777
+ const els = fieldAbs.shape.elements;
3778
+ els.forEach((el, i) => {
3779
+ checkFieldConstraint(
3780
+ displayName,
3781
+ paramName,
3782
+ constraint.element,
3783
+ el,
3784
+ `${fieldPath}[${i}]`,
3785
+ loc
3786
+ );
3787
+ });
3788
+ }
3789
+ }
3790
+ const lv = litValue(fieldAbs);
3791
+ const sv = typeof lv === "string" ? lv.length : void 0;
3792
+ const isStr = fieldAbs.shape.k === "prim" && fieldAbs.shape.type === "string";
3793
+ for (const p of constraint.preds) {
3794
+ const flat = p.op === "and" ? p.args : [p];
3795
+ for (const atom of flat) {
3796
+ if ((atom.op === "gt" || atom.op === "ge" || atom.op === "lt" || atom.op === "le") && atom.b.op === "lit" && typeof atom.b.value === "number") {
3797
+ const n = atom.b.value;
3798
+ const opSym = { gt: ">", ge: "\u2265", lt: "<", le: "\u2264" }[atom.op];
3799
+ if (atom.a.op === "app" && atom.a.fn === "length") {
3800
+ if (sv === void 0) continue;
3801
+ let ok2 = true;
3802
+ if (atom.op === "gt") ok2 = sv > n;
3803
+ if (atom.op === "ge") ok2 = sv >= n;
3804
+ if (atom.op === "lt") ok2 = sv < n;
3805
+ if (atom.op === "le") ok2 = sv <= n;
3806
+ if (!ok2) {
3807
+ out.push({
3808
+ severity: "error",
3809
+ code: "nudo:constraint-violated",
3810
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3811
+ actual: formatAbs(fieldAbs),
3812
+ expected: `length(${fieldPath}) ${opSym} ${n}`,
3813
+ suggestion: `\u6539\u7528\u6EE1\u8DB3\u957F\u5EA6 ${opSym} ${n} \u7684 ${fieldPath}`,
3814
+ fn: displayName,
3815
+ line: loc?.start.line,
3816
+ column: loc?.start.column
3817
+ });
3818
+ }
3819
+ continue;
3820
+ }
3821
+ if (lv === void 0 || typeof lv !== "number" || isStr) continue;
3822
+ let ok = true;
3823
+ if (atom.op === "gt") ok = lv > n;
3824
+ if (atom.op === "ge") ok = lv >= n;
3825
+ if (atom.op === "lt") ok = lv < n;
3826
+ if (atom.op === "le") ok = lv <= n;
3827
+ if (!ok) {
3828
+ out.push({
3829
+ severity: "error",
3830
+ code: "nudo:constraint-violated",
3831
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3832
+ actual: formatAbs(fieldAbs),
3833
+ expected: `${fieldPath} ${opSym} ${n}`,
3834
+ suggestion: `\u6539\u7528\u6EE1\u8DB3 ${fieldPath} ${opSym} ${n} \u7684\u503C\uFF0C\u6216\u653E\u5BBD ${paramName} \u7684\u524D\u7F6E`,
3835
+ fn: displayName,
3836
+ line: loc?.start.line,
3837
+ column: loc?.start.column
3838
+ });
3839
+ }
3840
+ }
3841
+ }
3842
+ }
3843
+ };
3844
+ const checkShapeReqs = (displayName, reqs, paramNames, absArgs, argIndexOf, loc) => {
3845
+ for (const [idx, entry] of reqs) {
3846
+ const c = entry.constraint;
3847
+ if (!c.fields && !c.element && !c.int && !c.prim) continue;
3848
+ const argIdx = argIndexOf(idx);
3849
+ if (argIdx === void 0) continue;
3850
+ const arg = absArgs[argIdx];
3851
+ if (!arg) continue;
3852
+ const paramName = entry.param || paramNames[idx] || `arg${idx}`;
3853
+ if (c.fields) {
3854
+ checkShapeAgainstAbs(displayName, paramName, c, arg, paramName, loc);
3855
+ }
3856
+ if (c.element) {
3857
+ if (arg.shape.k === "arr") {
3858
+ checkFieldConstraint(
3859
+ displayName,
3860
+ paramName,
3861
+ c.element,
3862
+ arg.shape.element,
3863
+ `${paramName}[]`,
3864
+ loc
3865
+ );
3866
+ } else if (arg.shape.k === "tuple") {
3867
+ const els = arg.shape.elements;
3868
+ els.forEach((el, i) => {
3869
+ checkFieldConstraint(
3870
+ displayName,
3871
+ paramName,
3872
+ c.element,
3873
+ el,
3874
+ `${paramName}[${i}]`,
3875
+ loc
3876
+ );
3877
+ });
3878
+ } else if (arg.shape.k !== "unknown" && arg.shape.k !== "any") {
3879
+ out.push({
3880
+ severity: "error",
3881
+ code: "nudo:constraint-violated",
3882
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3883
+ actual: formatAbs(arg),
3884
+ expected: `array at ${paramName}`,
3885
+ suggestion: `\u6539\u7528\u6EE1\u8DB3 array \u7EA6\u675F\u7684\u503C`,
3886
+ fn: displayName,
3887
+ line: loc?.start.line,
3888
+ column: loc?.start.column
3889
+ });
3890
+ }
3891
+ }
3892
+ if (c.int) {
3893
+ const iv = litValue(arg);
3894
+ if (typeof iv === "number" && !Number.isInteger(iv)) {
3895
+ out.push({
3896
+ severity: "error",
3897
+ code: "nudo:constraint-violated",
3898
+ message: `${displayName}[${paramName}]: \u5B9E\u53C2 \u22AD \u524D\u7F6E`,
3899
+ actual: formatAbs(arg),
3900
+ expected: `${paramName} is int`,
3901
+ suggestion: `\u6539\u7528\u6574\u6570`,
3902
+ fn: displayName,
3903
+ line: loc?.start.line,
3904
+ column: loc?.start.column
3905
+ });
3906
+ }
3907
+ }
3908
+ }
3909
+ };
3910
+ const parseCallArgs = (args) => {
3911
+ const absArgs = [];
3912
+ let hasInfo = false;
3913
+ for (const a of args ?? []) {
3914
+ if (a.type === "NumericLiteral" && typeof a.value === "number") {
3915
+ absArgs.push(numLit(a.value));
3916
+ hasInfo = true;
3917
+ } else if (a.type === "UnaryExpression" && a.operator === "-" && a.argument?.type === "NumericLiteral") {
3918
+ const num2 = a.argument;
3919
+ absArgs.push(numLit(-num2.value));
3920
+ hasInfo = true;
3921
+ } else if (a.type === "ObjectExpression") {
3922
+ const abs2 = evalArgAbs(a, (n) => varAbs.get(n));
3923
+ absArgs.push(abs2 ?? absUnknown());
3924
+ if (abs2 && abs2.shape.k === "obj") hasInfo = true;
3925
+ } else if (a.type === "ArrayExpression") {
3926
+ const abs2 = evalArgAbs(a, (n) => varAbs.get(n));
3927
+ absArgs.push(abs2 ?? absUnknown());
3928
+ if (abs2 && (abs2.shape.k === "arr" || abs2.shape.k === "tuple")) hasInfo = true;
3929
+ } else if (a.type === "StringLiteral" && typeof a.value === "string") {
3930
+ absArgs.push({
3931
+ shape: { k: "prim", type: "string" },
3932
+ term: { op: "lit", value: a.value },
3933
+ conf: "exact"
3934
+ });
3935
+ hasInfo = true;
3936
+ } else if (a.type === "Identifier" && typeof a.name === "string") {
3937
+ const abs2 = varAbs.get(a.name);
3938
+ absArgs.push(abs2 ?? absUnknown());
3939
+ if (abs2 && abs2.shape.k !== "unknown") hasInfo = true;
3940
+ } else {
3941
+ absArgs.push(absUnknown());
3942
+ }
3943
+ }
3944
+ return { absArgs, hasInfo };
3945
+ };
3946
+ const checkOneCall = (fnName, args, loc) => {
3947
+ if (!knownFns.includes(fnName)) return;
3948
+ checkArgStructures(fnName, source, args, loc);
3949
+ const { absArgs, hasInfo } = parseCallArgs(args);
3950
+ if (!hasInfo || absArgs.length === 0) return;
3951
+ const g = generalizeFromAst(fnName, source, {
3952
+ file,
3953
+ refine: {
3954
+ loadModule: opts?.loadModule,
3955
+ fromFile: opts?.fromFile ?? ""
3956
+ }
3957
+ });
3958
+ const paramNames = g?.params ?? [];
3959
+ const optsR = {
3960
+ loadModule: opts?.loadModule,
3961
+ fromFile: opts?.fromFile ?? ""
3962
+ };
3963
+ const ownFull = refineToIndexedFull(source, fnName, paramNames, optsR);
3964
+ checkShapeReqs(fnName, ownFull, paramNames, absArgs, (i) => i, loc);
3965
+ checkReqs(
3966
+ fnName,
3967
+ ownFull.map(([i, e]) => [i, e.pred]),
3968
+ paramNames,
3969
+ absArgs,
3970
+ (i) => i,
3971
+ loc
3972
+ );
3973
+ const fwd = forwards.get(fnName);
3974
+ if (fwd) {
3975
+ const tg = generalizeFromAst(fwd.target, source, file ? { file } : {});
3976
+ const tParams = tg?.params ?? [];
3977
+ const tFull = refineToIndexedFull(source, fwd.target, tParams, optsR);
3978
+ if (tFull.length > 0) {
3979
+ const wrapperArgOfTarget = /* @__PURE__ */ new Map();
3980
+ fwd.map.forEach((wrapperIdx, targetIdx) => {
3981
+ wrapperArgOfTarget.set(targetIdx, wrapperIdx);
3982
+ });
3983
+ const mapArg = (targetIdx) => wrapperArgOfTarget.get(targetIdx);
3984
+ checkShapeReqs(`${fnName}\u2192${fwd.target}`, tFull, tParams, absArgs, mapArg, loc);
3985
+ checkReqs(
3986
+ `${fnName}\u2192${fwd.target}`,
3987
+ tFull.map(([i, e]) => [i, e.pred]),
3988
+ tParams,
3989
+ absArgs,
3990
+ mapArg,
3991
+ loc
3992
+ );
3993
+ }
3994
+ }
3995
+ };
3996
+ const checkExternalCall = (ext, args, displayName, loc) => {
3997
+ checkArgStructures(ext.fnName, ext.source, args, loc, displayName);
3998
+ const { absArgs, hasInfo } = parseCallArgs(args);
3999
+ if (!hasInfo || absArgs.length === 0) return;
4000
+ let full = [];
4001
+ let paramNames = [];
4002
+ try {
4003
+ const g = generalizeFromAst(ext.fnName, ext.source);
4004
+ paramNames = g?.params ?? [];
4005
+ full = refineToIndexedFull(ext.source, ext.fnName, paramNames, {
4006
+ loadModule: opts?.loadModule,
4007
+ fromFile: opts?.fromFile ?? ""
4008
+ });
4009
+ } catch {
4010
+ return;
4011
+ }
4012
+ checkShapeReqs(displayName, full, paramNames, absArgs, (i) => i, loc);
4013
+ checkReqs(
4014
+ displayName,
4015
+ full.map(([i, e]) => [i, e.pred]),
4016
+ paramNames,
4017
+ absArgs,
4018
+ (i) => i,
4019
+ loc
4020
+ );
4021
+ };
4022
+ const checkHofFnRelArgs = (g, args, loc, displayName, evalArg) => {
4023
+ const fnRels = g.fnRels;
4024
+ if (!fnRels) return;
4025
+ for (let i = 0; i < g.params.length; i++) {
4026
+ const pname = g.params[i];
4027
+ const rel = fnRels.get(pname);
4028
+ if (!rel) continue;
4029
+ const expected = rel.abs;
4030
+ if (expected.shape.k !== "fn") continue;
4031
+ const argNode = args[i];
4032
+ if (!argNode) continue;
4033
+ const absArg = evalArg(argNode);
4034
+ if (!absArg) continue;
4035
+ if (absArg.shape.k === "any" || absArg.shape.k === "unknown") continue;
4036
+ if (getFnImpl(absArg)) continue;
4037
+ if (absArg.shape.k === "sum") {
4038
+ const okAny = absArg.shape.members.some(
4039
+ (m) => hofFnArgOk(m, expected)
4040
+ );
4041
+ if (okAny) continue;
4042
+ }
4043
+ if (!hofFnArgOk(absArg, expected)) {
4044
+ const isPromote = rel.source === "promote";
4045
+ out.push({
4046
+ severity: isPromote ? "warning" : "error",
4047
+ code: "nudo:arg-structure",
4048
+ message: `${displayName}[${pname}]: \u5B9E\u53C2\u4E0D\u662F\u53EF\u8C03\u7528\u7684 fn`,
4049
+ actual: formatAbs(absArg),
4050
+ expected: formatShape(expected),
4051
+ suggestion: `\u671F\u671B ${formatShape(expected)}`,
4052
+ fn: displayName,
4053
+ line: loc?.start.line,
4054
+ column: loc?.start.column
4055
+ });
4056
+ }
4057
+ }
4058
+ };
4059
+ const checkArgStructures = (fnName, fnSource, args, loc, displayName) => {
4060
+ let structReqs;
4061
+ let paramNames;
4062
+ let gFn;
4063
+ try {
4064
+ const sameFile = fnSource === source;
4065
+ structReqs = collectParamStructReqs(fnSource, fnName, sameFile ? file : void 0);
4066
+ gFn = generalizeFromAst(
4067
+ fnName,
4068
+ fnSource,
4069
+ sameFile && file ? { file } : {}
4070
+ );
4071
+ paramNames = gFn?.params ?? [];
4072
+ } catch {
4073
+ return;
4074
+ }
4075
+ if (gFn?.fnRels && gFn.fnRels.size > 0) {
4076
+ checkHofFnRelArgs(
4077
+ gFn,
4078
+ args,
4079
+ loc,
4080
+ displayName ?? fnName,
4081
+ (n) => evalArgAbs(n, (x) => varAbs.get(x))
4082
+ );
4083
+ }
4084
+ if (structReqs.size === 0) return;
4085
+ let refinedParams;
4086
+ try {
4087
+ const sameFile = fnSource === source;
4088
+ const reqs = refineToIndexedFull(fnSource, fnName, paramNames, {
4089
+ loadModule: opts?.loadModule,
4090
+ fromFile: opts?.fromFile ?? ""
4091
+ });
4092
+ if (reqs.length > 0) {
4093
+ refinedParams = new Set(reqs.map(([, e]) => e.param));
4094
+ }
4095
+ } catch {
4096
+ }
4097
+ for (let i = 0; i < args.length; i++) {
4098
+ const pname = paramNames[i];
4099
+ if (!pname) continue;
4100
+ if (refinedParams?.has(pname)) continue;
4101
+ const keys = structReqs.get(pname);
4102
+ if (!keys || keys.size === 0) continue;
4103
+ const argNode = args[i];
4104
+ if (!argNode) continue;
4105
+ const absArg = evalArgAbs(argNode, (n) => varAbs.get(n));
4106
+ if (!absArg || absArg.shape.k === "unknown") continue;
4107
+ const isLeny = absArg.shape.k === "arr" || absArg.shape.k === "tuple" || absArg.shape.k === "prim" && absArg.shape.type === "string";
4108
+ const needKeys = isLeny ? [...keys].filter((k) => k !== "length") : [...keys];
4109
+ if (needKeys.length === 0) continue;
4110
+ const slots = {};
4111
+ for (const k of needKeys) slots[k] = { value: absUnknown() };
4112
+ const target = abs({ k: "obj", slots }, void 0, void 0, "exact");
4113
+ const leq = leqAbs(absArg, target);
4114
+ if (!leq.ok) {
4115
+ const name = displayName ?? fnName;
4116
+ out.push({
4117
+ severity: "error",
4118
+ code: "nudo:arg-structure",
4119
+ message: `${name}[${pname}]: \u5B9E\u53C2\u7ED3\u6784 \u22AD \u5F62\u53C2`,
4120
+ actual: formatAbs(absArg),
4121
+ expected: formatAbs(target),
4122
+ suggestion: leq.reason ?? `\u8865\u5168 ${pname} \u4E0A\u88AB\u8BBF\u95EE\u7684\u5B57\u6BB5`,
4123
+ fn: name,
4124
+ line: loc?.start.line,
4125
+ column: loc?.start.column
4126
+ });
4127
+ }
4128
+ }
4129
+ };
4130
+ const visit = (n) => {
4131
+ if (!n || typeof n !== "object") return;
4132
+ const obj2 = n;
4133
+ if (obj2.type === "CallExpression") {
4134
+ const callee = obj2.callee;
4135
+ const args = obj2.arguments ?? [];
4136
+ const resolved = resolveCalleeFn(callee, resolve, knownSet);
4137
+ if (typeof resolved === "string") {
4138
+ checkOneCall(resolved, args, obj2.loc);
4139
+ } else if (resolved?.external) {
4140
+ const name = resolved.external.fnName || "require()";
4141
+ checkExternalCall(resolved.external, args, name, obj2.loc);
4142
+ }
4143
+ }
4144
+ for (const key of Object.keys(obj2)) {
4145
+ if (key === "loc" || key === "start" || key === "end") continue;
4146
+ const val = obj2[key];
4147
+ if (Array.isArray(val)) val.forEach(visit);
4148
+ else if (val && typeof val === "object") visit(val);
4149
+ }
4150
+ };
4151
+ visit(file);
4152
+ return out;
4153
+ }
4154
+
4155
+ // src/algebra/check-report.ts
4156
+ function serializeCheckJson(r) {
4157
+ return {
4158
+ version: 1,
4159
+ file: r.file,
4160
+ ok: r.ok,
4161
+ summary: { ...r.summary },
4162
+ signatures: r.signatures.map((s) => ({
4163
+ name: s.name,
4164
+ params: [...s.params],
4165
+ display: s.display,
4166
+ detail: s.detail,
4167
+ conf: s.conf,
4168
+ abs: formatAbs(s.abs)
4169
+ })),
4170
+ issues: r.issues.map((i) => ({
4171
+ severity: i.severity,
4172
+ code: i.code,
4173
+ message: i.message,
4174
+ ...i.fn !== void 0 ? { fn: i.fn } : {},
4175
+ ...i.line !== void 0 ? { line: i.line } : {},
4176
+ ...i.column !== void 0 ? { column: i.column } : {},
4177
+ ...i.actual !== void 0 ? { actual: i.actual } : {},
4178
+ ...i.expected !== void 0 ? { expected: i.expected } : {},
4179
+ ...i.suggestion !== void 0 ? { suggestion: i.suggestion } : {}
4180
+ }))
4181
+ };
4182
+ }
4183
+ function formatCheckReport(r, opts = {}) {
4184
+ const lines = [];
4185
+ lines.push(`nudo check ${r.file}`);
4186
+ lines.push(r.ok ? "OK" : "FAILED");
4187
+ lines.push(
4188
+ ` ${r.summary.errors} error \xB7 ${r.summary.warnings} warning \xB7 ${r.summary.infos} info \xB7 ${r.summary.functions} fn`
4189
+ );
4190
+ if (r.signatures.length > 0) {
4191
+ lines.push("");
4192
+ lines.push("signatures");
4193
+ for (const s of r.signatures) {
4194
+ lines.push(` ${s.name}(${s.params.join(", ")}) ${s.display}`);
4195
+ if (opts.verbose) {
4196
+ for (const ln of s.detail.split("\n").slice(1)) {
4197
+ lines.push(` ${ln}`);
4198
+ }
4199
+ }
4200
+ }
4201
+ }
4202
+ if (r.issues.length === 0) {
4203
+ lines.push("");
4204
+ lines.push("(no issues)");
4205
+ } else {
4206
+ lines.push("");
4207
+ lines.push("issues");
4208
+ for (const i of r.issues) {
4209
+ const loc = i.line != null ? `L${i.line}` : "";
4210
+ const head = [i.severity.toUpperCase(), loc, i.fn].filter(Boolean).join(" ");
4211
+ lines.push(` [${head}] ${i.message} (${i.code})`);
4212
+ if (i.actual) lines.push(` actual: ${i.actual}`);
4213
+ if (i.expected) lines.push(` expected: ${i.expected}`);
4214
+ if (i.suggestion) lines.push(` \u2192 ${i.suggestion}`);
4215
+ }
4216
+ }
4217
+ return lines.join("\n");
4218
+ }
4219
+
4220
+ // src/algebra/inlay.ts
4221
+ function listFunctions(source) {
4222
+ const file = parseSource(source);
4223
+ const out = [];
4224
+ const visitDecl = (decl) => {
4225
+ if (decl.type === "FunctionDeclaration" && decl.id) {
4226
+ const fd = decl;
4227
+ out.push({ name: fd.id.name, node: fd });
4228
+ }
4229
+ if (decl.type === "VariableDeclaration") {
4230
+ for (const d of decl.declarations ?? []) {
4231
+ if (d.id?.type === "Identifier" && d.init && (d.init.type === "ArrowFunctionExpression" || d.init.type === "FunctionExpression")) {
4232
+ out.push({ name: d.id.name, node: d.init });
4233
+ }
4234
+ }
4235
+ }
4236
+ };
4237
+ for (const stmt of file.program.body) {
4238
+ if (stmt.type === "ExportNamedDeclaration" && stmt.declaration) {
4239
+ visitDecl(stmt.declaration);
4240
+ } else if (stmt.type === "ExportDefaultDeclaration" && stmt.declaration) {
4241
+ visitDecl(stmt.declaration);
4242
+ } else {
4243
+ visitDecl(stmt);
4244
+ }
4245
+ }
4246
+ return out;
4247
+ }
4248
+ function paramPreds(source, fnName, paramNames) {
4249
+ const byIndex = /* @__PURE__ */ new Map();
4250
+ const file = parseSource(source);
4251
+ const paramIndex = new Map(paramNames.map((p, i) => [p, i]));
4252
+ const pushCmp = (test, consequent) => {
4253
+ if (test?.type !== "BinaryExpression") return;
4254
+ const left = test.left;
4255
+ const right = test.right;
4256
+ const op = test.operator;
4257
+ if (left?.type !== "Identifier" || !left.name || !paramIndex.has(left.name) || right?.type !== "NumericLiteral" || typeof right.value !== "number") {
4258
+ return;
4259
+ }
4260
+ const isReturnParam = consequent?.type === "ReturnStatement" && consequent.argument?.type === "Identifier" && consequent.argument.name === left.name;
4261
+ if (!isReturnParam) return;
4262
+ const idx = paramIndex.get(left.name);
4263
+ const t = { op: "var", id: left.name };
4264
+ const b = { op: "lit", value: right.value };
4265
+ let pred;
4266
+ if (op === ">") pred = { op: "gt", a: t, b };
4267
+ else if (op === ">=") pred = { op: "ge", a: t, b };
4268
+ else if (op === "<") pred = { op: "lt", a: t, b };
4269
+ else if (op === "<=") pred = { op: "le", a: t, b };
4270
+ if (!pred) return;
4271
+ const list = byIndex.get(idx) ?? [];
4272
+ list.push(pred);
4273
+ byIndex.set(idx, list);
4274
+ };
4275
+ const visit = (n) => {
4276
+ if (!n || typeof n !== "object") return;
4277
+ const obj2 = n;
4278
+ if (obj2.type === "IfStatement") {
4279
+ const test = obj2.test;
4280
+ const consequent = obj2.consequent;
4281
+ pushCmp(test, consequent);
4282
+ if (test?.type === "LogicalExpression" && test.operator === "&&") {
4283
+ pushCmp(test.left, consequent);
4284
+ pushCmp(test.right, consequent);
4285
+ }
4286
+ }
4287
+ for (const key of Object.keys(obj2)) {
4288
+ if (key === "loc" || key === "start" || key === "end") continue;
4289
+ const val = obj2[key];
4290
+ if (Array.isArray(val)) val.forEach(visit);
4291
+ else if (val && typeof val === "object") visit(val);
4292
+ }
4293
+ };
4294
+ visit(file);
4295
+ const byName = /* @__PURE__ */ new Map();
4296
+ for (const [idx, preds] of byIndex) {
4297
+ const name = paramNames[idx];
4298
+ if (name) byName.set(name, preds);
4299
+ }
4300
+ return byName;
4301
+ }
4302
+ function collectAbsInlays(source, refineOpts) {
4303
+ const inlays = [];
4304
+ for (const { name, node } of listFunctions(source)) {
4305
+ let g;
4306
+ try {
4307
+ g = generalizeFromAst(name, source, refineOpts ? { refine: refineOpts } : {});
4308
+ } catch {
4309
+ continue;
4310
+ }
4311
+ if (!g) continue;
4312
+ const params = g.params;
4313
+ const predsByName = /* @__PURE__ */ new Map();
4314
+ if (g.entryReqs) {
4315
+ for (const r of g.entryReqs) {
4316
+ predsByName.set(r.param, [r.pred]);
4317
+ }
4318
+ }
4319
+ for (const [k, v2] of paramPreds(source, name, params)) {
4320
+ if (!predsByName.has(k)) predsByName.set(k, v2);
4321
+ }
4322
+ const fnNode = node;
4323
+ const paramList = fnNode.params ?? [];
4324
+ for (let i = 0; i < paramList.length; i++) {
4325
+ const p = paramList[i];
4326
+ const pname = params[i] ?? p?.name;
4327
+ if (!p?.loc || !pname) continue;
4328
+ const preds = predsByName.get(pname);
4329
+ if (preds && preds.length > 0) {
4330
+ const text = preds.map(predToString).join(" \u2227 ");
4331
+ inlays.push({
4332
+ line: p.loc.end.line,
4333
+ character: p.loc.end.column,
4334
+ label: ` where ${text}`,
4335
+ kind: "parameter"
4336
+ });
4337
+ }
4338
+ }
4339
+ const bodyLoc = fnNode.body?.loc;
4340
+ if (bodyLoc?.start) {
4341
+ const retShape = formatShape(g.symbolic);
4342
+ let label = `: ${retShape}`;
4343
+ if (g.symbolic.term && g.symbolic.term.op !== "lit") {
4344
+ label += ` = ${termToString(g.symbolic.term)}`;
4345
+ }
4346
+ if (g.symbolic.pred && g.symbolic.pred.op !== "true") {
4347
+ label += ` where ${predToString(g.symbolic.pred)}`;
4348
+ }
4349
+ inlays.push({
4350
+ line: bodyLoc.start.line,
4351
+ character: Math.max(0, bodyLoc.start.column),
4352
+ label: `${label} `,
4353
+ kind: "type"
4354
+ });
4355
+ }
4356
+ }
4357
+ return inlays;
4358
+ }
4359
+
4360
+ // src/algebra/denote.ts
4361
+ function denoteGuard(a, v2) {
4362
+ const lv = litValue(a);
4363
+ if (lv !== void 0 && (!a.pred || a.pred.op === "true")) {
4364
+ return `${v2} === ${JSON.stringify(lv)}`;
4365
+ }
4366
+ const shape2 = denoteShape(a.shape, v2);
4367
+ const pred = denotePred(a, v2);
4368
+ if (shape2 === "true") return pred;
4369
+ if (pred === "true") return shape2;
4370
+ return `(${shape2}) && (${pred})`;
4371
+ }
4372
+ function denoteShape(s, v2) {
4373
+ switch (s.k) {
4374
+ case "never":
4375
+ return "false";
4376
+ case "unknown":
4377
+ case "any":
4378
+ return "true";
4379
+ case "prim":
4380
+ switch (s.type) {
4381
+ case "number":
4382
+ return `typeof ${v2} === "number"`;
4383
+ case "string":
4384
+ return `typeof ${v2} === "string"`;
4385
+ case "boolean":
4386
+ return `typeof ${v2} === "boolean"`;
4387
+ case "bigint":
4388
+ return `typeof ${v2} === "bigint"`;
4389
+ case "symbol":
4390
+ return `typeof ${v2} === "symbol"`;
4391
+ default:
4392
+ return "true";
4393
+ }
4394
+ case "obj": {
4395
+ const checks = [`typeof ${v2} === "object"`, `${v2} !== null`];
4396
+ for (const [key, slot] of Object.entries(s.slots)) {
4397
+ const access = `${v2}.${key}`;
4398
+ const inner = denoteGuard(slot.value, access);
4399
+ if (slot.optional) {
4400
+ if (inner !== "true") checks.push(`(${access} === undefined || ${inner})`);
4401
+ } else {
4402
+ if (inner !== "true") checks.push(inner);
4403
+ }
4404
+ }
4405
+ return checks.join(" && ");
4406
+ }
4407
+ case "arr":
4408
+ return `Array.isArray(${v2}) && ${v2}.every((item) => ${denoteGuard(s.element, "item")})`;
4409
+ case "tuple": {
4410
+ const checks = [`Array.isArray(${v2})`];
4411
+ const minLen = s.elements.length;
4412
+ checks.push(s.rest ? `${v2}.length >= ${minLen}` : `${v2}.length === ${minLen}`);
4413
+ s.elements.forEach((el, i) => {
4414
+ const inner = denoteGuard(el, `${v2}[${i}]`);
4415
+ if (inner !== "true") checks.push(inner);
4416
+ });
4417
+ if (s.rest) {
4418
+ const rest = denoteGuard(s.rest, "item");
4419
+ if (rest !== "true") {
4420
+ checks.push(`${v2}.slice(${minLen}).every((item) => ${rest})`);
4421
+ }
4422
+ }
4423
+ return checks.join(" && ");
4424
+ }
4425
+ case "fn":
4426
+ return `typeof ${v2} === "function"`;
4427
+ case "eff":
4428
+ if (s.eff === "promise") return `${v2} instanceof Promise`;
4429
+ return "true";
4430
+ case "brand":
4431
+ return denoteShape(s.shape.shape, v2);
4432
+ case "sum": {
4433
+ if (s.members.length === 0) return "false";
4434
+ const parts = s.members.map((m) => denoteGuard(m, v2));
4435
+ return `(${parts.join(" || ")})`;
4436
+ }
4437
+ }
4438
+ }
4439
+ function denotePred(a, v2) {
4440
+ const p = a.pred;
4441
+ if (!p || p.op === "true") {
4442
+ const lv = litValue(a);
4443
+ if (lv !== void 0) return `${v2} === ${JSON.stringify(lv)}`;
4444
+ return "true";
4445
+ }
4446
+ return predAsJs(p, v2, a);
4447
+ }
4448
+ function predAsJs(p, v2, a) {
4449
+ switch (p.op) {
4450
+ case "true":
4451
+ return "true";
4452
+ case "false":
4453
+ return "false";
4454
+ case "and":
4455
+ return p.args.map((x) => predAsJs(x, v2, a)).join(" && ");
4456
+ case "or":
4457
+ return `(${p.args.map((x) => predAsJs(x, v2, a)).join(" || ")})`;
4458
+ case "not": {
4459
+ const inner = predAsJs(p.arg, v2, a);
4460
+ return inner === "true" ? "false" : `!(${inner})`;
4461
+ }
4462
+ case "gt":
4463
+ case "ge":
4464
+ case "lt":
4465
+ case "le":
4466
+ case "eq":
4467
+ case "ne": {
4468
+ const op = { gt: ">", ge: ">=", lt: "<", le: "<=", eq: "===", ne: "!==" }[p.op];
4469
+ const leftIsValue = termIsValue(p.a, a);
4470
+ const rightLit = litOfTerm(p.b);
4471
+ if (leftIsValue && rightLit !== void 0) {
4472
+ return `${v2} ${op} ${JSON.stringify(rightLit)}`;
4473
+ }
4474
+ const leftLit = litOfTerm(p.a);
4475
+ const rightIsValue = termIsValue(p.b, a);
4476
+ if (rightIsValue && leftLit !== void 0) {
4477
+ return `${JSON.stringify(leftLit)} ${op} ${v2}`;
4478
+ }
4479
+ if (leftLit !== void 0 && rightLit !== void 0) {
4480
+ return `${JSON.stringify(leftLit)} ${op} ${JSON.stringify(rightLit)}`;
4481
+ }
4482
+ return "true";
4483
+ }
4484
+ default:
4485
+ return "true";
4486
+ }
4487
+ }
4488
+ function litOfTerm(t) {
4489
+ return t.op === "lit" ? t.value : void 0;
4490
+ }
4491
+ function termIsValue(t, a) {
4492
+ if (t.op === "var") return true;
4493
+ if (t.op === "lit") {
4494
+ const lv = litValue(a);
4495
+ return lv !== void 0 && Object.is(lv, t.value);
4496
+ }
4497
+ return false;
4498
+ }
4499
+
4500
+ // src/algebra/bridge.ts
4501
+ var confByTv = /* @__PURE__ */ new WeakMap();
4502
+ function setTvConfidence(tv, conf) {
4503
+ if (tv && typeof tv === "object") confByTv.set(tv, conf);
4504
+ }
4505
+ function getTvConfidence(tv) {
4506
+ if (tv && typeof tv === "object") return confByTv.get(tv);
4507
+ return void 0;
4508
+ }
4509
+ function absToTypeValue(a) {
4510
+ let conf = a.conf;
4511
+ let result;
4512
+ switch (a.shape.k) {
4513
+ case "never":
4514
+ result = T.never;
4515
+ break;
4516
+ case "unknown":
4517
+ result = T.unknown;
4518
+ break;
4519
+ case "any":
4520
+ result = T.unknown;
4521
+ break;
4522
+ case "prim": {
4523
+ const lv = litValue(a);
4524
+ if (lv !== void 0) {
4525
+ result = T.literal(lv);
4526
+ break;
4527
+ }
4528
+ if (isTemplateLike(a) && a.shape.k === "prim" && a.shape.type === "string") {
4529
+ const parts = templatePartsOf(a).map(absToTypeValue);
4530
+ result = createTemplate(parts);
4531
+ break;
4532
+ }
4533
+ const prim = primToT(a.shape.type);
4534
+ if (a.pred && a.pred.op !== "true") {
4535
+ const refined = tryEncodeRefined(prim, a);
4536
+ if (refined) {
4537
+ result = refined;
4538
+ } else {
4539
+ result = prim;
4540
+ conf = confJoin(conf, "widened");
4541
+ }
4542
+ } else {
4543
+ result = prim;
4544
+ if (a.term && a.term.op !== "lit") conf = confJoin(conf, "widened");
4545
+ }
4546
+ break;
4547
+ }
4548
+ case "obj": {
4549
+ const props = {};
4550
+ for (const [k, slot] of Object.entries(a.shape.slots)) {
4551
+ let v2 = absToTypeValue(slot.value);
4552
+ if (slot.optional) {
4553
+ v2 = T.union(v2, T.undefined);
4554
+ }
4555
+ props[k] = v2;
4556
+ }
4557
+ result = T.object(props);
4558
+ if (a.shape.open) conf = confJoin(conf, "widened");
4559
+ break;
4560
+ }
4561
+ case "arr":
4562
+ result = T.array(absToTypeValue(a.shape.element));
4563
+ break;
4564
+ case "tuple":
4565
+ result = T.tuple(a.shape.elements.map(absToTypeValue));
4566
+ break;
4567
+ case "fn": {
4568
+ const body = { type: "BlockStatement", body: [], directives: [] };
4569
+ result = T.fn(a.shape.params, body, null);
4570
+ break;
4571
+ }
4572
+ case "brand":
4573
+ result = T.instanceOf(a.shape.name, brandProps(a.shape.shape));
4574
+ break;
4575
+ case "eff":
4576
+ result = T.promise(absToTypeValue(a.shape.inner));
4577
+ break;
4578
+ case "sum":
4579
+ result = T.union(...a.shape.members.map(absToTypeValue));
4580
+ break;
4581
+ default:
4582
+ result = T.unknown;
4583
+ conf = confJoin(conf, "partial");
4584
+ }
4585
+ setTvConfidence(result, conf);
4586
+ return result;
4587
+ }
4588
+ function primToT(type) {
4589
+ switch (type) {
4590
+ case "number":
4591
+ return T.number;
4592
+ case "string":
4593
+ return T.string;
4594
+ case "boolean":
4595
+ return T.boolean;
4596
+ case "bigint":
4597
+ return T.bigint;
4598
+ case "symbol":
4599
+ return T.symbol;
4600
+ default:
4601
+ return T.unknown;
4602
+ }
4603
+ }
4604
+ function brandProps(shape2) {
4605
+ if (shape2.shape.k === "obj") {
4606
+ const out = {};
4607
+ for (const [k, slot] of Object.entries(shape2.shape.slots)) {
4608
+ out[k] = absToTypeValue(slot.value);
4609
+ }
4610
+ return out;
4611
+ }
4612
+ return {};
4613
+ }
4614
+ function tryEncodeRefined(base, a) {
4615
+ if (base.kind !== "primitive" || base.type !== "number") return void 0;
4616
+ const p = a.pred;
4617
+ if (!p) return void 0;
4618
+ if ((p.op === "gt" || p.op === "ge" || p.op === "lt" || p.op === "le") && p.b.op === "lit" && typeof p.b.value === "number") {
4619
+ const n = p.b.value;
4620
+ const op = p.op;
4621
+ const check = (value) => {
4622
+ if (typeof value !== "number") return false;
4623
+ switch (op) {
4624
+ case "gt":
4625
+ return value > n;
4626
+ case "ge":
4627
+ return value >= n;
4628
+ case "lt":
4629
+ return value < n;
4630
+ case "le":
4631
+ return value <= n;
4632
+ }
4633
+ };
4634
+ const opSym = op === "gt" ? ">" : op === "ge" ? ">=" : op === "lt" ? "<" : "<=";
4635
+ return T.refine(base, {
4636
+ name: `number (${opSym} ${n})`,
4637
+ meta: { op, n, pred: predToString(p) },
4638
+ check
4639
+ });
4640
+ }
4641
+ return void 0;
4642
+ }
4643
+ function typeValueToAbs(tv) {
4644
+ if (!tv) return abs({ k: "unknown" }, void 0, void 0, "partial");
4645
+ const confOr = (fallback) => getTvConfidence(tv) ?? fallback;
4646
+ switch (tv.kind) {
4647
+ case "never":
4648
+ return abs({ k: "never" }, void 0, void 0, confOr("exact"));
4649
+ case "unknown":
4650
+ return abs(
4651
+ { k: "unknown" },
4652
+ void 0,
4653
+ void 0,
4654
+ confOr("partial")
4655
+ );
4656
+ case "literal":
4657
+ if (typeof tv.value === "bigint") {
4658
+ return abs(
4659
+ { k: "prim", type: "bigint" },
4660
+ void 0,
4661
+ void 0,
4662
+ confOr("exact")
4663
+ );
4664
+ }
4665
+ return abs(
4666
+ shapeOfLit(tv.value),
4667
+ lit(tv.value),
4668
+ pTrue,
4669
+ confOr("exact")
4670
+ );
4671
+ case "primitive":
4672
+ return abs({ k: "prim", type: tv.type }, void 0, void 0, confOr("exact"));
4673
+ case "refined": {
4674
+ const tplParts = getTemplateParts(tv);
4675
+ if (tplParts) {
4676
+ return createTemplateAbs(tplParts.map(typeValueToAbs));
4677
+ }
4678
+ const base = typeValueToAbs(tv.base);
4679
+ const decoded = tryDecodeRefinedPred(tv, base.term);
4680
+ return abs(
4681
+ base.shape,
4682
+ base.term ?? (decoded ? v("_r") : void 0),
4683
+ decoded ?? base.pred,
4684
+ confOr(confJoin(base.conf, "path"))
4685
+ );
4686
+ }
4687
+ case "object": {
4688
+ const slots = {};
4689
+ for (const [k, v2] of Object.entries(tv.properties)) {
4690
+ slots[k] = { value: typeValueToAbs(v2) };
4691
+ }
4692
+ return abs({ k: "obj", slots }, void 0, void 0, confOr("exact"));
4693
+ }
4694
+ case "array":
4695
+ return abs(
4696
+ { k: "arr", element: typeValueToAbs(tv.element) },
4697
+ void 0,
4698
+ void 0,
4699
+ confOr("exact")
4700
+ );
4701
+ case "tuple":
4702
+ return abs(
4703
+ { k: "tuple", elements: tv.elements.map(typeValueToAbs) },
4704
+ void 0,
4705
+ void 0,
4706
+ confOr("exact")
4707
+ );
4708
+ case "function": {
4709
+ const params = tv.params ?? [];
4710
+ return abs({ k: "fn", params }, void 0, void 0, confOr("exact"));
4711
+ }
4712
+ case "promise":
4713
+ return abs(
4714
+ { k: "eff", eff: "promise", inner: typeValueToAbs(tv.value) },
4715
+ void 0,
4716
+ void 0,
4717
+ confOr("exact")
4718
+ );
4719
+ case "instance": {
4720
+ const slots = {};
4721
+ for (const [k, v2] of Object.entries(tv.properties ?? {})) {
4722
+ slots[k] = { value: typeValueToAbs(v2) };
4723
+ }
4724
+ const inner = abs({ k: "obj", slots }, void 0, void 0, confOr("exact"));
4725
+ return abs(
4726
+ { k: "brand", name: tv.className, shape: inner },
4727
+ void 0,
4728
+ void 0,
4729
+ confOr("exact")
4730
+ );
4731
+ }
4732
+ case "union":
4733
+ return abs(
4734
+ { k: "sum", members: tv.members.map(typeValueToAbs) },
4735
+ void 0,
4736
+ void 0,
4737
+ confOr("path")
4738
+ );
4739
+ default:
4740
+ return abs({ k: "unknown" }, void 0, void 0, confOr("partial"));
4741
+ }
4742
+ }
4743
+ function tryDecodeRefinedPred(tv, term) {
4744
+ if (tv.kind !== "refined") return void 0;
4745
+ const meta = tv.refinement.meta;
4746
+ const op = meta?.op;
4747
+ const n = meta?.n;
4748
+ if (typeof n !== "number") return void 0;
4749
+ if (op !== "gt" && op !== "ge" && op !== "lt" && op !== "le") return void 0;
4750
+ const t = term ?? v("_r");
4751
+ const b = lit(n);
4752
+ switch (op) {
4753
+ case "gt":
4754
+ return gt(t, b);
4755
+ case "ge":
4756
+ return ge(t, b);
4757
+ case "lt":
4758
+ return lt(t, b);
4759
+ case "le":
4760
+ return le(t, b);
4761
+ }
4762
+ }
4763
+ function shapeOfLit(v2) {
4764
+ if (typeof v2 === "number") return { k: "prim", type: "number" };
4765
+ if (typeof v2 === "string") return { k: "prim", type: "string" };
4766
+ if (typeof v2 === "boolean") return { k: "prim", type: "boolean" };
4767
+ if (typeof v2 === "bigint") return { k: "prim", type: "bigint" };
4768
+ return { k: "unknown" };
4769
+ }
4770
+ function bridgeIsLossy(a) {
4771
+ const reasons = [];
4772
+ if (a.term && a.term.op !== "lit") {
4773
+ reasons.push(`dropped term ${termToString(a.term)}`);
4774
+ }
4775
+ if (a.pred && a.pred.op !== "true") {
4776
+ const tv = absToTypeValue(a);
4777
+ if (tv.kind !== "refined") {
4778
+ reasons.push(`dropped pred ${predToString(a.pred)}`);
4779
+ }
4780
+ }
4781
+ return { lossy: reasons.length > 0, reasons };
4782
+ }
723
4783
  export {
4784
+ $add,
4785
+ $arr,
4786
+ $async,
4787
+ $asyncReturn,
4788
+ $await,
4789
+ $call,
4790
+ $callNamed,
4791
+ $catchVal,
4792
+ $class,
4793
+ $concat,
4794
+ $div,
4795
+ $elems,
4796
+ $eq,
4797
+ $fnVal,
4798
+ $for,
4799
+ $forIter,
4800
+ $forOf,
4801
+ $fork,
4802
+ $ge,
4803
+ $gen,
4804
+ $get,
4805
+ $gt,
4806
+ $idx,
4807
+ $idxSet,
4808
+ $invoke,
4809
+ $invokeSuper,
4810
+ $join,
4811
+ $le,
4812
+ $len,
4813
+ $lit,
4814
+ $lt,
4815
+ $mod,
4816
+ $mul,
4817
+ $ne,
4818
+ $neg,
4819
+ $new,
4820
+ $not,
4821
+ $obj,
4822
+ $optionalGet,
4823
+ $optionalInvoke,
4824
+ $orDefault,
4825
+ $set,
4826
+ $setKey,
4827
+ $spread,
4828
+ $staticInvoke,
4829
+ $sub,
4830
+ $super,
4831
+ $switch,
4832
+ $thisGet,
4833
+ $thisSet,
4834
+ $throw,
4835
+ $typeof,
4836
+ $while,
4837
+ $whileSeq,
4838
+ $yield,
4839
+ DEFAULT_MAX_LOOP_ITERS,
4840
+ MAX_CALL_DEPTH,
4841
+ MAX_TOTAL_CALLS,
4842
+ NudoThrow,
724
4843
  Ops,
4844
+ SELF,
725
4845
  T,
4846
+ abs,
4847
+ absFunction,
4848
+ absToString,
4849
+ absToTypeValue,
4850
+ add,
4851
+ alphaOf,
4852
+ analyzeFn,
4853
+ and,
4854
+ anyVar,
4855
+ app,
4856
+ applyAbsFn,
726
4857
  applyBinaryOp,
4858
+ applyCallbackAbs,
4859
+ array,
4860
+ asAbs,
4861
+ asAbsVal,
4862
+ attachFnImpl,
4863
+ awaitAbs,
4864
+ betaOf,
4865
+ bindImports,
4866
+ bool,
4867
+ boolLit,
4868
+ boolean,
4869
+ bridgeIsLossy,
4870
+ buildArgsFromAssume,
4871
+ callAbsMethod,
4872
+ callFunction,
4873
+ callTranspiledExport,
4874
+ callTranspiledExportFull,
4875
+ canSkipLiteralCallScan,
4876
+ checkArg,
4877
+ checkCall,
4878
+ checkSource,
4879
+ classFromMethods,
4880
+ clearBClasses,
4881
+ cmp,
4882
+ coerceAsyncReturn,
4883
+ collapseLiteralUnion,
4884
+ collapseToOptional,
4885
+ collectAbsExports,
4886
+ collectAbsInlays,
4887
+ collectAbsNodeTypes,
4888
+ concatString,
727
4889
  concatTemplates,
4890
+ confJoin,
4891
+ constraintToEntryAbs,
728
4892
  createEnvironment,
4893
+ createHofCollectCtx,
729
4894
  createRange,
730
4895
  createTemplate,
4896
+ createTemplateAbs,
4897
+ currentExecPhi,
4898
+ currentPhi,
731
4899
  deepCloneTypeValue,
4900
+ defaultLeakBudget,
4901
+ defineClass,
4902
+ definitelyNotNullishShape,
4903
+ denoteGuard,
4904
+ describePhi,
732
4905
  dispatchBinaryOp,
733
4906
  dispatchMethod,
734
4907
  dispatchProperty,
4908
+ div,
4909
+ emptyEnv,
4910
+ emptyPhi,
4911
+ eq,
4912
+ evalArrayStatic,
4913
+ evalBuiltinInstanceMethod,
4914
+ evalBuiltinNew,
4915
+ evalDateCtor,
4916
+ evalDateMethod,
4917
+ evalDateStatic,
4918
+ evalGlobalFn,
4919
+ evalJsonMethod,
4920
+ evalMathMethod,
4921
+ evalMethodBody,
4922
+ evalNamespaceCall,
4923
+ evalNode,
4924
+ evalNumberStatic,
4925
+ evalObjectMethod,
4926
+ evalProgramAbs,
4927
+ evalPromiseCtor,
4928
+ evalPromiseStatic,
4929
+ evalRegExpCtor,
4930
+ evalRegExpMethod,
4931
+ evalSource,
4932
+ evictCheckSourceMemoForPaths,
4933
+ evictGeneralizeMemoForPaths,
4934
+ exceedsBudget,
4935
+ execNudoModule,
4936
+ extractAllLoadSpecs,
4937
+ extractFn,
4938
+ extractNudoImports,
4939
+ extractRefineReturnFromSource,
4940
+ extractRefinesFromSource,
4941
+ falseConstraint,
4942
+ findAbsAtPosition,
4943
+ fnFingerprints,
4944
+ fnOf,
4945
+ formatAbs,
4946
+ formatAbsMultiline,
4947
+ formatCheckReport,
4948
+ formatDiagnostics,
4949
+ formatShape,
4950
+ formatShapeSlot,
4951
+ ge,
4952
+ geNum,
4953
+ generalizeAll,
4954
+ generalizeFromAst,
4955
+ generalizeSourceKeyPart,
4956
+ getAbsOrigin,
4957
+ getAbsProperty,
4958
+ getBCallCollector,
4959
+ getBClass,
4960
+ getCheckSourceMemoSize,
4961
+ getClass,
4962
+ getClassChain,
4963
+ getFnImpl,
4964
+ getFnNameAndBodies,
4965
+ getFnSig,
4966
+ getGeneralizeMemoSize,
735
4967
  getKnownPrefix,
736
4968
  getKnownSuffix,
4969
+ getParseSourceCacheSize,
737
4970
  getPrimitiveTypeOf,
738
4971
  getRangeMeta,
739
4972
  getRefinedBase,
740
4973
  getTemplateParts,
4974
+ getTerm,
4975
+ getTvConfidence,
4976
+ gt,
4977
+ gtNum,
4978
+ hashSource,
4979
+ implies,
4980
+ instanceOf,
4981
+ instantiateClass,
4982
+ instantiateConstraint,
4983
+ instantiateReturn,
4984
+ isDefinitelyFalse,
4985
+ isDefinitelyTrue,
4986
+ isExactLit,
4987
+ isFnSig,
4988
+ isNudoConstraint,
4989
+ isNudoThrow,
4990
+ isNullishLitAbs,
4991
+ isNumPrim,
4992
+ isObj,
741
4993
  isRange,
4994
+ isRelFn,
4995
+ isStrPrim,
742
4996
  isSubtypeOf,
743
4997
  isTemplate,
4998
+ isTemplateLike,
4999
+ joinAbs,
5000
+ joinFunctions,
5001
+ joinObjects,
5002
+ joinValues,
5003
+ le,
5004
+ leNum,
5005
+ leakIfNeeded,
5006
+ lenTerm,
5007
+ leqAbs,
5008
+ listFunctionNames,
5009
+ lit,
5010
+ litValue,
5011
+ loadModuleDepsFingerprint,
5012
+ lookupMethod,
5013
+ lookupMethodWithOwner,
5014
+ lookupSuperMethod,
5015
+ lt,
5016
+ ltNum,
5017
+ makeSum,
5018
+ mapElementFallback,
5019
+ maybeLeak,
744
5020
  mergeObjectProperties,
5021
+ mock,
5022
+ mockHelperToTypeValue,
5023
+ mod,
5024
+ mul,
745
5025
  narrowType,
5026
+ ne,
5027
+ negAbs,
5028
+ never,
5029
+ normPath,
5030
+ not,
5031
+ notAbs,
5032
+ noteMemberDispatchMiss,
5033
+ notePrimMemberMissing,
5034
+ noteUnknownMemberMissing,
5035
+ num,
5036
+ numLit,
5037
+ numVar,
5038
+ number,
5039
+ numericBounds,
5040
+ obj,
5041
+ objOf,
5042
+ or,
5043
+ pFalse,
5044
+ pTrue,
5045
+ parseSource,
5046
+ phiAnd,
5047
+ popPhi,
5048
+ predEquals,
5049
+ predToString,
5050
+ predVars,
5051
+ projectBrand,
5052
+ projectFlatMapResult,
5053
+ promoteParamShape,
5054
+ ptypeof,
5055
+ pushPhi,
5056
+ recordMemberDiag,
5057
+ refineToIndexedFull,
5058
+ registerBClass,
5059
+ relationFingerprint,
5060
+ relationFn,
5061
+ resetAbsCallBudget,
5062
+ resetCheckSourceMemo,
5063
+ resetFnFpCache,
5064
+ resetGeneralizeMemo,
5065
+ resetHashSourceCache,
5066
+ resetLeakCounter,
5067
+ resetNudoModuleExecCache,
5068
+ resetParseSourceCache,
5069
+ resetPhi,
5070
+ resolveDepPath,
5071
+ runTranspiled,
5072
+ serializeCheckJson,
5073
+ setAbsAssignCollector,
5074
+ setAbsCallCollector,
5075
+ setAbsNodeCollector,
5076
+ setAbsTruncationCollector,
5077
+ setApplyCallbackHost,
5078
+ setBCallCollector,
5079
+ setMemberDiagCollector,
5080
+ setTvConfidence,
5081
+ shape,
5082
+ shapeOfTerm,
5083
+ shapeOnlyFn,
5084
+ shapeToString,
5085
+ simplifyTerm,
746
5086
  simplifyUnion,
5087
+ snapshotAbs,
5088
+ spread,
5089
+ spy,
5090
+ stableAnalyzeKeySource,
5091
+ str,
5092
+ strLit,
5093
+ strictEqAbs,
5094
+ string,
5095
+ stripTypes,
5096
+ stub,
5097
+ sub,
5098
+ substAbs,
5099
+ substPred,
5100
+ substPredAbs,
747
5101
  subtractType,
5102
+ superNameOf,
5103
+ tagAbsOrigin,
5104
+ templatePartsOf,
5105
+ termDepth,
5106
+ termEquals,
5107
+ termNodes,
5108
+ termToString,
5109
+ transpile,
5110
+ transpileExpression,
5111
+ transpileFile,
5112
+ transpileSource,
5113
+ trueConstraint,
5114
+ tryPromoteDirectCall,
5115
+ tryPromoteForOfIteratee,
5116
+ tryPromoteHofCallback,
5117
+ tryPromoteReceiverAsArr,
748
5118
  typeValueEquals,
5119
+ typeValueToAbs,
749
5120
  typeValueToString,
750
- widenLiteral
5121
+ typeofAbs,
5122
+ undefAbs,
5123
+ unknown,
5124
+ v,
5125
+ widenLiteral,
5126
+ withExecPhi,
5127
+ withPhiConstraint,
5128
+ withVar,
5129
+ wrapPromise
751
5130
  };